diff options
author | Łukasz Stelmach <l.stelmach@samsung.com> | 2013-10-04 13:55:11 +0200 |
---|---|---|
committer | Łukasz Stelmach <l.stelmach@samsung.com> | 2013-10-04 13:55:11 +0200 |
commit | 4daab3758f62250691d3994850ddd3a7faf80d5e (patch) | |
tree | 895f25ab9018c6f343a261f0c1e5e3ae0bdd9362 /scheduler | |
parent | 4c8dd44ec57d63e728bda99034c043b8941419df (diff) | |
download | cups-4daab3758f62250691d3994850ddd3a7faf80d5e.tar.gz cups-4daab3758f62250691d3994850ddd3a7faf80d5e.tar.bz2 cups-4daab3758f62250691d3994850ddd3a7faf80d5e.zip |
Imported Upstream version 1.6.4upstream/1.6.4
Diffstat (limited to 'scheduler')
67 files changed, 7728 insertions, 11431 deletions
diff --git a/scheduler/Dependencies b/scheduler/Dependencies index 5be01ff..2035646 100644 --- a/scheduler/Dependencies +++ b/scheduler/Dependencies @@ -1,361 +1,329 @@ -# DO NOT DELETE - -auth.o: cupsd.h ../cups/cups-private.h ../cups/cups.h ../cups/file.h -auth.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h -auth.o: ../cups/language.h ../cups/string-private.h ../config.h -auth.o: ../cups/debug-private.h ../cups/versioning.h ../cups/ppd-private.h -auth.o: ../cups/ppd.h ../cups/cups.h ../cups/pwg-private.h -auth.o: ../cups/http-private.h ../cups/http.h ../cups/md5-private.h -auth.o: ../cups/ipp-private.h ../cups/ipp.h ../cups/language-private.h -auth.o: ../cups/transcode.h ../cups/thread-private.h ../cups/file-private.h -auth.o: ../cups/cups-private.h mime.h ../cups/array.h ../cups/file.h sysman.h -auth.o: statbuf.h cert.h auth.h client.h policy.h printers.h -auth.o: ../cups/pwg-private.h classes.h job.h conf.h banners.h dirsvc.h -auth.o: network.h subscriptions.h -banners.o: cupsd.h ../cups/cups-private.h ../cups/cups.h ../cups/file.h -banners.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h -banners.o: ../cups/language.h ../cups/string-private.h ../config.h -banners.o: ../cups/debug-private.h ../cups/versioning.h ../cups/ppd-private.h -banners.o: ../cups/ppd.h ../cups/cups.h ../cups/pwg-private.h -banners.o: ../cups/http-private.h ../cups/http.h ../cups/md5-private.h -banners.o: ../cups/ipp-private.h ../cups/ipp.h ../cups/language-private.h -banners.o: ../cups/transcode.h ../cups/thread-private.h -banners.o: ../cups/file-private.h ../cups/cups-private.h mime.h -banners.o: ../cups/array.h ../cups/file.h sysman.h statbuf.h cert.h auth.h -banners.o: client.h policy.h printers.h ../cups/pwg-private.h classes.h job.h -banners.o: conf.h banners.h dirsvc.h network.h subscriptions.h ../cups/dir.h -cert.o: cupsd.h ../cups/cups-private.h ../cups/cups.h ../cups/file.h -cert.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h -cert.o: ../cups/language.h ../cups/string-private.h ../config.h -cert.o: ../cups/debug-private.h ../cups/versioning.h ../cups/ppd-private.h -cert.o: ../cups/ppd.h ../cups/cups.h ../cups/pwg-private.h -cert.o: ../cups/http-private.h ../cups/http.h ../cups/md5-private.h -cert.o: ../cups/ipp-private.h ../cups/ipp.h ../cups/language-private.h -cert.o: ../cups/transcode.h ../cups/thread-private.h ../cups/file-private.h -cert.o: ../cups/cups-private.h mime.h ../cups/array.h ../cups/file.h sysman.h -cert.o: statbuf.h cert.h auth.h client.h policy.h printers.h -cert.o: ../cups/pwg-private.h classes.h job.h conf.h banners.h dirsvc.h -cert.o: network.h subscriptions.h -classes.o: cupsd.h ../cups/cups-private.h ../cups/cups.h ../cups/file.h -classes.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h -classes.o: ../cups/language.h ../cups/string-private.h ../config.h -classes.o: ../cups/debug-private.h ../cups/versioning.h ../cups/ppd-private.h -classes.o: ../cups/ppd.h ../cups/cups.h ../cups/pwg-private.h -classes.o: ../cups/http-private.h ../cups/http.h ../cups/md5-private.h -classes.o: ../cups/ipp-private.h ../cups/ipp.h ../cups/language-private.h -classes.o: ../cups/transcode.h ../cups/thread-private.h -classes.o: ../cups/file-private.h ../cups/cups-private.h mime.h -classes.o: ../cups/array.h ../cups/file.h sysman.h statbuf.h cert.h auth.h -classes.o: client.h policy.h printers.h ../cups/pwg-private.h classes.h job.h -classes.o: conf.h banners.h dirsvc.h network.h subscriptions.h -client.o: cupsd.h ../cups/cups-private.h ../cups/cups.h ../cups/file.h -client.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h -client.o: ../cups/language.h ../cups/string-private.h ../config.h -client.o: ../cups/debug-private.h ../cups/versioning.h ../cups/ppd-private.h -client.o: ../cups/ppd.h ../cups/cups.h ../cups/pwg-private.h -client.o: ../cups/http-private.h ../cups/http.h ../cups/md5-private.h -client.o: ../cups/ipp-private.h ../cups/ipp.h ../cups/language-private.h -client.o: ../cups/transcode.h ../cups/thread-private.h ../cups/file-private.h -client.o: ../cups/cups-private.h mime.h ../cups/array.h ../cups/file.h -client.o: sysman.h statbuf.h cert.h auth.h client.h policy.h printers.h -client.o: ../cups/pwg-private.h classes.h job.h conf.h banners.h dirsvc.h -client.o: network.h subscriptions.h -conf.o: cupsd.h ../cups/cups-private.h ../cups/cups.h ../cups/file.h -conf.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h -conf.o: ../cups/language.h ../cups/string-private.h ../config.h -conf.o: ../cups/debug-private.h ../cups/versioning.h ../cups/ppd-private.h -conf.o: ../cups/ppd.h ../cups/cups.h ../cups/pwg-private.h -conf.o: ../cups/http-private.h ../cups/http.h ../cups/md5-private.h -conf.o: ../cups/ipp-private.h ../cups/ipp.h ../cups/language-private.h -conf.o: ../cups/transcode.h ../cups/thread-private.h ../cups/file-private.h -conf.o: ../cups/cups-private.h mime.h ../cups/array.h ../cups/file.h sysman.h -conf.o: statbuf.h cert.h auth.h client.h policy.h printers.h -conf.o: ../cups/pwg-private.h classes.h job.h conf.h banners.h dirsvc.h -conf.o: network.h subscriptions.h -dirsvc.o: cupsd.h ../cups/cups-private.h ../cups/cups.h ../cups/file.h -dirsvc.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h -dirsvc.o: ../cups/language.h ../cups/string-private.h ../config.h -dirsvc.o: ../cups/debug-private.h ../cups/versioning.h ../cups/ppd-private.h -dirsvc.o: ../cups/ppd.h ../cups/cups.h ../cups/pwg-private.h -dirsvc.o: ../cups/http-private.h ../cups/http.h ../cups/md5-private.h -dirsvc.o: ../cups/ipp-private.h ../cups/ipp.h ../cups/language-private.h -dirsvc.o: ../cups/transcode.h ../cups/thread-private.h ../cups/file-private.h -dirsvc.o: ../cups/cups-private.h mime.h ../cups/array.h ../cups/file.h -dirsvc.o: sysman.h statbuf.h cert.h auth.h client.h policy.h printers.h -dirsvc.o: ../cups/pwg-private.h classes.h job.h conf.h banners.h dirsvc.h -dirsvc.o: network.h subscriptions.h -env.o: cupsd.h ../cups/cups-private.h ../cups/cups.h ../cups/file.h -env.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h -env.o: ../cups/language.h ../cups/string-private.h ../config.h -env.o: ../cups/debug-private.h ../cups/versioning.h ../cups/ppd-private.h -env.o: ../cups/ppd.h ../cups/cups.h ../cups/pwg-private.h -env.o: ../cups/http-private.h ../cups/http.h ../cups/md5-private.h -env.o: ../cups/ipp-private.h ../cups/ipp.h ../cups/language-private.h -env.o: ../cups/transcode.h ../cups/thread-private.h ../cups/file-private.h -env.o: ../cups/cups-private.h mime.h ../cups/array.h ../cups/file.h sysman.h -env.o: statbuf.h cert.h auth.h client.h policy.h printers.h -env.o: ../cups/pwg-private.h classes.h job.h conf.h banners.h dirsvc.h -env.o: network.h subscriptions.h -file.o: cupsd.h ../cups/cups-private.h ../cups/cups.h ../cups/file.h -file.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h -file.o: ../cups/language.h ../cups/string-private.h ../config.h -file.o: ../cups/debug-private.h ../cups/versioning.h ../cups/ppd-private.h -file.o: ../cups/ppd.h ../cups/cups.h ../cups/pwg-private.h -file.o: ../cups/http-private.h ../cups/http.h ../cups/md5-private.h -file.o: ../cups/ipp-private.h ../cups/ipp.h ../cups/language-private.h -file.o: ../cups/transcode.h ../cups/thread-private.h ../cups/file-private.h -file.o: ../cups/cups-private.h mime.h ../cups/array.h ../cups/file.h sysman.h -file.o: statbuf.h cert.h auth.h client.h policy.h printers.h -file.o: ../cups/pwg-private.h classes.h job.h conf.h banners.h dirsvc.h -file.o: network.h subscriptions.h ../cups/dir.h -main.o: cupsd.h ../cups/cups-private.h ../cups/cups.h ../cups/file.h -main.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h -main.o: ../cups/language.h ../cups/string-private.h ../config.h -main.o: ../cups/debug-private.h ../cups/versioning.h ../cups/ppd-private.h -main.o: ../cups/ppd.h ../cups/cups.h ../cups/pwg-private.h -main.o: ../cups/http-private.h ../cups/http.h ../cups/md5-private.h -main.o: ../cups/ipp-private.h ../cups/ipp.h ../cups/language-private.h -main.o: ../cups/transcode.h ../cups/thread-private.h ../cups/file-private.h -main.o: ../cups/cups-private.h mime.h ../cups/array.h ../cups/file.h sysman.h -main.o: statbuf.h cert.h auth.h client.h policy.h printers.h -main.o: ../cups/pwg-private.h classes.h job.h conf.h banners.h dirsvc.h -main.o: network.h subscriptions.h -ipp.o: cupsd.h ../cups/cups-private.h ../cups/cups.h ../cups/file.h -ipp.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h -ipp.o: ../cups/language.h ../cups/string-private.h ../config.h -ipp.o: ../cups/debug-private.h ../cups/versioning.h ../cups/ppd-private.h -ipp.o: ../cups/ppd.h ../cups/cups.h ../cups/pwg-private.h -ipp.o: ../cups/http-private.h ../cups/http.h ../cups/md5-private.h -ipp.o: ../cups/ipp-private.h ../cups/ipp.h ../cups/language-private.h -ipp.o: ../cups/transcode.h ../cups/thread-private.h ../cups/file-private.h -ipp.o: ../cups/cups-private.h mime.h ../cups/array.h ../cups/file.h sysman.h -ipp.o: statbuf.h cert.h auth.h client.h policy.h printers.h -ipp.o: ../cups/pwg-private.h classes.h job.h conf.h banners.h dirsvc.h -ipp.o: network.h subscriptions.h ../cups/ppd-private.h -listen.o: cupsd.h ../cups/cups-private.h ../cups/cups.h ../cups/file.h -listen.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h -listen.o: ../cups/language.h ../cups/string-private.h ../config.h -listen.o: ../cups/debug-private.h ../cups/versioning.h ../cups/ppd-private.h -listen.o: ../cups/ppd.h ../cups/cups.h ../cups/pwg-private.h -listen.o: ../cups/http-private.h ../cups/http.h ../cups/md5-private.h -listen.o: ../cups/ipp-private.h ../cups/ipp.h ../cups/language-private.h -listen.o: ../cups/transcode.h ../cups/thread-private.h ../cups/file-private.h -listen.o: ../cups/cups-private.h mime.h ../cups/array.h ../cups/file.h -listen.o: sysman.h statbuf.h cert.h auth.h client.h policy.h printers.h -listen.o: ../cups/pwg-private.h classes.h job.h conf.h banners.h dirsvc.h -listen.o: network.h subscriptions.h -job.o: cupsd.h ../cups/cups-private.h ../cups/cups.h ../cups/file.h -job.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h -job.o: ../cups/language.h ../cups/string-private.h ../config.h -job.o: ../cups/debug-private.h ../cups/versioning.h ../cups/ppd-private.h -job.o: ../cups/ppd.h ../cups/cups.h ../cups/pwg-private.h -job.o: ../cups/http-private.h ../cups/http.h ../cups/md5-private.h -job.o: ../cups/ipp-private.h ../cups/ipp.h ../cups/language-private.h -job.o: ../cups/transcode.h ../cups/thread-private.h ../cups/file-private.h -job.o: ../cups/cups-private.h mime.h ../cups/array.h ../cups/file.h sysman.h -job.o: statbuf.h cert.h auth.h client.h policy.h printers.h -job.o: ../cups/pwg-private.h classes.h job.h conf.h banners.h dirsvc.h -job.o: network.h subscriptions.h ../cups/backend.h ../cups/dir.h -log.o: cupsd.h ../cups/cups-private.h ../cups/cups.h ../cups/file.h -log.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h -log.o: ../cups/language.h ../cups/string-private.h ../config.h -log.o: ../cups/debug-private.h ../cups/versioning.h ../cups/ppd-private.h -log.o: ../cups/ppd.h ../cups/cups.h ../cups/pwg-private.h -log.o: ../cups/http-private.h ../cups/http.h ../cups/md5-private.h -log.o: ../cups/ipp-private.h ../cups/ipp.h ../cups/language-private.h -log.o: ../cups/transcode.h ../cups/thread-private.h ../cups/file-private.h -log.o: ../cups/cups-private.h mime.h ../cups/array.h ../cups/file.h sysman.h -log.o: statbuf.h cert.h auth.h client.h policy.h printers.h -log.o: ../cups/pwg-private.h classes.h job.h conf.h banners.h dirsvc.h -log.o: network.h subscriptions.h -network.o: ../cups/http-private.h ../config.h ../cups/http.h -network.o: ../cups/md5-private.h ../cups/ipp-private.h ../cups/ipp.h cupsd.h -network.o: ../cups/cups-private.h ../cups/cups.h ../cups/file.h -network.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h -network.o: ../cups/language.h ../cups/string-private.h -network.o: ../cups/debug-private.h ../cups/versioning.h ../cups/ppd-private.h -network.o: ../cups/ppd.h ../cups/cups.h ../cups/pwg-private.h -network.o: ../cups/http-private.h ../cups/language-private.h -network.o: ../cups/transcode.h ../cups/thread-private.h -network.o: ../cups/file-private.h ../cups/cups-private.h mime.h -network.o: ../cups/array.h ../cups/file.h sysman.h statbuf.h cert.h auth.h -network.o: client.h policy.h printers.h ../cups/pwg-private.h classes.h job.h -network.o: conf.h banners.h dirsvc.h network.h subscriptions.h -policy.o: cupsd.h ../cups/cups-private.h ../cups/cups.h ../cups/file.h -policy.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h -policy.o: ../cups/language.h ../cups/string-private.h ../config.h -policy.o: ../cups/debug-private.h ../cups/versioning.h ../cups/ppd-private.h -policy.o: ../cups/ppd.h ../cups/cups.h ../cups/pwg-private.h -policy.o: ../cups/http-private.h ../cups/http.h ../cups/md5-private.h -policy.o: ../cups/ipp-private.h ../cups/ipp.h ../cups/language-private.h -policy.o: ../cups/transcode.h ../cups/thread-private.h ../cups/file-private.h -policy.o: ../cups/cups-private.h mime.h ../cups/array.h ../cups/file.h -policy.o: sysman.h statbuf.h cert.h auth.h client.h policy.h printers.h -policy.o: ../cups/pwg-private.h classes.h job.h conf.h banners.h dirsvc.h -policy.o: network.h subscriptions.h -printers.o: cupsd.h ../cups/cups-private.h ../cups/cups.h ../cups/file.h -printers.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h -printers.o: ../cups/language.h ../cups/string-private.h ../config.h -printers.o: ../cups/debug-private.h ../cups/versioning.h -printers.o: ../cups/ppd-private.h ../cups/ppd.h ../cups/cups.h -printers.o: ../cups/pwg-private.h ../cups/http-private.h ../cups/http.h -printers.o: ../cups/md5-private.h ../cups/ipp-private.h ../cups/ipp.h -printers.o: ../cups/language-private.h ../cups/transcode.h -printers.o: ../cups/thread-private.h ../cups/file-private.h -printers.o: ../cups/cups-private.h mime.h ../cups/array.h ../cups/file.h -printers.o: sysman.h statbuf.h cert.h auth.h client.h policy.h printers.h -printers.o: ../cups/pwg-private.h classes.h job.h conf.h banners.h dirsvc.h -printers.o: network.h subscriptions.h ../cups/dir.h -process.o: cupsd.h ../cups/cups-private.h ../cups/cups.h ../cups/file.h -process.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h -process.o: ../cups/language.h ../cups/string-private.h ../config.h -process.o: ../cups/debug-private.h ../cups/versioning.h ../cups/ppd-private.h -process.o: ../cups/ppd.h ../cups/cups.h ../cups/pwg-private.h -process.o: ../cups/http-private.h ../cups/http.h ../cups/md5-private.h -process.o: ../cups/ipp-private.h ../cups/ipp.h ../cups/language-private.h -process.o: ../cups/transcode.h ../cups/thread-private.h -process.o: ../cups/file-private.h ../cups/cups-private.h mime.h -process.o: ../cups/array.h ../cups/file.h sysman.h statbuf.h cert.h auth.h -process.o: client.h policy.h printers.h ../cups/pwg-private.h classes.h job.h -process.o: conf.h banners.h dirsvc.h network.h subscriptions.h -quotas.o: cupsd.h ../cups/cups-private.h ../cups/cups.h ../cups/file.h -quotas.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h -quotas.o: ../cups/language.h ../cups/string-private.h ../config.h -quotas.o: ../cups/debug-private.h ../cups/versioning.h ../cups/ppd-private.h -quotas.o: ../cups/ppd.h ../cups/cups.h ../cups/pwg-private.h -quotas.o: ../cups/http-private.h ../cups/http.h ../cups/md5-private.h -quotas.o: ../cups/ipp-private.h ../cups/ipp.h ../cups/language-private.h -quotas.o: ../cups/transcode.h ../cups/thread-private.h ../cups/file-private.h -quotas.o: ../cups/cups-private.h mime.h ../cups/array.h ../cups/file.h -quotas.o: sysman.h statbuf.h cert.h auth.h client.h policy.h printers.h -quotas.o: ../cups/pwg-private.h classes.h job.h conf.h banners.h dirsvc.h -quotas.o: network.h subscriptions.h -select.o: cupsd.h ../cups/cups-private.h ../cups/cups.h ../cups/file.h -select.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h -select.o: ../cups/language.h ../cups/string-private.h ../config.h -select.o: ../cups/debug-private.h ../cups/versioning.h ../cups/ppd-private.h -select.o: ../cups/ppd.h ../cups/cups.h ../cups/pwg-private.h -select.o: ../cups/http-private.h ../cups/http.h ../cups/md5-private.h -select.o: ../cups/ipp-private.h ../cups/ipp.h ../cups/language-private.h -select.o: ../cups/transcode.h ../cups/thread-private.h ../cups/file-private.h -select.o: ../cups/cups-private.h mime.h ../cups/array.h ../cups/file.h -select.o: sysman.h statbuf.h cert.h auth.h client.h policy.h printers.h -select.o: ../cups/pwg-private.h classes.h job.h conf.h banners.h dirsvc.h -select.o: network.h subscriptions.h -server.o: ../cups/http-private.h ../config.h ../cups/http.h -server.o: ../cups/md5-private.h ../cups/ipp-private.h ../cups/ipp.h cupsd.h -server.o: ../cups/cups-private.h ../cups/cups.h ../cups/file.h -server.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h -server.o: ../cups/language.h ../cups/string-private.h ../cups/debug-private.h -server.o: ../cups/versioning.h ../cups/ppd-private.h ../cups/ppd.h -server.o: ../cups/cups.h ../cups/pwg-private.h ../cups/http-private.h -server.o: ../cups/language-private.h ../cups/transcode.h -server.o: ../cups/thread-private.h ../cups/file-private.h -server.o: ../cups/cups-private.h mime.h ../cups/array.h ../cups/file.h -server.o: sysman.h statbuf.h cert.h auth.h client.h policy.h printers.h -server.o: ../cups/pwg-private.h classes.h job.h conf.h banners.h dirsvc.h -server.o: network.h subscriptions.h -statbuf.o: cupsd.h ../cups/cups-private.h ../cups/cups.h ../cups/file.h -statbuf.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h -statbuf.o: ../cups/language.h ../cups/string-private.h ../config.h -statbuf.o: ../cups/debug-private.h ../cups/versioning.h ../cups/ppd-private.h -statbuf.o: ../cups/ppd.h ../cups/cups.h ../cups/pwg-private.h -statbuf.o: ../cups/http-private.h ../cups/http.h ../cups/md5-private.h -statbuf.o: ../cups/ipp-private.h ../cups/ipp.h ../cups/language-private.h -statbuf.o: ../cups/transcode.h ../cups/thread-private.h -statbuf.o: ../cups/file-private.h ../cups/cups-private.h mime.h -statbuf.o: ../cups/array.h ../cups/file.h sysman.h statbuf.h cert.h auth.h -statbuf.o: client.h policy.h printers.h ../cups/pwg-private.h classes.h job.h -statbuf.o: conf.h banners.h dirsvc.h network.h subscriptions.h -subscriptions.o: cupsd.h ../cups/cups-private.h ../cups/cups.h ../cups/file.h -subscriptions.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h -subscriptions.o: ../cups/array.h ../cups/language.h ../cups/string-private.h -subscriptions.o: ../config.h ../cups/debug-private.h ../cups/versioning.h -subscriptions.o: ../cups/ppd-private.h ../cups/ppd.h ../cups/cups.h -subscriptions.o: ../cups/pwg-private.h ../cups/http-private.h ../cups/http.h -subscriptions.o: ../cups/md5-private.h ../cups/ipp-private.h ../cups/ipp.h -subscriptions.o: ../cups/language-private.h ../cups/transcode.h -subscriptions.o: ../cups/thread-private.h ../cups/file-private.h -subscriptions.o: ../cups/cups-private.h mime.h ../cups/array.h ../cups/file.h -subscriptions.o: sysman.h statbuf.h cert.h auth.h client.h policy.h -subscriptions.o: printers.h ../cups/pwg-private.h classes.h job.h conf.h -subscriptions.o: banners.h dirsvc.h network.h subscriptions.h -sysman.o: cupsd.h ../cups/cups-private.h ../cups/cups.h ../cups/file.h -sysman.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h -sysman.o: ../cups/language.h ../cups/string-private.h ../config.h -sysman.o: ../cups/debug-private.h ../cups/versioning.h ../cups/ppd-private.h -sysman.o: ../cups/ppd.h ../cups/cups.h ../cups/pwg-private.h -sysman.o: ../cups/http-private.h ../cups/http.h ../cups/md5-private.h -sysman.o: ../cups/ipp-private.h ../cups/ipp.h ../cups/language-private.h -sysman.o: ../cups/transcode.h ../cups/thread-private.h ../cups/file-private.h -sysman.o: ../cups/cups-private.h mime.h ../cups/array.h ../cups/file.h -sysman.o: sysman.h statbuf.h cert.h auth.h client.h policy.h printers.h -sysman.o: ../cups/pwg-private.h classes.h job.h conf.h banners.h dirsvc.h -sysman.o: network.h subscriptions.h -filter.o: ../cups/string-private.h ../config.h ../cups/debug-private.h -filter.o: ../cups/versioning.h mime.h ../cups/array.h ../cups/ipp.h -filter.o: ../cups/file.h -mime.o: ../cups/string-private.h ../config.h ../cups/debug-private.h -mime.o: ../cups/versioning.h ../cups/dir.h ../cups/versioning.h -mime.o: mime-private.h mime.h ../cups/array.h ../cups/ipp.h ../cups/file.h -type.o: ../cups/string-private.h ../config.h ../cups/debug-private.h -type.o: ../cups/versioning.h mime.h ../cups/array.h ../cups/ipp.h -type.o: ../cups/file.h -cupsfilter.o: ../cups/cups-private.h ../cups/cups.h ../cups/file.h -cupsfilter.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h -cupsfilter.o: ../cups/array.h ../cups/language.h ../cups/string-private.h -cupsfilter.o: ../config.h ../cups/debug-private.h ../cups/versioning.h -cupsfilter.o: ../cups/ppd-private.h ../cups/ppd.h ../cups/cups.h -cupsfilter.o: ../cups/pwg-private.h ../cups/http-private.h ../cups/http.h -cupsfilter.o: ../cups/md5-private.h ../cups/ipp-private.h ../cups/ipp.h -cupsfilter.o: ../cups/language-private.h ../cups/transcode.h -cupsfilter.o: ../cups/thread-private.h ../cups/file-private.h -cupsfilter.o: ../cups/cups-private.h ../cups/ppd-private.h mime.h -cupsfilter.o: ../cups/array.h ../cups/file.h -cups-deviced.o: util.h ../cups/array-private.h ../cups/array.h -cups-deviced.o: ../cups/file-private.h ../cups/cups-private.h ../cups/dir.h -cups-deviced.o: ../cups/versioning.h -cups-exec.o: ../cups/string-private.h ../config.h -cups-lpd.o: ../cups/cups-private.h ../cups/cups.h ../cups/file.h -cups-lpd.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h -cups-lpd.o: ../cups/language.h ../cups/string-private.h ../config.h -cups-lpd.o: ../cups/debug-private.h ../cups/versioning.h -cups-lpd.o: ../cups/ppd-private.h ../cups/ppd.h ../cups/cups.h -cups-lpd.o: ../cups/pwg-private.h ../cups/http-private.h ../cups/http.h -cups-lpd.o: ../cups/md5-private.h ../cups/ipp-private.h ../cups/ipp.h -cups-lpd.o: ../cups/language-private.h ../cups/transcode.h -cups-lpd.o: ../cups/thread-private.h -cups-polld.o: ../cups/cups-private.h ../cups/cups.h ../cups/file.h -cups-polld.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h -cups-polld.o: ../cups/array.h ../cups/language.h ../cups/string-private.h -cups-polld.o: ../config.h ../cups/debug-private.h ../cups/versioning.h -cups-polld.o: ../cups/ppd-private.h ../cups/ppd.h ../cups/cups.h -cups-polld.o: ../cups/pwg-private.h ../cups/http-private.h ../cups/http.h -cups-polld.o: ../cups/md5-private.h ../cups/ipp-private.h ../cups/ipp.h -cups-polld.o: ../cups/language-private.h ../cups/transcode.h -cups-polld.o: ../cups/thread-private.h -testdirsvc.o: ../cups/cups.h ../cups/file.h ../cups/versioning.h -testdirsvc.o: ../cups/ipp.h ../cups/http.h ../cups/array.h ../cups/language.h -testdirsvc.o: ../cups/string-private.h ../config.h -testlpd.o: ../cups/cups.h ../cups/file.h ../cups/versioning.h ../cups/ipp.h -testlpd.o: ../cups/http.h ../cups/array.h ../cups/language.h -testlpd.o: ../cups/string-private.h ../config.h -testmime.o: ../cups/string-private.h ../config.h ../cups/dir.h -testmime.o: ../cups/versioning.h ../cups/debug-private.h ../cups/versioning.h -testmime.o: ../cups/ppd-private.h mime.h ../cups/array.h ../cups/ipp.h -testmime.o: ../cups/file.h -testspeed.o: ../cups/string-private.h ../config.h ../cups/cups.h -testspeed.o: ../cups/file.h ../cups/versioning.h ../cups/ipp.h ../cups/http.h -testspeed.o: ../cups/array.h ../cups/language.h ../cups/language.h -testspeed.o: ../cups/debug-private.h ../cups/versioning.h -testsub.o: ../cups/cups.h ../cups/file.h ../cups/versioning.h ../cups/ipp.h -testsub.o: ../cups/http.h ../cups/array.h ../cups/language.h -testsub.o: ../cups/debug-private.h ../cups/versioning.h -testsub.o: ../cups/string-private.h ../config.h -util.o: util.h ../cups/array-private.h ../cups/array.h ../cups/file-private.h -util.o: ../cups/cups-private.h -cups-driverd.o: util.h ../cups/array-private.h ../cups/array.h -cups-driverd.o: ../cups/file-private.h ../cups/cups-private.h ../cups/dir.h -cups-driverd.o: ../cups/versioning.h ../cups/transcode.h ../cups/language.h -cups-driverd.o: ../cups/array.h ../cups/ppd-private.h ../ppdc/ppdc.h -cups-driverd.o: ../cups/file.h +auth.o: auth.c cupsd.h ../cups/cups-private.h ../cups/string-private.h \ + ../config.h ../cups/debug-private.h ../cups/versioning.h \ + ../cups/ipp-private.h ../cups/ipp.h ../cups/http.h ../cups/array.h \ + ../cups/http-private.h ../cups/md5-private.h \ + ../cups/language-private.h ../cups/transcode.h ../cups/language.h \ + ../cups/pwg-private.h ../cups/cups.h ../cups/file.h \ + ../cups/ppd-private.h ../cups/ppd.h ../cups/thread-private.h \ + ../cups/file-private.h mime.h sysman.h statbuf.h cert.h auth.h \ + client.h policy.h printers.h classes.h job.h conf.h banners.h dirsvc.h \ + network.h subscriptions.h +avahi.o: avahi.c ../config.h +banners.o: banners.c cupsd.h ../cups/cups-private.h \ + ../cups/string-private.h ../config.h ../cups/debug-private.h \ + ../cups/versioning.h ../cups/ipp-private.h ../cups/ipp.h \ + ../cups/http.h ../cups/array.h ../cups/http-private.h \ + ../cups/md5-private.h ../cups/language-private.h ../cups/transcode.h \ + ../cups/language.h ../cups/pwg-private.h ../cups/cups.h ../cups/file.h \ + ../cups/ppd-private.h ../cups/ppd.h ../cups/thread-private.h \ + ../cups/file-private.h mime.h sysman.h statbuf.h cert.h auth.h \ + client.h policy.h printers.h classes.h job.h conf.h banners.h dirsvc.h \ + network.h subscriptions.h ../cups/dir.h +cert.o: cert.c cupsd.h ../cups/cups-private.h ../cups/string-private.h \ + ../config.h ../cups/debug-private.h ../cups/versioning.h \ + ../cups/ipp-private.h ../cups/ipp.h ../cups/http.h ../cups/array.h \ + ../cups/http-private.h ../cups/md5-private.h \ + ../cups/language-private.h ../cups/transcode.h ../cups/language.h \ + ../cups/pwg-private.h ../cups/cups.h ../cups/file.h \ + ../cups/ppd-private.h ../cups/ppd.h ../cups/thread-private.h \ + ../cups/file-private.h mime.h sysman.h statbuf.h cert.h auth.h \ + client.h policy.h printers.h classes.h job.h conf.h banners.h dirsvc.h \ + network.h subscriptions.h +classes.o: classes.c cupsd.h ../cups/cups-private.h \ + ../cups/string-private.h ../config.h ../cups/debug-private.h \ + ../cups/versioning.h ../cups/ipp-private.h ../cups/ipp.h \ + ../cups/http.h ../cups/array.h ../cups/http-private.h \ + ../cups/md5-private.h ../cups/language-private.h ../cups/transcode.h \ + ../cups/language.h ../cups/pwg-private.h ../cups/cups.h ../cups/file.h \ + ../cups/ppd-private.h ../cups/ppd.h ../cups/thread-private.h \ + ../cups/file-private.h mime.h sysman.h statbuf.h cert.h auth.h \ + client.h policy.h printers.h classes.h job.h conf.h banners.h dirsvc.h \ + network.h subscriptions.h +client.o: client.c cupsd.h ../cups/cups-private.h \ + ../cups/string-private.h ../config.h ../cups/debug-private.h \ + ../cups/versioning.h ../cups/ipp-private.h ../cups/ipp.h \ + ../cups/http.h ../cups/array.h ../cups/http-private.h \ + ../cups/md5-private.h ../cups/language-private.h ../cups/transcode.h \ + ../cups/language.h ../cups/pwg-private.h ../cups/cups.h ../cups/file.h \ + ../cups/ppd-private.h ../cups/ppd.h ../cups/thread-private.h \ + ../cups/file-private.h mime.h sysman.h statbuf.h cert.h auth.h \ + client.h policy.h printers.h classes.h job.h conf.h banners.h dirsvc.h \ + network.h subscriptions.h +conf.o: conf.c cupsd.h ../cups/cups-private.h ../cups/string-private.h \ + ../config.h ../cups/debug-private.h ../cups/versioning.h \ + ../cups/ipp-private.h ../cups/ipp.h ../cups/http.h ../cups/array.h \ + ../cups/http-private.h ../cups/md5-private.h \ + ../cups/language-private.h ../cups/transcode.h ../cups/language.h \ + ../cups/pwg-private.h ../cups/cups.h ../cups/file.h \ + ../cups/ppd-private.h ../cups/ppd.h ../cups/thread-private.h \ + ../cups/file-private.h mime.h sysman.h statbuf.h cert.h auth.h \ + client.h policy.h printers.h classes.h job.h conf.h banners.h dirsvc.h \ + network.h subscriptions.h +dirsvc.o: dirsvc.c cupsd.h ../cups/cups-private.h \ + ../cups/string-private.h ../config.h ../cups/debug-private.h \ + ../cups/versioning.h ../cups/ipp-private.h ../cups/ipp.h \ + ../cups/http.h ../cups/array.h ../cups/http-private.h \ + ../cups/md5-private.h ../cups/language-private.h ../cups/transcode.h \ + ../cups/language.h ../cups/pwg-private.h ../cups/cups.h ../cups/file.h \ + ../cups/ppd-private.h ../cups/ppd.h ../cups/thread-private.h \ + ../cups/file-private.h mime.h sysman.h statbuf.h cert.h auth.h \ + client.h policy.h printers.h classes.h job.h conf.h banners.h dirsvc.h \ + network.h subscriptions.h +env.o: env.c cupsd.h ../cups/cups-private.h ../cups/string-private.h \ + ../config.h ../cups/debug-private.h ../cups/versioning.h \ + ../cups/ipp-private.h ../cups/ipp.h ../cups/http.h ../cups/array.h \ + ../cups/http-private.h ../cups/md5-private.h \ + ../cups/language-private.h ../cups/transcode.h ../cups/language.h \ + ../cups/pwg-private.h ../cups/cups.h ../cups/file.h \ + ../cups/ppd-private.h ../cups/ppd.h ../cups/thread-private.h \ + ../cups/file-private.h mime.h sysman.h statbuf.h cert.h auth.h \ + client.h policy.h printers.h classes.h job.h conf.h banners.h dirsvc.h \ + network.h subscriptions.h +file.o: file.c cupsd.h ../cups/cups-private.h ../cups/string-private.h \ + ../config.h ../cups/debug-private.h ../cups/versioning.h \ + ../cups/ipp-private.h ../cups/ipp.h ../cups/http.h ../cups/array.h \ + ../cups/http-private.h ../cups/md5-private.h \ + ../cups/language-private.h ../cups/transcode.h ../cups/language.h \ + ../cups/pwg-private.h ../cups/cups.h ../cups/file.h \ + ../cups/ppd-private.h ../cups/ppd.h ../cups/thread-private.h \ + ../cups/file-private.h mime.h sysman.h statbuf.h cert.h auth.h \ + client.h policy.h printers.h classes.h job.h conf.h banners.h dirsvc.h \ + network.h subscriptions.h ../cups/dir.h +main.o: main.c cupsd.h ../cups/cups-private.h ../cups/string-private.h \ + ../config.h ../cups/debug-private.h ../cups/versioning.h \ + ../cups/ipp-private.h ../cups/ipp.h ../cups/http.h ../cups/array.h \ + ../cups/http-private.h ../cups/md5-private.h \ + ../cups/language-private.h ../cups/transcode.h ../cups/language.h \ + ../cups/pwg-private.h ../cups/cups.h ../cups/file.h \ + ../cups/ppd-private.h ../cups/ppd.h ../cups/thread-private.h \ + ../cups/file-private.h mime.h sysman.h statbuf.h cert.h auth.h \ + client.h policy.h printers.h classes.h job.h conf.h banners.h dirsvc.h \ + network.h subscriptions.h +ipp.o: ipp.c cupsd.h ../cups/cups-private.h ../cups/string-private.h \ + ../config.h ../cups/debug-private.h ../cups/versioning.h \ + ../cups/ipp-private.h ../cups/ipp.h ../cups/http.h ../cups/array.h \ + ../cups/http-private.h ../cups/md5-private.h \ + ../cups/language-private.h ../cups/transcode.h ../cups/language.h \ + ../cups/pwg-private.h ../cups/cups.h ../cups/file.h \ + ../cups/ppd-private.h ../cups/ppd.h ../cups/thread-private.h \ + ../cups/file-private.h mime.h sysman.h statbuf.h cert.h auth.h \ + client.h policy.h printers.h classes.h job.h conf.h banners.h dirsvc.h \ + network.h subscriptions.h +listen.o: listen.c cupsd.h ../cups/cups-private.h \ + ../cups/string-private.h ../config.h ../cups/debug-private.h \ + ../cups/versioning.h ../cups/ipp-private.h ../cups/ipp.h \ + ../cups/http.h ../cups/array.h ../cups/http-private.h \ + ../cups/md5-private.h ../cups/language-private.h ../cups/transcode.h \ + ../cups/language.h ../cups/pwg-private.h ../cups/cups.h ../cups/file.h \ + ../cups/ppd-private.h ../cups/ppd.h ../cups/thread-private.h \ + ../cups/file-private.h mime.h sysman.h statbuf.h cert.h auth.h \ + client.h policy.h printers.h classes.h job.h conf.h banners.h dirsvc.h \ + network.h subscriptions.h +job.o: job.c cupsd.h ../cups/cups-private.h ../cups/string-private.h \ + ../config.h ../cups/debug-private.h ../cups/versioning.h \ + ../cups/ipp-private.h ../cups/ipp.h ../cups/http.h ../cups/array.h \ + ../cups/http-private.h ../cups/md5-private.h \ + ../cups/language-private.h ../cups/transcode.h ../cups/language.h \ + ../cups/pwg-private.h ../cups/cups.h ../cups/file.h \ + ../cups/ppd-private.h ../cups/ppd.h ../cups/thread-private.h \ + ../cups/file-private.h mime.h sysman.h statbuf.h cert.h auth.h \ + client.h policy.h printers.h classes.h job.h conf.h banners.h dirsvc.h \ + network.h subscriptions.h ../cups/backend.h ../cups/dir.h +log.o: log.c cupsd.h ../cups/cups-private.h ../cups/string-private.h \ + ../config.h ../cups/debug-private.h ../cups/versioning.h \ + ../cups/ipp-private.h ../cups/ipp.h ../cups/http.h ../cups/array.h \ + ../cups/http-private.h ../cups/md5-private.h \ + ../cups/language-private.h ../cups/transcode.h ../cups/language.h \ + ../cups/pwg-private.h ../cups/cups.h ../cups/file.h \ + ../cups/ppd-private.h ../cups/ppd.h ../cups/thread-private.h \ + ../cups/file-private.h mime.h sysman.h statbuf.h cert.h auth.h \ + client.h policy.h printers.h classes.h job.h conf.h banners.h dirsvc.h \ + network.h subscriptions.h +network.o: network.c ../cups/http-private.h ../config.h ../cups/http.h \ + ../cups/versioning.h ../cups/array.h ../cups/md5-private.h \ + ../cups/ipp-private.h ../cups/ipp.h cupsd.h ../cups/cups-private.h \ + ../cups/string-private.h ../cups/debug-private.h \ + ../cups/language-private.h ../cups/transcode.h ../cups/language.h \ + ../cups/pwg-private.h ../cups/cups.h ../cups/file.h \ + ../cups/ppd-private.h ../cups/ppd.h ../cups/thread-private.h \ + ../cups/file-private.h mime.h sysman.h statbuf.h cert.h auth.h \ + client.h policy.h printers.h classes.h job.h conf.h banners.h dirsvc.h \ + network.h subscriptions.h +policy.o: policy.c cupsd.h ../cups/cups-private.h \ + ../cups/string-private.h ../config.h ../cups/debug-private.h \ + ../cups/versioning.h ../cups/ipp-private.h ../cups/ipp.h \ + ../cups/http.h ../cups/array.h ../cups/http-private.h \ + ../cups/md5-private.h ../cups/language-private.h ../cups/transcode.h \ + ../cups/language.h ../cups/pwg-private.h ../cups/cups.h ../cups/file.h \ + ../cups/ppd-private.h ../cups/ppd.h ../cups/thread-private.h \ + ../cups/file-private.h mime.h sysman.h statbuf.h cert.h auth.h \ + client.h policy.h printers.h classes.h job.h conf.h banners.h dirsvc.h \ + network.h subscriptions.h +printers.o: printers.c cupsd.h ../cups/cups-private.h \ + ../cups/string-private.h ../config.h ../cups/debug-private.h \ + ../cups/versioning.h ../cups/ipp-private.h ../cups/ipp.h \ + ../cups/http.h ../cups/array.h ../cups/http-private.h \ + ../cups/md5-private.h ../cups/language-private.h ../cups/transcode.h \ + ../cups/language.h ../cups/pwg-private.h ../cups/cups.h ../cups/file.h \ + ../cups/ppd-private.h ../cups/ppd.h ../cups/thread-private.h \ + ../cups/file-private.h mime.h sysman.h statbuf.h cert.h auth.h \ + client.h policy.h printers.h classes.h job.h conf.h banners.h dirsvc.h \ + network.h subscriptions.h ../cups/dir.h +process.o: process.c cupsd.h ../cups/cups-private.h \ + ../cups/string-private.h ../config.h ../cups/debug-private.h \ + ../cups/versioning.h ../cups/ipp-private.h ../cups/ipp.h \ + ../cups/http.h ../cups/array.h ../cups/http-private.h \ + ../cups/md5-private.h ../cups/language-private.h ../cups/transcode.h \ + ../cups/language.h ../cups/pwg-private.h ../cups/cups.h ../cups/file.h \ + ../cups/ppd-private.h ../cups/ppd.h ../cups/thread-private.h \ + ../cups/file-private.h mime.h sysman.h statbuf.h cert.h auth.h \ + client.h policy.h printers.h classes.h job.h conf.h banners.h dirsvc.h \ + network.h subscriptions.h +quotas.o: quotas.c cupsd.h ../cups/cups-private.h \ + ../cups/string-private.h ../config.h ../cups/debug-private.h \ + ../cups/versioning.h ../cups/ipp-private.h ../cups/ipp.h \ + ../cups/http.h ../cups/array.h ../cups/http-private.h \ + ../cups/md5-private.h ../cups/language-private.h ../cups/transcode.h \ + ../cups/language.h ../cups/pwg-private.h ../cups/cups.h ../cups/file.h \ + ../cups/ppd-private.h ../cups/ppd.h ../cups/thread-private.h \ + ../cups/file-private.h mime.h sysman.h statbuf.h cert.h auth.h \ + client.h policy.h printers.h classes.h job.h conf.h banners.h dirsvc.h \ + network.h subscriptions.h +select.o: select.c cupsd.h ../cups/cups-private.h \ + ../cups/string-private.h ../config.h ../cups/debug-private.h \ + ../cups/versioning.h ../cups/ipp-private.h ../cups/ipp.h \ + ../cups/http.h ../cups/array.h ../cups/http-private.h \ + ../cups/md5-private.h ../cups/language-private.h ../cups/transcode.h \ + ../cups/language.h ../cups/pwg-private.h ../cups/cups.h ../cups/file.h \ + ../cups/ppd-private.h ../cups/ppd.h ../cups/thread-private.h \ + ../cups/file-private.h mime.h sysman.h statbuf.h cert.h auth.h \ + client.h policy.h printers.h classes.h job.h conf.h banners.h dirsvc.h \ + network.h subscriptions.h +server.o: server.c ../cups/http-private.h ../config.h ../cups/http.h \ + ../cups/versioning.h ../cups/array.h ../cups/md5-private.h \ + ../cups/ipp-private.h ../cups/ipp.h cupsd.h ../cups/cups-private.h \ + ../cups/string-private.h ../cups/debug-private.h \ + ../cups/language-private.h ../cups/transcode.h ../cups/language.h \ + ../cups/pwg-private.h ../cups/cups.h ../cups/file.h \ + ../cups/ppd-private.h ../cups/ppd.h ../cups/thread-private.h \ + ../cups/file-private.h mime.h sysman.h statbuf.h cert.h auth.h \ + client.h policy.h printers.h classes.h job.h conf.h banners.h dirsvc.h \ + network.h subscriptions.h +statbuf.o: statbuf.c cupsd.h ../cups/cups-private.h \ + ../cups/string-private.h ../config.h ../cups/debug-private.h \ + ../cups/versioning.h ../cups/ipp-private.h ../cups/ipp.h \ + ../cups/http.h ../cups/array.h ../cups/http-private.h \ + ../cups/md5-private.h ../cups/language-private.h ../cups/transcode.h \ + ../cups/language.h ../cups/pwg-private.h ../cups/cups.h ../cups/file.h \ + ../cups/ppd-private.h ../cups/ppd.h ../cups/thread-private.h \ + ../cups/file-private.h mime.h sysman.h statbuf.h cert.h auth.h \ + client.h policy.h printers.h classes.h job.h conf.h banners.h dirsvc.h \ + network.h subscriptions.h +subscriptions.o: subscriptions.c cupsd.h ../cups/cups-private.h \ + ../cups/string-private.h ../config.h ../cups/debug-private.h \ + ../cups/versioning.h ../cups/ipp-private.h ../cups/ipp.h \ + ../cups/http.h ../cups/array.h ../cups/http-private.h \ + ../cups/md5-private.h ../cups/language-private.h ../cups/transcode.h \ + ../cups/language.h ../cups/pwg-private.h ../cups/cups.h ../cups/file.h \ + ../cups/ppd-private.h ../cups/ppd.h ../cups/thread-private.h \ + ../cups/file-private.h mime.h sysman.h statbuf.h cert.h auth.h \ + client.h policy.h printers.h classes.h job.h conf.h banners.h dirsvc.h \ + network.h subscriptions.h +sysman.o: sysman.c cupsd.h ../cups/cups-private.h \ + ../cups/string-private.h ../config.h ../cups/debug-private.h \ + ../cups/versioning.h ../cups/ipp-private.h ../cups/ipp.h \ + ../cups/http.h ../cups/array.h ../cups/http-private.h \ + ../cups/md5-private.h ../cups/language-private.h ../cups/transcode.h \ + ../cups/language.h ../cups/pwg-private.h ../cups/cups.h ../cups/file.h \ + ../cups/ppd-private.h ../cups/ppd.h ../cups/thread-private.h \ + ../cups/file-private.h mime.h sysman.h statbuf.h cert.h auth.h \ + client.h policy.h printers.h classes.h job.h conf.h banners.h dirsvc.h \ + network.h subscriptions.h +timeout.o: timeout.c cupsd.h ../cups/cups-private.h \ + ../cups/string-private.h ../config.h ../cups/debug-private.h \ + ../cups/versioning.h ../cups/ipp-private.h ../cups/ipp.h \ + ../cups/http.h ../cups/array.h ../cups/http-private.h \ + ../cups/md5-private.h ../cups/language-private.h ../cups/transcode.h \ + ../cups/language.h ../cups/pwg-private.h ../cups/cups.h ../cups/file.h \ + ../cups/ppd-private.h ../cups/ppd.h ../cups/thread-private.h \ + ../cups/file-private.h mime.h sysman.h statbuf.h cert.h auth.h \ + client.h policy.h printers.h classes.h job.h conf.h banners.h dirsvc.h \ + network.h subscriptions.h +tls.o: tls.c cupsd.h ../cups/cups-private.h ../cups/string-private.h \ + ../config.h ../cups/debug-private.h ../cups/versioning.h \ + ../cups/ipp-private.h ../cups/ipp.h ../cups/http.h ../cups/array.h \ + ../cups/http-private.h ../cups/md5-private.h \ + ../cups/language-private.h ../cups/transcode.h ../cups/language.h \ + ../cups/pwg-private.h ../cups/cups.h ../cups/file.h \ + ../cups/ppd-private.h ../cups/ppd.h ../cups/thread-private.h \ + ../cups/file-private.h mime.h sysman.h statbuf.h cert.h auth.h \ + client.h policy.h printers.h classes.h job.h conf.h banners.h dirsvc.h \ + network.h subscriptions.h tls-darwin.c +filter.o: filter.c ../cups/string-private.h ../config.h \ + ../cups/debug-private.h ../cups/versioning.h mime.h ../cups/array.h \ + ../cups/ipp.h ../cups/http.h ../cups/file.h +mime.o: mime.c ../cups/string-private.h ../config.h \ + ../cups/debug-private.h ../cups/versioning.h ../cups/dir.h \ + mime-private.h mime.h ../cups/array.h ../cups/ipp.h ../cups/http.h \ + ../cups/file.h +type.o: type.c ../cups/string-private.h ../config.h \ + ../cups/debug-private.h ../cups/versioning.h mime.h ../cups/array.h \ + ../cups/ipp.h ../cups/http.h ../cups/file.h +cupsfilter.o: cupsfilter.c ../cups/cups-private.h \ + ../cups/string-private.h ../config.h ../cups/debug-private.h \ + ../cups/versioning.h ../cups/ipp-private.h ../cups/ipp.h \ + ../cups/http.h ../cups/array.h ../cups/http-private.h \ + ../cups/md5-private.h ../cups/language-private.h ../cups/transcode.h \ + ../cups/language.h ../cups/pwg-private.h ../cups/cups.h ../cups/file.h \ + ../cups/ppd-private.h ../cups/ppd.h ../cups/thread-private.h \ + ../cups/file-private.h mime.h +cups-deviced.o: cups-deviced.c util.h ../cups/array-private.h \ + ../cups/array.h ../cups/versioning.h ../cups/file-private.h \ + ../cups/cups-private.h ../cups/string-private.h ../config.h \ + ../cups/debug-private.h ../cups/ipp-private.h ../cups/ipp.h \ + ../cups/http.h ../cups/http-private.h ../cups/md5-private.h \ + ../cups/language-private.h ../cups/transcode.h ../cups/language.h \ + ../cups/pwg-private.h ../cups/cups.h ../cups/file.h \ + ../cups/ppd-private.h ../cups/ppd.h ../cups/thread-private.h \ + ../cups/dir.h +cups-exec.o: cups-exec.c ../cups/string-private.h ../config.h +cups-lpd.o: cups-lpd.c ../cups/cups-private.h ../cups/string-private.h \ + ../config.h ../cups/debug-private.h ../cups/versioning.h \ + ../cups/ipp-private.h ../cups/ipp.h ../cups/http.h ../cups/array.h \ + ../cups/http-private.h ../cups/md5-private.h \ + ../cups/language-private.h ../cups/transcode.h ../cups/language.h \ + ../cups/pwg-private.h ../cups/cups.h ../cups/file.h \ + ../cups/ppd-private.h ../cups/ppd.h ../cups/thread-private.h +testlpd.o: testlpd.c ../cups/cups.h ../cups/file.h ../cups/versioning.h \ + ../cups/ipp.h ../cups/http.h ../cups/array.h ../cups/language.h \ + ../cups/string-private.h ../config.h +testmime.o: testmime.c ../cups/string-private.h ../config.h ../cups/dir.h \ + ../cups/versioning.h ../cups/debug-private.h ../cups/ppd-private.h \ + ../cups/cups.h ../cups/file.h ../cups/ipp.h ../cups/http.h \ + ../cups/array.h ../cups/language.h ../cups/ppd.h ../cups/pwg-private.h \ + mime.h +testspeed.o: testspeed.c ../cups/string-private.h ../config.h \ + ../cups/cups.h ../cups/file.h ../cups/versioning.h ../cups/ipp.h \ + ../cups/http.h ../cups/array.h ../cups/language.h \ + ../cups/debug-private.h +testsub.o: testsub.c ../cups/cups.h ../cups/file.h ../cups/versioning.h \ + ../cups/ipp.h ../cups/http.h ../cups/array.h ../cups/language.h \ + ../cups/debug-private.h ../cups/string-private.h ../config.h \ + ../cups/ipp-private.h +util.o: util.c util.h ../cups/array-private.h ../cups/array.h \ + ../cups/versioning.h ../cups/file-private.h ../cups/cups-private.h \ + ../cups/string-private.h ../config.h ../cups/debug-private.h \ + ../cups/ipp-private.h ../cups/ipp.h ../cups/http.h \ + ../cups/http-private.h ../cups/md5-private.h \ + ../cups/language-private.h ../cups/transcode.h ../cups/language.h \ + ../cups/pwg-private.h ../cups/cups.h ../cups/file.h \ + ../cups/ppd-private.h ../cups/ppd.h ../cups/thread-private.h +cups-driverd.o: cups-driverd.cxx util.h ../cups/array-private.h \ + ../cups/array.h ../cups/versioning.h ../cups/file-private.h \ + ../cups/cups-private.h ../cups/string-private.h ../config.h \ + ../cups/debug-private.h ../cups/ipp-private.h ../cups/ipp.h \ + ../cups/http.h ../cups/http-private.h ../cups/md5-private.h \ + ../cups/language-private.h ../cups/transcode.h ../cups/language.h \ + ../cups/pwg-private.h ../cups/cups.h ../cups/file.h \ + ../cups/ppd-private.h ../cups/ppd.h ../cups/thread-private.h \ + ../cups/dir.h ../ppdc/ppdc.h diff --git a/scheduler/Makefile b/scheduler/Makefile index 18dc80c..2790569 100644 --- a/scheduler/Makefile +++ b/scheduler/Makefile @@ -1,9 +1,9 @@ # -# "$Id: Makefile 9766 2011-05-11 22:17:34Z mike $" +# "$Id: Makefile 11173 2013-07-23 12:31:34Z msweet $" # # Scheduler Makefile for CUPS. # -# Copyright 2007-2011 by Apple Inc. +# Copyright 2007-2012 by Apple Inc. # Copyright 1997-2007 by Easy Software Products, all rights reserved. # # These coded instructions, statements, and computer programs are the @@ -21,6 +21,7 @@ CUPSDOBJS = \ cert.o \ classes.o \ client.o \ + colorman.o \ conf.o \ dirsvc.o \ env.o \ @@ -39,7 +40,8 @@ CUPSDOBJS = \ server.o \ statbuf.o \ subscriptions.o \ - sysman.o + sysman.o \ + tls.o LIBOBJS = \ filter.o \ mime.o \ @@ -51,8 +53,6 @@ COBJS = \ cups-deviced.o \ cups-exec.o \ cups-lpd.o \ - cups-polld.o \ - testdirsvc.o \ testlpd.o \ testmime.o \ testspeed.o \ @@ -68,7 +68,6 @@ LIBTARGETS = \ libcupsmime.a UNITTARGETS = \ - testdirsvc \ testlpd \ testmime \ testspeed \ @@ -80,8 +79,7 @@ PROGRAMS = \ cups-deviced \ cups-driverd \ cups-exec \ - cups-lpd \ - cups-polld + cups-lpd TARGETS = \ $(LIBTARGETS) \ @@ -124,8 +122,16 @@ clean: # depend: - makedepend -Y -I.. -fDependencies $(COBJS:.o=.c) \ - $(CXXOBJS:.o=.cxx) >/dev/null 2>&1 + $(CC) -MM $(ALL_CFLAGS) $(COBJS:.o=.c) >Dependencies + $(CXX) -MM $(ALL_CXXFLAGS) $(CXXOBJS:.o=.cxx) >>Dependencies + + +# +# Run oclint to check code coverage... +# + +oclint: + oclint -o=oclint.html -html $(CUPSDOBJS:.o=.c) $(LIBOBJS:.o=.c) -- $(ALL_CFLAGS) # @@ -213,12 +219,8 @@ install-data: install-exec: echo Installing programs in $(SBINDIR)... $(INSTALL_DIR) -m 755 $(SBINDIR) - $(INSTALL_BIN) -m 500 cupsd $(SBINDIR) + $(INSTALL_BIN) -m $(CUPS_CUPSD_FILE_PERM) cupsd $(SBINDIR) $(INSTALL_BIN) cupsfilter $(SBINDIR) - -if test "x`uname`" = xDarwin; then \ - $(INSTALL_DIR) $(BUILDROOT)/System/Library/Printers/Libraries; \ - $(LN) $(sbindir)/cupsfilter $(BUILDROOT)/System/Library/Printers/Libraries/convert; \ - fi echo Installing programs in $(SERVERBIN)/daemon... $(INSTALL_DIR) -m 755 $(SERVERBIN) $(INSTALL_DIR) -m 755 $(SERVERBIN)/daemon @@ -226,7 +228,6 @@ install-exec: $(INSTALL_BIN) cups-driverd $(SERVERBIN)/daemon $(INSTALL_BIN) cups-exec $(SERVERBIN)/daemon $(INSTALL_BIN) cups-lpd $(SERVERBIN)/daemon - $(INSTALL_BIN) cups-polld $(SERVERBIN)/daemon if test "x$(SYMROOT)" != "x"; then \ $(INSTALL_DIR) $(SYMROOT); \ for file in $(PROGRAMS); do \ @@ -284,7 +285,6 @@ uninstall: $(RM) $(SERVERBIN)/daemon/cups-driverd $(RM) $(SERVERBIN)/daemon/cups-exec $(RM) $(SERVERBIN)/daemon/cups-lpd - $(RM) $(SERVERBIN)/daemon/cups-polld $(RM) $(BUILDROOT)/System/Library/Printers/Libraries/convert -$(RMDIR) $(STATEDIR)/certs -$(RMDIR) $(STATEDIR) @@ -389,6 +389,8 @@ cupsd-static: $(CUPSDOBJS) libcupsmime.a ../cups/$(LIBCUPSSTATIC) $(LIBMALLOC) $(SERVERLIBS) $(DNSSDLIBS) $(LIBGSSAPI) \ $(LIBWRAP) +tls.o: tls-darwin.c tls-gnutls.c tls-openssl.c + # # Make the cupsfilter utility. @@ -439,15 +441,6 @@ cups-lpd: cups-lpd.o ../cups/$(LIBCUPS) # -# Make the polling daemon, "cups-polld". -# - -cups-polld: cups-polld.o ../cups/$(LIBCUPS) - echo Linking $@... - $(CC) $(LDFLAGS) -o cups-polld cups-polld.o $(LIBS) - - -# # libcupsmime.so.1, libcupsmime.sl.1 # @@ -507,15 +500,6 @@ libcupsmime.a: $(LIBOBJS) # -# Make the test program, "testdirsvc". -# - -testdirsvc: testdirsvc.o - echo Linking $@... - $(CC) $(LDFLAGS) -o testdirsvc testdirsvc.o $(COMMONLIBS) $(NETLIBS) - - -# # Make the test program, "testlpd". # @@ -564,7 +548,7 @@ testsub: testsub.o ../cups/$(LIBCUPSSTATIC) sloc: echo "cupsd: \c" - sloccount $(CUPSDOBJS:.o=.c) $(LIBOBJS:.o=.c) cups-driverd.cxx cups-polld.c cups-lpd.c 2>/dev/null | grep "Total Physical" | awk '{print $$9}' + sloccount $(CUPSDOBJS:.o=.c) $(LIBOBJS:.o=.c) cups-driverd.cxx cups-lpd.c 2>/dev/null | grep "Total Physical" | awk '{print $$9}' # @@ -575,5 +559,5 @@ include Dependencies # -# End of "$Id: Makefile 9766 2011-05-11 22:17:34Z mike $". +# End of "$Id: Makefile 11173 2013-07-23 12:31:34Z msweet $". # diff --git a/scheduler/auth.c b/scheduler/auth.c index d2aeb40..1169adf 100644 --- a/scheduler/auth.c +++ b/scheduler/auth.c @@ -1,9 +1,9 @@ /* - * "$Id: auth.c 9949 2011-08-31 04:58:33Z mike $" + * "$Id: auth.c 11173 2013-07-23 12:31:34Z msweet $" * * Authorization routines for the CUPS scheduler. * - * Copyright 2007-2011 by Apple Inc. + * Copyright 2007-2012 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * This file contains Kerberos support code, copyright 2006 by @@ -89,14 +89,13 @@ extern const char *cssmErrorString(int error); typedef struct xucred cupsd_ucred_t; # define CUPSD_UCRED_UID(c) (c).cr_uid #else +# ifndef __OpenBSD__ typedef struct ucred cupsd_ucred_t; +# else +typedef struct sockpeercred cupsd_ucred_t; +# endif # define CUPSD_UCRED_UID(c) (c).uid #endif /* HAVE_SYS_UCRED_H */ -#ifdef HAVE_KRB5_IPC_CLIENT_SET_TARGET_UID -/* Not in public headers... */ -extern void krb5_ipc_client_set_target_uid(uid_t); -extern void krb5_ipc_client_clear_target(void); -#endif /* HAVE_KRB5_IPC_CLIENT_SET_TARGET_UID */ /* @@ -130,8 +129,8 @@ static void to64(char *s, unsigned long v, int n); #if HAVE_LIBPAM typedef struct cupsd_authdata_s /**** Authentication data ****/ { - char username[33], /* Username string */ - password[33]; /* Password string */ + char username[HTTP_MAX_VALUE], /* Username string */ + password[HTTP_MAX_VALUE]; /* Password string */ } cupsd_authdata_t; #endif /* HAVE_LIBPAM */ @@ -322,8 +321,10 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */ int type; /* Authentication type */ const char *authorization; /* Pointer into Authorization string */ char *ptr, /* Pointer into string */ - username[256], /* Username string */ - password[33]; /* Password string */ + username[HTTP_MAX_VALUE], + /* Username string */ + password[HTTP_MAX_VALUE]; + /* Password string */ cupsd_cert_t *localuser; /* Certificate username */ char nonce[HTTP_MAX_VALUE], /* Nonce value from client */ md5[33], /* MD5 password */ @@ -356,18 +357,19 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */ con->type = CUPSD_AUTH_NONE; cupsdLogMessage(CUPSD_LOG_DEBUG2, - "cupsdAuthorize: con->uri=\"%s\", con->best=%p(%s)", - con->uri, con->best, con->best ? con->best->location : ""); + "[Client %d] con->uri=\"%s\", con->best=%p(%s)", + con->http.fd, con->uri, con->best, + con->best ? con->best->location : ""); if (con->best && con->best->type != CUPSD_AUTH_NONE) { if (con->best->type == CUPSD_AUTH_DEFAULT) - type = DefaultAuthType; + type = cupsdDefaultAuthType(); else type = con->best->type; } else - type = DefaultAuthType; + type = cupsdDefaultAuthType(); /* * Decode the Authorization string... @@ -375,8 +377,8 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */ authorization = httpGetField(&con->http, HTTP_FIELD_AUTHORIZATION); - cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAuthorize: Authorization=\"%s\"", - authorization); + cupsdLogMessage(CUPSD_LOG_DEBUG2, "[Client %d] Authorization=\"%s\"", + con->http.fd, authorization); username[0] = '\0'; password[0] = '\0'; @@ -400,7 +402,8 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */ */ cupsdLogMessage(CUPSD_LOG_DEBUG, - "cupsdAuthorize: No authentication data provided."); + "[Client %d] No authentication data provided.", + con->http.fd); return; } #ifdef HAVE_AUTHORIZATION_H @@ -425,7 +428,8 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */ if (authlen != kAuthorizationExternalFormLength) { cupsdLogMessage(CUPSD_LOG_ERROR, - "External Authorization reference size is incorrect!"); + "[Client %d] External Authorization reference size is " + "incorrect.", con->http.fd); return; } @@ -433,8 +437,9 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */ (AuthorizationExternalForm *)nonce, &con->authref)) != 0) { cupsdLogMessage(CUPSD_LOG_ERROR, - "AuthorizationCreateFromExternalForm returned %d (%s)", - (int)status, cssmErrorString(status)); + "[Client %d] AuthorizationCreateFromExternalForm " + "returned %d (%s)", con->http.fd, (int)status, + cssmErrorString(status)); return; } @@ -449,8 +454,8 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */ strlcpy(username, authinfo->items[0].value, sizeof(username)); cupsdLogMessage(CUPSD_LOG_DEBUG, - "cupsdAuthorize: Authorized as \"%s\" using AuthRef", - username); + "[Client %d] Authorized as \"%s\" using AuthRef", + con->http.fd, username); } AuthorizationFreeItemSet(authinfo); @@ -470,15 +475,17 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */ if (getsockopt(con->http.fd, 0, LOCAL_PEERCRED, &peercred, &peersize)) { - cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to get peer credentials - %s", - strerror(errno)); + cupsdLogMessage(CUPSD_LOG_ERROR, + "[Client %d] Unable to get peer credentials - %s", + con->http.fd, strerror(errno)); return; } if ((pwd = getpwuid(CUPSD_UCRED_UID(peercred))) == NULL) { cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to find UID %d for peer credentials.", + "[Client %d] Unable to find UID %d for peer " + "credentials.", con->http.fd, (int)CUPSD_UCRED_UID(peercred)); return; } @@ -486,8 +493,8 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */ strlcpy(username, pwd->pw_name, sizeof(username)); cupsdLogMessage(CUPSD_LOG_DEBUG, - "cupsdAuthorize: Authorized as \"%s\" using " - "AuthRef + PeerCred", username); + "[Client %d] Authorized as \"%s\" using " + "AuthRef + PeerCred", con->http.fd, username); } con->type = CUPSD_AUTH_BASIC; @@ -506,21 +513,43 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */ socklen_t peersize; /* Size of peer credentials */ #ifdef HAVE_AUTHORIZATION_H const char *name; /* Authorizing name */ + int no_peer = 0; /* Don't allow peer credentials? */ + + /* + * See if we should allow peer credentials... + */ for (name = (char *)cupsArrayFirst(con->best->names); name; name = (char *)cupsArrayNext(con->best->names)) - if (!_cups_strncasecmp(name, "@AUTHKEY(", 9) || !_cups_strcasecmp(name, "@SYSTEM")) + { + if (!_cups_strncasecmp(name, "@AUTHKEY(", 9) || + !_cups_strcasecmp(name, "@SYSTEM")) { - cupsdLogMessage(CUPSD_LOG_ERROR, - "PeerCred authentication not allowed for resource."); - return; + /* Normally don't want peer credentials if we need an auth key... */ + no_peer = 1; } + else if (!_cups_strcasecmp(name, "@OWNER")) + { + /* but if @OWNER is present then we allow it... */ + no_peer = 0; + break; + } + } + + if (no_peer) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "[Client %d] PeerCred authentication not allowed for " + "resource per AUTHKEY policy.", con->http.fd); + return; + } #endif /* HAVE_AUTHORIZATION_H */ if ((pwd = getpwnam(authorization + 9)) == NULL) { - cupsdLogMessage(CUPSD_LOG_ERROR, "User \"%s\" does not exist.", + cupsdLogMessage(CUPSD_LOG_ERROR, + "[Client %d] User \"%s\" does not exist.", con->http.fd, authorization + 9); return; } @@ -533,26 +562,27 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */ if (getsockopt(con->http.fd, SOL_SOCKET, SO_PEERCRED, &peercred, &peersize)) # endif /* __APPLE__ */ { - cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to get peer credentials - %s", - strerror(errno)); + cupsdLogMessage(CUPSD_LOG_ERROR, + "[Client %d] Unable to get peer credentials - %s", + con->http.fd, strerror(errno)); return; } if (pwd->pw_uid != CUPSD_UCRED_UID(peercred)) { cupsdLogMessage(CUPSD_LOG_ERROR, - "Invalid peer credentials for \"%s\" - got %d, " - "expected %d!", authorization + 9, + "[Client %d] Invalid peer credentials for \"%s\" - got " + "%d, expected %d!", con->http.fd, authorization + 9, CUPSD_UCRED_UID(peercred), pwd->pw_uid); # ifdef HAVE_SYS_UCRED_H - cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdAuthorize: cr_version=%d", - peercred.cr_version); - cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdAuthorize: cr_uid=%d", - peercred.cr_uid); - cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdAuthorize: cr_ngroups=%d", - peercred.cr_ngroups); - cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdAuthorize: cr_groups[0]=%d", - peercred.cr_groups[0]); + cupsdLogMessage(CUPSD_LOG_DEBUG, "[Client %d] cr_version=%d", + con->http.fd, peercred.cr_version); + cupsdLogMessage(CUPSD_LOG_DEBUG, "[Client %d] cr_uid=%d", + con->http.fd, peercred.cr_uid); + cupsdLogMessage(CUPSD_LOG_DEBUG, "[Client %d] cr_ngroups=%d", + con->http.fd, peercred.cr_ngroups); + cupsdLogMessage(CUPSD_LOG_DEBUG, "[Client %d] cr_groups[0]=%d", + con->http.fd, peercred.cr_groups[0]); # endif /* HAVE_SYS_UCRED_H */ return; } @@ -564,7 +594,7 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */ # endif /* HAVE_GSSAPI */ cupsdLogMessage(CUPSD_LOG_DEBUG, - "cupsdAuthorize: Authorized as %s using PeerCred", + "[Client %d] Authorized as %s using PeerCred", con->http.fd, username); con->type = CUPSD_AUTH_BASIC; @@ -581,28 +611,20 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */ while (isspace(*authorization & 255)) authorization ++; - if ((localuser = cupsdFindCert(authorization)) != NULL) - { - strlcpy(username, localuser->username, sizeof(username)); - - cupsdLogMessage(CUPSD_LOG_DEBUG, - "cupsdAuthorize: Authorized as %s using Local", - username); - } - else + if ((localuser = cupsdFindCert(authorization)) == NULL) { cupsdLogMessage(CUPSD_LOG_ERROR, - "cupsdAuthorize: Local authentication certificate not " - "found!"); + "[Client %d] Local authentication certificate not found.", + con->http.fd); return; } -#ifdef HAVE_GSSAPI - if (localuser->ccache) - con->type = CUPSD_AUTH_NEGOTIATE; - else -#endif /* HAVE_GSSAPI */ - con->type = CUPSD_AUTH_BASIC; + strlcpy(username, localuser->username, sizeof(username)); + con->type = localuser->type; + + cupsdLogMessage(CUPSD_LOG_DEBUG, + "[Client %d] Authorized as %s using Local", con->http.fd, + username); } else if (!strncmp(authorization, "Basic", 5)) { @@ -626,8 +648,8 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */ if ((ptr = strchr(username, ':')) == NULL) { - cupsdLogMessage(CUPSD_LOG_ERROR, - "cupsdAuthorize: Missing Basic password!"); + cupsdLogMessage(CUPSD_LOG_ERROR, "[Client %d] Missing Basic password.", + con->http.fd); return; } @@ -639,8 +661,8 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */ * Username must not be empty... */ - cupsdLogMessage(CUPSD_LOG_ERROR, - "cupsdAuthorize: Empty Basic username!"); + cupsdLogMessage(CUPSD_LOG_ERROR, "[Client %d] Empty Basic username.", + con->http.fd); return; } @@ -650,8 +672,8 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */ * Password must not be empty... */ - cupsdLogMessage(CUPSD_LOG_ERROR, - "cupsdAuthorize: Empty Basic password!"); + cupsdLogMessage(CUPSD_LOG_ERROR, "[Client %d] Empty Basic password.", + con->http.fd); return; } @@ -703,8 +725,8 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */ if (pamerr != PAM_SUCCESS) { cupsdLogMessage(CUPSD_LOG_ERROR, - "cupsdAuthorize: pam_start() returned %d (%s)!", - pamerr, pam_strerror(pamh, pamerr)); + "[Client %d] pam_start() returned %d (%s)", + con->http.fd, pamerr, pam_strerror(pamh, pamerr)); return; } @@ -713,8 +735,8 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */ pamerr = pam_set_item(pamh, PAM_RHOST, con->http.hostname); if (pamerr != PAM_SUCCESS) cupsdLogMessage(CUPSD_LOG_WARN, - "cupsdAuthorize: pam_set_item(PAM_RHOST) " - "returned %d (%s)!", pamerr, + "[Client %d] pam_set_item(PAM_RHOST) " + "returned %d (%s)", con->http.fd, pamerr, pam_strerror(pamh, pamerr)); # endif /* PAM_RHOST */ @@ -722,8 +744,8 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */ pamerr = pam_set_item(pamh, PAM_TTY, "cups"); if (pamerr != PAM_SUCCESS) cupsdLogMessage(CUPSD_LOG_WARN, - "cupsdAuthorize: pam_set_item(PAM_TTY) " - "returned %d (%s)!", pamerr, + "[Client %d] pam_set_item(PAM_TTY) " + "returned %d (%s)!", con->http.fd, pamerr, pam_strerror(pamh, pamerr)); # endif /* PAM_TTY */ # endif /* HAVE_PAM_SET_ITEM */ @@ -732,9 +754,8 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */ if (pamerr != PAM_SUCCESS) { cupsdLogMessage(CUPSD_LOG_ERROR, - "cupsdAuthorize: pam_authenticate() returned %d " - "(%s)!", - pamerr, pam_strerror(pamh, pamerr)); + "[Client %d] pam_authenticate() returned %d (%s)", + con->http.fd, pamerr, pam_strerror(pamh, pamerr)); pam_end(pamh, 0); return; } @@ -743,8 +764,8 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */ pamerr = pam_setcred(pamh, PAM_ESTABLISH_CRED | PAM_SILENT); if (pamerr != PAM_SUCCESS) cupsdLogMessage(CUPSD_LOG_WARN, - "cupsdAuthorize: pam_setcred() " - "returned %d (%s)!", pamerr, + "[Client %d] pam_setcred() returned %d (%s)", + con->http.fd, pamerr, pam_strerror(pamh, pamerr)); # endif /* HAVE_PAM_SETCRED */ @@ -752,9 +773,8 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */ if (pamerr != PAM_SUCCESS) { cupsdLogMessage(CUPSD_LOG_ERROR, - "cupsdAuthorize: pam_acct_mgmt() returned %d " - "(%s)!", - pamerr, pam_strerror(pamh, pamerr)); + "[Client %d] pam_acct_mgmt() returned %d (%s)", + con->http.fd, pamerr, pam_strerror(pamh, pamerr)); pam_end(pamh, 0); return; } @@ -771,16 +791,16 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */ cupsdLogMessage(CUPSD_LOG_DEBUG, - "cupsdAuthorize: AIX authenticate of username " - "\"%s\"", username); + "[Client %d] AIX authenticate of username \"%s\"", + con->http.fd, username); reenter = 1; if (authenticate(username, password, &reenter, &authmsg) != 0) { cupsdLogMessage(CUPSD_LOG_DEBUG, - "cupsdAuthorize: Unable to authenticate username " - "\"%s\": %s", - username, strerror(errno)); + "[Client %d] Unable to authenticate username " + "\"%s\": %s", con->http.fd, username, + strerror(errno)); return; } @@ -806,8 +826,8 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */ */ cupsdLogMessage(CUPSD_LOG_ERROR, - "cupsdAuthorize: Unknown username \"%s\"!", - username); + "[Client %d] Unknown username \"%s\".", + con->http.fd, username); return; } @@ -822,8 +842,8 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */ */ cupsdLogMessage(CUPSD_LOG_ERROR, - "cupsdAuthorize: Username \"%s\" has no shadow " - "password!", username); + "[Client %d] Username \"%s\" has no shadow " + "password.", con->http.fd, username); return; } @@ -837,8 +857,8 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */ */ cupsdLogMessage(CUPSD_LOG_ERROR, - "cupsdAuthorize: Username \"%s\" has no password!", - username); + "[Client %d] Username \"%s\" has no password.", + con->http.fd, username); return; } @@ -850,8 +870,8 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */ pass = cups_crypt(password, pw->pw_passwd); cupsdLogMessage(CUPSD_LOG_DEBUG2, - "cupsdAuthorize: pw_passwd=\"%s\", crypt=\"%s\"", - pw->pw_passwd, pass); + "[Client %d] pw_passwd=\"%s\", crypt=\"%s\"", + con->http.fd, pw->pw_passwd, pass); if (!pass || strcmp(pw->pw_passwd, pass)) { @@ -861,15 +881,14 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */ pass = cups_crypt(password, spw->sp_pwdp); cupsdLogMessage(CUPSD_LOG_DEBUG2, - "cupsdAuthorize: sp_pwdp=\"%s\", crypt=\"%s\"", - spw->sp_pwdp, pass); + "[Client %d] sp_pwdp=\"%s\", crypt=\"%s\"", + con->http.fd, spw->sp_pwdp, pass); if (pass == NULL || strcmp(spw->sp_pwdp, pass)) { cupsdLogMessage(CUPSD_LOG_ERROR, - "cupsdAuthorize: Authentication failed for " - "user \"%s\"!", - username); + "[Client %d] Authentication failed for user " + "\"%s\".", con->http.fd, username); return; } } @@ -877,9 +896,8 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */ # endif /* HAVE_SHADOW_H */ { cupsdLogMessage(CUPSD_LOG_ERROR, - "cupsdAuthorize: Authentication failed for " - "user \"%s\"!", - username); + "[Client %d] Authentication failed for user " + "\"%s\".", con->http.fd, username); return; } } @@ -887,8 +905,8 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */ } cupsdLogMessage(CUPSD_LOG_DEBUG, - "cupsdAuthorize: Authorized as %s using Basic", - username); + "[Client %d] Authorized as %s using Basic", + con->http.fd, username); break; case CUPSD_AUTH_BASICDIGEST : @@ -899,8 +917,8 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */ if (!get_md5_password(username, NULL, md5)) { cupsdLogMessage(CUPSD_LOG_ERROR, - "cupsdAuthorize: Unknown MD5 username \"%s\"!", - username); + "[Client %d] Unknown MD5 username \"%s\".", + con->http.fd, username); return; } @@ -909,14 +927,14 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */ if (strcmp(md5, basicmd5)) { cupsdLogMessage(CUPSD_LOG_ERROR, - "cupsdAuthorize: Authentication failed for \"%s\"!", - username); + "[Client %d] Authentication failed for \"%s\".", + con->http.fd, username); return; } cupsdLogMessage(CUPSD_LOG_DEBUG, - "cupsdAuthorize: Authorized as %s using BasicDigest", - username); + "[Client %d] Authorized as %s using BasicDigest", + con->http.fd, username); break; } @@ -936,7 +954,8 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */ */ cupsdLogMessage(CUPSD_LOG_ERROR, - "cupsdAuthorize: Empty or missing Digest username!"); + "[Client %d] Empty or missing Digest username.", + con->http.fd); return; } @@ -948,7 +967,8 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */ */ cupsdLogMessage(CUPSD_LOG_ERROR, - "cupsdAuthorize: Empty or missing Digest password!"); + "[Client %d] Empty or missing Digest password.", + con->http.fd); return; } @@ -956,16 +976,16 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */ nonce)) { cupsdLogMessage(CUPSD_LOG_ERROR, - "cupsdAuthorize: No nonce value for Digest " - "authentication!"); + "[Client %d] No nonce value for Digest authentication.", + con->http.fd); return; } if (strcmp(con->http.hostname, nonce)) { cupsdLogMessage(CUPSD_LOG_ERROR, - "cupsdAuthorize: Bad nonce value, expected \"%s\", " - "got \"%s\"!", con->http.hostname, nonce); + "[Client %d] Bad nonce value, expected \"%s\", " + "got \"%s\".", con->http.fd, con->http.hostname, nonce); return; } @@ -976,8 +996,8 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */ if (!get_md5_password(username, NULL, md5)) { cupsdLogMessage(CUPSD_LOG_ERROR, - "cupsdAuthorize: Unknown MD5 username \"%s\"!", - username); + "[Client %d] Unknown MD5 username \"%s\".", + con->http.fd, username); return; } @@ -986,13 +1006,13 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */ if (strcmp(md5, password)) { cupsdLogMessage(CUPSD_LOG_ERROR, - "cupsdAuthorize: Authentication failed for \"%s\"!", - username); + "[Client %d] Authentication failed for \"%s\".", + con->http.fd, username); return; } cupsdLogMessage(CUPSD_LOG_DEBUG, - "cupsdAuthorize: Authorized as %s using Digest", + "[Client %d] Authorized as %s using Digest", con->http.fd, username); con->type = CUPSD_AUTH_DIGEST; @@ -1020,8 +1040,9 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */ if (gss_init_sec_context == NULL) { cupsdLogMessage(CUPSD_LOG_WARN, - "GSSAPI/Kerberos authentication failed because the " - "Kerberos framework is not present."); + "[Client %d] GSSAPI/Kerberos authentication failed " + "because the Kerberos framework is not present.", + con->http.fd); return; } # endif /* __APPLE__ */ @@ -1037,7 +1058,8 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */ if (!*authorization) { cupsdLogMessage(CUPSD_LOG_DEBUG2, - "cupsdAuthorize: No authentication data specified."); + "[Client %d] No authentication data specified.", + con->http.fd); return; } @@ -1059,7 +1081,7 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */ client_name = GSS_C_NO_NAME; major_status = gss_accept_sec_context(&minor_status, &context, - GSS_C_NO_CREDENTIAL, + ServerCreds, &input_token, GSS_C_NO_CHANNEL_BINDINGS, &client_name, @@ -1075,8 +1097,8 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */ if (GSS_ERROR(major_status)) { cupsdLogGSSMessage(CUPSD_LOG_DEBUG, major_status, minor_status, - "cupsdAuthorize: Error accepting GSSAPI security " - "context"); + "[Client %d] Error accepting GSSAPI security context", + con->http.fd); if (context != GSS_C_NO_CONTEXT) gss_delete_sec_context(&minor_status, &context, GSS_C_NO_BUFFER); @@ -1091,7 +1113,7 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */ if (major_status == GSS_S_CONTINUE_NEEDED) cupsdLogGSSMessage(CUPSD_LOG_DEBUG, major_status, minor_status, - "cupsdAuthorize: Credentials not complete"); + "[Client %d] Credentials not complete", con->http.fd); else if (major_status == GSS_S_COMPLETE) { major_status = gss_display_name(&minor_status, client_name, @@ -1100,7 +1122,7 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */ if (GSS_ERROR(major_status)) { cupsdLogGSSMessage(CUPSD_LOG_DEBUG, major_status, minor_status, - "cupsdAuthorize: Error getting username"); + "[Client %d] Error getting username", con->http.fd); gss_release_name(&minor_status, &client_name); gss_delete_sec_context(&minor_status, &context, GSS_C_NO_BUFFER); return; @@ -1109,8 +1131,8 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */ strlcpy(username, output_token.value, sizeof(username)); cupsdLogMessage(CUPSD_LOG_DEBUG, - "cupsdAuthorize: Authorized as %s using Negotiate", - username); + "[Client %d] Authorized as %s using Negotiate", + con->http.fd, username); gss_release_name(&minor_status, &client_name); gss_release_buffer(&minor_status, &output_token); @@ -1140,14 +1162,15 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */ &peersize)) # endif /* __APPLE__ */ { - cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to get peer credentials - %s", - strerror(errno)); + cupsdLogMessage(CUPSD_LOG_ERROR, + "[Client %d] Unable to get peer credentials - %s", + con->http.fd, strerror(errno)); } else { cupsdLogMessage(CUPSD_LOG_DEBUG, - "cupsdAuthorize: Using credentials for UID %d...", - CUPSD_UCRED_UID(peercred)); + "[Client %d] Using credentials for UID %d.", + con->http.fd, CUPSD_UCRED_UID(peercred)); con->gss_uid = CUPSD_UCRED_UID(peercred); } } @@ -1162,8 +1185,9 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */ if (sscanf(authorization, "%255s", scheme) != 1) strcpy(scheme, "UNKNOWN"); - cupsdLogMessage(CUPSD_LOG_ERROR, "Bad authentication data \"%s ...\"", - scheme); + cupsdLogMessage(CUPSD_LOG_ERROR, + "[Client %d] Bad authentication data \"%s ...\"", + con->http.fd, scheme); return; } @@ -1843,7 +1867,7 @@ cupsdIsAuthorized(cupsd_client_t *con, /* I - Connection */ best = con->best; if ((type = best->type) == CUPSD_AUTH_DEFAULT) - type = DefaultAuthType; + type = cupsdDefaultAuthType(); cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdIsAuthorized: level=CUPSD_AUTH_%s, type=%s, " @@ -1907,7 +1931,8 @@ cupsdIsAuthorized(cupsd_client_t *con, /* I - Connection */ _cups_strcasecmp(con->http.hostname, "localhost") && best->satisfy == CUPSD_AUTH_SATISFY_ALL) && !(type == CUPSD_AUTH_NEGOTIATE || - (type == CUPSD_AUTH_NONE && DefaultAuthType == CUPSD_AUTH_NEGOTIATE))) + (type == CUPSD_AUTH_NONE && + cupsdDefaultAuthType() == CUPSD_AUTH_NEGOTIATE))) { cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdIsAuthorized: Need upgrade to TLS..."); @@ -2582,5 +2607,5 @@ to64(char *s, /* O - Output string */ /* - * End of "$Id: auth.c 9949 2011-08-31 04:58:33Z mike $". + * End of "$Id: auth.c 11173 2013-07-23 12:31:34Z msweet $". */ diff --git a/scheduler/auth.h b/scheduler/auth.h index f15a6f9..8979023 100644 --- a/scheduler/auth.h +++ b/scheduler/auth.h @@ -1,5 +1,5 @@ /* - * "$Id: auth.h 9652 2011-03-25 21:25:38Z mike $" + * "$Id: auth.h 11173 2013-07-23 12:31:34Z msweet $" * * Authorization definitions for the CUPS scheduler. * @@ -30,6 +30,7 @@ #define CUPSD_AUTH_DIGEST 2 /* Digest authentication */ #define CUPSD_AUTH_BASICDIGEST 3 /* Basic authentication w/passwd.md5 */ #define CUPSD_AUTH_NEGOTIATE 4 /* Kerberos authentication */ +#define CUPSD_AUTH_AUTO 5 /* Kerberos or Basic, depending on configuration of server */ #define CUPSD_AUTH_ANON 0 /* Anonymous access */ #define CUPSD_AUTH_USER 1 /* Must have a valid username/password */ @@ -112,8 +113,6 @@ typedef struct cupsd_client_s cupsd_client_t; VAR cups_array_t *Locations VALUE(NULL); /* Authorization locations */ -VAR int DefaultAuthType VALUE(CUPSD_AUTH_BASIC); - /* Default AuthType, if not specified */ #ifdef HAVE_SSL VAR http_encryption_t DefaultEncryption VALUE(HTTP_ENCRYPT_REQUIRED); /* Default encryption for authentication */ @@ -148,5 +147,5 @@ extern cupsd_location_t *cupsdNewLocation(const char *location); /* - * End of "$Id: auth.h 9652 2011-03-25 21:25:38Z mike $". + * End of "$Id: auth.h 11173 2013-07-23 12:31:34Z msweet $". */ diff --git a/scheduler/banners.c b/scheduler/banners.c index 7a4987f..87a1a68 100644 --- a/scheduler/banners.c +++ b/scheduler/banners.c @@ -1,5 +1,5 @@ /* - * "$Id: banners.c 9793 2011-05-20 03:49:49Z mike $" + * "$Id: banners.c 11173 2013-07-23 12:31:34Z msweet $" * * Banner routines for the CUPS scheduler. * @@ -220,5 +220,5 @@ free_banners(void) /* - * End of "$Id: banners.c 9793 2011-05-20 03:49:49Z mike $". + * End of "$Id: banners.c 11173 2013-07-23 12:31:34Z msweet $". */ diff --git a/scheduler/banners.h b/scheduler/banners.h index 2578cdd..4a91e8a 100644 --- a/scheduler/banners.h +++ b/scheduler/banners.h @@ -1,5 +1,5 @@ /* - * "$Id: banners.h 9350 2010-11-04 23:23:25Z mike $" + * "$Id: banners.h 11173 2013-07-23 12:31:34Z msweet $" * * Banner definitions for the CUPS scheduler. * @@ -41,5 +41,5 @@ extern void cupsdLoadBanners(const char *d); /* - * End of "$Id: banners.h 9350 2010-11-04 23:23:25Z mike $". + * End of "$Id: banners.h 11173 2013-07-23 12:31:34Z msweet $". */ diff --git a/scheduler/cert.c b/scheduler/cert.c index 2e83a8b..cd47228 100644 --- a/scheduler/cert.c +++ b/scheduler/cert.c @@ -1,9 +1,9 @@ /* - * "$Id: cert.c 10262 2012-02-12 05:48:09Z mike $" + * "$Id: cert.c 11173 2013-07-23 12:31:34Z msweet $" * * Authentication certificate routines for the CUPS scheduler. * - * Copyright 2007-2011 by Apple Inc. + * Copyright 2007-2012 by Apple Inc. * Copyright 1997-2006 by Easy Software Products. * * These coded instructions, statements, and computer programs are the @@ -42,7 +42,7 @@ void cupsdAddCert(int pid, /* I - Process ID */ const char *username, /* I - Username */ - void *ccache) /* I - Kerberos credentials or NULL */ + int type) /* I - AuthType for username */ { int i; /* Looping var */ cupsd_cert_t *cert; /* Current certificate */ @@ -66,7 +66,8 @@ cupsdAddCert(int pid, /* I - Process ID */ * Fill in the certificate information... */ - cert->pid = pid; + cert->pid = pid; + cert->type = type; strlcpy(cert->username, username, sizeof(cert->username)); for (i = 0; i < 32; i ++) @@ -260,16 +261,6 @@ cupsdAddCert(int pid, /* I - Process ID */ close(fd); /* - * Add Kerberos credentials as needed... - */ - -#ifdef HAVE_GSSAPI - cert->ccache = (krb5_ccache)ccache; -#else - (void)ccache; -#endif /* HAVE_GSSAPI */ - - /* * Insert the certificate at the front of the list... */ @@ -308,15 +299,6 @@ cupsdDeleteCert(int pid) /* I - Process ID */ else prev->next = cert->next; -#ifdef HAVE_GSSAPI - /* - * Release Kerberos credentials as needed... - */ - - if (cert->ccache) - krb5_cc_destroy(KerberosContext, cert->ccache); -#endif /* HAVE_GSSAPI */ - free(cert); /* @@ -449,10 +431,10 @@ cupsdInitCerts(void) */ if (!RunUser) - cupsdAddCert(0, "root", NULL); + cupsdAddCert(0, "root", cupsdDefaultAuthType()); } /* - * End of "$Id: cert.c 10262 2012-02-12 05:48:09Z mike $". + * End of "$Id: cert.c 11173 2013-07-23 12:31:34Z msweet $". */ diff --git a/scheduler/cert.h b/scheduler/cert.h index e456a1a..26eaa9f 100644 --- a/scheduler/cert.h +++ b/scheduler/cert.h @@ -1,9 +1,9 @@ /* - * "$Id: cert.h 9350 2010-11-04 23:23:25Z mike $" + * "$Id: cert.h 11173 2013-07-23 12:31:34Z msweet $" * * Authentication certificate definitions for the CUPS scheduler. * - * Copyright 2007-2010 by Apple Inc. + * Copyright 2007-2012 by Apple Inc. * Copyright 1997-2005 by Easy Software Products. * * These coded instructions, statements, and computer programs are the @@ -23,9 +23,7 @@ typedef struct cupsd_cert_s int pid; /* Process ID (0 for root certificate) */ char certificate[33]; /* 32 hex characters, or 128 bits */ char username[33]; /* Authenticated username */ -#ifdef HAVE_GSSAPI - krb5_ccache ccache; /* Kerberos credential cache */ -#endif /* HAVE_GSSAPI */ + int type; /* AuthType for username */ } cupsd_cert_t; @@ -43,8 +41,7 @@ VAR time_t RootCertTime /* Root certificate update time */ * Prototypes... */ -extern void cupsdAddCert(int pid, const char *username, - void *ccache); +extern void cupsdAddCert(int pid, const char *username, int type); extern void cupsdDeleteCert(int pid); extern void cupsdDeleteAllCerts(void); extern cupsd_cert_t *cupsdFindCert(const char *certificate); @@ -52,5 +49,5 @@ extern void cupsdInitCerts(void); /* - * End of "$Id: cert.h 9350 2010-11-04 23:23:25Z mike $". + * End of "$Id: cert.h 11173 2013-07-23 12:31:34Z msweet $". */ diff --git a/scheduler/classes.c b/scheduler/classes.c index c001bc4..1aed92c 100644 --- a/scheduler/classes.c +++ b/scheduler/classes.c @@ -1,5 +1,5 @@ /* - * "$Id: classes.c 9793 2011-05-20 03:49:49Z mike $" + * "$Id: classes.c 11173 2013-07-23 12:31:34Z msweet $" * * Printer class routines for the CUPS scheduler. * @@ -22,8 +22,6 @@ * cupsdFindClass() - Find the named class. * cupsdLoadAllClasses() - Load classes from the classes.conf file. * cupsdSaveAllClasses() - Save classes to the classes.conf file. - * cupsdUpdateImplicitClasses() - Update the accepting state of implicit - * classes. */ /* @@ -184,24 +182,9 @@ cupsdDeletePrinterFromClasses( for (c = (cupsd_printer_t *)cupsArrayFirst(Printers); c; c = (cupsd_printer_t *)cupsArrayNext(Printers)) - if (c->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT)) + if (c->type & CUPS_PRINTER_CLASS) changed |= cupsdDeletePrinterFromClass(c, p); - /* - * Then clean out any empty implicit classes... - */ - - for (c = (cupsd_printer_t *)cupsArrayFirst(ImplicitPrinters); - c; - c = (cupsd_printer_t *)cupsArrayNext(ImplicitPrinters)) - if (c->num_printers == 0) - { - cupsdLogMessage(CUPSD_LOG_DEBUG, "Deleting implicit class \"%s\"...", - c->name); - cupsdDeletePrinter(c, 0); - changed = 1; - } - return (changed); } @@ -279,8 +262,7 @@ cupsdFindClass(const char *name) /* I - Name of class */ cupsd_printer_t *c; /* Current class/printer */ - if ((c = cupsdFindDest(name)) != NULL && - (c->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT))) + if ((c = cupsdFindDest(name)) != NULL && (c->type & CUPS_PRINTER_CLASS)) return (c); else return (NULL); @@ -443,9 +425,8 @@ cupsdLoadAllClasses(void) { cupsdSetString(&temp->make_model, "Remote Printer on unknown"); - temp->state = IPP_PRINTER_STOPPED; - temp->type |= CUPS_PRINTER_REMOTE; - temp->browse_time = 2147483647; + temp->state = IPP_PRINTER_STOPPED; + temp->type |= CUPS_PRINTER_REMOTE; cupsdSetString(&temp->location, "Location Unknown"); cupsdSetString(&temp->info, "No Information Available"); @@ -733,7 +714,6 @@ cupsdSaveAllClasses(void) */ if ((pclass->type & CUPS_PRINTER_REMOTE) || - (pclass->type & CUPS_PRINTER_IMPLICIT) || !(pclass->type & CUPS_PRINTER_CLASS)) continue; @@ -834,35 +814,5 @@ cupsdSaveAllClasses(void) /* - * 'cupsdUpdateImplicitClasses()' - Update the accepting state of implicit - * classes. - */ - -void -cupsdUpdateImplicitClasses(void) -{ - int i; /* Looping var */ - cupsd_printer_t *pclass; /* Current class */ - int accepting; /* printer-is-accepting-jobs value */ - - - for (pclass = (cupsd_printer_t *)cupsArrayFirst(ImplicitPrinters); - pclass; - pclass = (cupsd_printer_t *)cupsArrayNext(ImplicitPrinters)) - { - /* - * Loop through the printers to come up with a composite state... - */ - - for (i = 0, accepting = 0; i < pclass->num_printers; i ++) - if ((accepting = pclass->printers[i]->accepting) != 0) - break; - - pclass->accepting = accepting; - } -} - - -/* - * End of "$Id: classes.c 9793 2011-05-20 03:49:49Z mike $". + * End of "$Id: classes.c 11173 2013-07-23 12:31:34Z msweet $". */ diff --git a/scheduler/classes.h b/scheduler/classes.h index 05c0878..6d94de2 100644 --- a/scheduler/classes.h +++ b/scheduler/classes.h @@ -1,9 +1,9 @@ /* - * "$Id: classes.h 9350 2010-11-04 23:23:25Z mike $" + * "$Id: classes.h 11173 2013-07-23 12:31:34Z msweet $" * * Printer class definitions for the CUPS scheduler. * - * Copyright 2007-2010 by Apple Inc. + * Copyright 2007-2011 by Apple Inc. * Copyright 1997-2005 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -28,9 +28,8 @@ extern cupsd_printer_t *cupsdFindAvailablePrinter(const char *name); extern cupsd_printer_t *cupsdFindClass(const char *name); extern void cupsdLoadAllClasses(void); extern void cupsdSaveAllClasses(void); -extern void cupsdUpdateImplicitClasses(void); /* - * End of "$Id: classes.h 9350 2010-11-04 23:23:25Z mike $". + * End of "$Id: classes.h 11173 2013-07-23 12:31:34Z msweet $". */ diff --git a/scheduler/client.c b/scheduler/client.c index e40ed27..b341e9d 100644 --- a/scheduler/client.c +++ b/scheduler/client.c @@ -1,9 +1,9 @@ /* - * "$Id: client.c 10338 2012-03-07 06:05:39Z mike $" + * "$Id: client.c 11173 2013-07-23 12:31:34Z msweet $" * * Client routines for the CUPS scheduler. * - * Copyright 2007-2011 by Apple Inc. + * Copyright 2007-2012 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * This file contains Kerberos support code, copyright 2006 by @@ -17,34 +17,30 @@ * * Contents: * - * cupsdAcceptClient() - Accept a new client. - * cupsdCloseAllClients() - Close all remote clients immediately. - * cupsdCloseClient() - Close a remote client. - * cupsdFlushHeader() - Flush the header fields to the client. - * cupsdReadClient() - Read data from a client. - * cupsdSendCommand() - Send output from a command via HTTP. - * cupsdSendError() - Send an error message via HTTP. - * cupsdSendHeader() - Send an HTTP request. - * cupsdUpdateCGI() - Read status messages from CGI scripts and - * programs. - * cupsdWriteClient() - Write data to a client as needed. - * check_if_modified() - Decode an "If-Modified-Since" line. - * compare_clients() - Compare two client connections. - * copy_cdsa_certificate() - Copy a SSL/TLS certificate from the System - * keychain. - * data_ready() - Check whether data is available from a client. - * encrypt_client() - Enable encryption for the client... - * get_file() - Get a filename and state info. - * install_conf_file() - Install a configuration file. - * is_cgi() - Is the resource a CGI script/program? - * is_path_absolute() - Is a path absolute and free of relative elements - * (i.e. ".."). - * make_certificate() - Make a self-signed SSL/TLS certificate. - * pipe_command() - Pipe the output of a command to the remote - * client. - * valid_host() - Is the Host: field valid? - * write_file() - Send a file via HTTP. - * write_pipe() - Flag that data is available on the CGI pipe. + * cupsdAcceptClient() - Accept a new client. + * cupsdCloseAllClients() - Close all remote clients immediately. + * cupsdCloseClient() - Close a remote client. + * cupsdFlushHeader() - Flush the header fields to the client. + * cupsdReadClient() - Read data from a client. + * cupsdSendCommand() - Send output from a command via HTTP. + * cupsdSendError() - Send an error message via HTTP. + * cupsdSendHeader() - Send an HTTP request. + * cupsdUpdateCGI() - Read status messages from CGI scripts and + * programs. + * cupsdWriteClient() - Write data to a client as needed. + * check_if_modified() - Decode an "If-Modified-Since" line. + * compare_clients() - Compare two client connections. + * data_ready() - Check whether data is available from a client. + * get_file() - Get a filename and state info. + * install_cupsd_conf() - Install a configuration file. + * is_cgi() - Is the resource a CGI script/program? + * is_path_absolute() - Is a path absolute and free of relative elements + * (i.e. ".."). + * pipe_command() - Pipe the output of a command to the remote + * client. + * valid_host() - Is the Host: field valid? + * write_file() - Send a file via HTTP. + * write_pipe() - Flag that data is available on the CGI pipe. */ /* @@ -59,6 +55,36 @@ /* + * Local globals... + */ + +static const char * const http_states[] = + { /* HTTP state strings */ + "HTTP_WAITING", + "HTTP_OPTIONS", + "HTTP_GET", + "HTTP_GET_SEND", + "HTTP_HEAD", + "HTTP_POST", + "HTTP_POST_RECV", + "HTTP_POST_SEND", + "HTTP_PUT", + "HTTP_PUT_RECV", + "HTTP_DELETE", + "HTTP_TRACE", + "HTTP_CLOSE", + "HTTP_STATUS" + }; +static const char * const ipp_states[] = + { /* IPP state strings */ + "IPP_IDLE", + "IPP_HEADER", + "IPP_ATTRIBUTE", + "IPP_DATA" + }; + + +/* * Local functions... */ @@ -66,22 +92,13 @@ static int check_if_modified(cupsd_client_t *con, struct stat *filestats); static int compare_clients(cupsd_client_t *a, cupsd_client_t *b, void *data); -#ifdef HAVE_CDSASSL -static CFArrayRef copy_cdsa_certificate(cupsd_client_t *con); -#endif /* HAVE_CDSASSL */ static int data_ready(cupsd_client_t *con); -#ifdef HAVE_SSL -static int encrypt_client(cupsd_client_t *con); -#endif /* HAVE_SSL */ static char *get_file(cupsd_client_t *con, struct stat *filestats, char *filename, int len); -static http_status_t install_conf_file(cupsd_client_t *con); +static http_status_t install_cupsd_conf(cupsd_client_t *con); static int is_cgi(cupsd_client_t *con, const char *filename, struct stat *filestats, mime_type_t *type); static int is_path_absolute(const char *path); -#ifdef HAVE_SSL -static int make_certificate(cupsd_client_t *con); -#endif /* HAVE_SSL */ static int pipe_command(cupsd_client_t *con, int infile, int *outfile, char *command, char *options, int root); static int valid_host(cupsd_client_t *con); @@ -157,8 +174,8 @@ cupsdAcceptClient(cupsd_listener_t *lis)/* I - Listener socket */ return; } - con->http.activity = time(NULL); con->file = -1; + con->http.activity = time(NULL); con->http.hostaddr = &(con->clientaddr); con->http.wait_value = 10000; @@ -356,11 +373,11 @@ cupsdAcceptClient(cupsd_listener_t *lis)/* I - Listener socket */ #ifdef AF_LOCAL if (con->http.hostaddr->addr.sa_family == AF_LOCAL) - cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdAcceptClient: %d from %s (Domain)", + cupsdLogMessage(CUPSD_LOG_DEBUG, "[Client %d] Accepted from %s (Domain)", con->http.fd, con->http.hostname); else #endif /* AF_LOCAL */ - cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdAcceptClient: %d from %s:%d (IPv%d)", + cupsdLogMessage(CUPSD_LOG_DEBUG, "[Client %d] Accepted from %s:%d (IPv%d)", con->http.fd, con->http.hostname, _httpAddrPort(con->http.hostaddr), _httpAddrFamily(con->http.hostaddr) == AF_INET ? 4 : 6); @@ -389,7 +406,7 @@ cupsdAcceptClient(cupsd_listener_t *lis)/* I - Listener socket */ { if (httpAddrLocalhost(&temp)) strlcpy(con->servername, "localhost", sizeof(con->servername)); - else if (HostNameLookups || RemotePort) + else if (HostNameLookups) httpAddrLookup(&temp, con->servername, sizeof(con->servername)); else httpAddrString(&temp, con->servername, sizeof(con->servername)); @@ -397,6 +414,10 @@ cupsdAcceptClient(cupsd_listener_t *lis)/* I - Listener socket */ con->serverport = _httpAddrPort(&(lis->address)); } + /* + * Add the connection to the array of active clients... + */ + cupsArrayAdd(Clients, con); /* @@ -440,7 +461,7 @@ cupsdAcceptClient(cupsd_listener_t *lis)/* I - Listener socket */ con->http.encryption = HTTP_ENCRYPT_ALWAYS; - if (!encrypt_client(con)) + if (!cupsdStartTLS(con)) cupsdCloseClient(con); } else @@ -479,17 +500,13 @@ cupsdCloseClient(cupsd_client_t *con) /* I - Client to close */ { int partial; /* Do partial close for SSL? */ #ifdef HAVE_LIBSSL - SSL_CTX *context; /* Context for encryption */ - unsigned long error; /* Error code */ #elif defined(HAVE_GNUTLS) - int error; /* Error code */ - gnutls_certificate_server_credentials *credentials; - /* TLS credentials */ # elif defined(HAVE_CDSASSL) #endif /* HAVE_LIBSSL */ - cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdCloseClient: %d", con->http.fd); + cupsdLogMessage(CUPSD_LOG_DEBUG, "[Client %d] Closing connection.", + con->http.fd); /* * Flush pending writes before closing... @@ -508,60 +525,7 @@ cupsdCloseClient(cupsd_client_t *con) /* I - Client to close */ { partial = 1; -# ifdef HAVE_LIBSSL - context = SSL_get_SSL_CTX(con->http.tls); - - switch (SSL_shutdown(con->http.tls)) - { - case 1 : - cupsdLogMessage(CUPSD_LOG_DEBUG, - "SSL shutdown successful!"); - break; - case -1 : - cupsdLogMessage(CUPSD_LOG_ERROR, - "Fatal error during SSL shutdown!"); - default : - while ((error = ERR_get_error()) != 0) - cupsdLogMessage(CUPSD_LOG_ERROR, "SSL shutdown failed: %s", - ERR_error_string(error, NULL)); - break; - } - - SSL_CTX_free(context); - SSL_free(con->http.tls); - -# elif defined(HAVE_GNUTLS) - credentials = (gnutls_certificate_server_credentials *)(con->http.tls_credentials); - - error = gnutls_bye(con->http.tls, GNUTLS_SHUT_WR); - switch (error) - { - case GNUTLS_E_SUCCESS: - cupsdLogMessage(CUPSD_LOG_DEBUG, - "SSL shutdown successful!"); - break; - default: - cupsdLogMessage(CUPSD_LOG_ERROR, - "SSL shutdown failed: %s", gnutls_strerror(error)); - break; - } - - gnutls_deinit(con->http.tls); - gnutls_certificate_free_credentials(*credentials); - free(credentials); - -# elif defined(HAVE_CDSASSL) - while (SSLClose(con->http.tls) == errSSLWouldBlock) - usleep(1000); - - SSLDisposeContext(con->http.tls); - - if (con->http.tls_credentials) - CFRelease(con->http.tls_credentials); - -# endif /* HAVE_LIBSSL */ - - con->http.tls = NULL; + cupsdEndTLS(con); } #endif /* HAVE_SSL */ @@ -719,18 +683,22 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ status = HTTP_CONTINUE; cupsdLogMessage(CUPSD_LOG_DEBUG2, - "cupsdReadClient(con=%p(%d)) " - "con->http.error=%d " - "con->http.used=%d, " - "con->http.state=%d " - "con->data_encoding=HTTP_ENCODE_%s, " - "con->data_remaining=" CUPS_LLFMT ", " - "con->file=%d", - con, con->http.fd, con->http.error, con->http.used, - con->http.state, + "[Client %d] cupsdReadClient " + "error=%d, " + "used=%d, " + "state=%s, " + "data_encoding=HTTP_ENCODE_%s, " + "data_remaining=" CUPS_LLFMT ", " + "request=%p(%s), " + "file=%d", + con->http.fd, con->http.error, con->http.used, + http_states[con->http.state], con->http.data_encoding == HTTP_ENCODE_CHUNKED ? "CHUNKED" : "LENGTH", - CUPS_LLCAST con->http.data_remaining, con->file); + CUPS_LLCAST con->http.data_remaining, + con->request, + con->request ? ipp_states[con->request->state] : "", + con->file); #ifdef HAVE_SSL if (con->auto_ssl) @@ -749,10 +717,10 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ */ cupsdLogMessage(CUPSD_LOG_DEBUG2, - "cupsdReadClient: Saw first byte %02X, auto-negotiating " - "SSL/TLS session...", buf[0] & 255); + "[Client %d] Saw first byte %02X, auto-negotiating " + "SSL/TLS session.", con->http.fd, buf[0] & 255); - if (!encrypt_client(con)) + if (!cupsdStartTLS(con)) cupsdCloseClient(con); return; @@ -771,12 +739,12 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ { if (con->http.error && con->http.error != EPIPE) cupsdLogMessage(CUPSD_LOG_DEBUG, - "cupsdReadClient: %d WAITING Closing for error %d " + "[Client %d] HTTP_WAITING Closing for error %d " "(%s)", con->http.fd, con->http.error, strerror(con->http.error)); else cupsdLogMessage(CUPSD_LOG_DEBUG, - "cupsdReadClient: %d WAITING Closing on EOF", + "[Client %d] HTTP_WAITING Closing on EOF", con->http.fd); cupsdCloseClient(con); @@ -848,7 +816,8 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ if (line[0]) { cupsdLogMessage(CUPSD_LOG_ERROR, - "Bad request line \"%s\" from %s!", + "[Client %d] Bad request line \"%s\" from %s.", + con->http.fd, _httpEncodeURI(buf, line, sizeof(buf)), con->http.hostname); cupsdSendError(con, HTTP_BAD_REQUEST, CUPSD_AUTH_NONE); @@ -862,7 +831,8 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ if (sscanf(version, "HTTP/%d.%d", &major, &minor) != 2) { cupsdLogMessage(CUPSD_LOG_ERROR, - "Bad request line \"%s\" from %s!", + "[Client %d] Bad request line \"%s\" from %s.", + con->http.fd, _httpEncodeURI(buf, line, sizeof(buf)), con->http.hostname); cupsdSendError(con, HTTP_BAD_REQUEST, CUPSD_AUTH_NONE); @@ -881,7 +851,8 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ else { cupsdLogMessage(CUPSD_LOG_ERROR, - "Unsupported request line \"%s\" from %s!", + "[Client %d] Unsupported request line \"%s\" " + "from %s.", con->http.fd, _httpEncodeURI(buf, line, sizeof(buf)), con->http.hostname); cupsdSendError(con, HTTP_NOT_SUPPORTED, CUPSD_AUTH_NONE); @@ -928,8 +899,9 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ * Nope, we don't do proxies... */ - cupsdLogMessage(CUPSD_LOG_ERROR, "Bad URI \"%s\" in request!", - con->uri); + cupsdLogMessage(CUPSD_LOG_ERROR, + "[Client %d] Bad URI \"%s\" in request.", + con->http.fd, con->uri); cupsdSendError(con, HTTP_METHOD_NOT_ALLOWED, CUPSD_AUTH_NONE); cupsdCloseClient(con); return; @@ -963,7 +935,9 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ con->http.state = HTTP_HEAD; else { - cupsdLogMessage(CUPSD_LOG_ERROR, "Bad operation \"%s\"!", operation); + cupsdLogMessage(CUPSD_LOG_ERROR, + "[Client %d] Bad operation \"%s\".", con->http.fd, + operation); cupsdSendError(con, HTTP_BAD_REQUEST, CUPSD_AUTH_NONE); cupsdCloseClient(con); return; @@ -972,7 +946,7 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ gettimeofday(&(con->start), NULL); con->operation = con->http.state; - cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdReadClient: %d %s %s HTTP/%d.%d", + cupsdLogMessage(CUPSD_LOG_DEBUG, "[Client %d] %s %s HTTP/%d.%d", con->http.fd, operation, con->uri, con->http.version / 100, con->http.version % 100); @@ -1003,13 +977,14 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ { if (con->http.error && con->http.error != EPIPE) cupsdLogMessage(CUPSD_LOG_DEBUG, - "cupsdReadClient: %d FIELDS Closing for error %d " - "(%s)", con->http.fd, con->http.error, + "[Client %d] Closing for error %d (%s) while " + "reading headers.", + con->http.fd, con->http.error, strerror(con->http.error)); else cupsdLogMessage(CUPSD_LOG_DEBUG, - "cupsdReadClient: %d FIELDS Closing on EOF", - con->http.fd); + "[Client %d] Closing on EOF while reading headers.", + con->http.fd); cupsdSendError(con, HTTP_BAD_REQUEST, CUPSD_AUTH_NONE); cupsdCloseClient(con); @@ -1025,7 +1000,7 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ */ cupsdLogMessage(CUPSD_LOG_DEBUG, - "cupsdReadClient: %d Closing on EOF", con->http.fd); + "[Client %d] Closing on EOF", con->http.fd); cupsdCloseClient(con); return; } @@ -1078,10 +1053,11 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ cupsdAuthorize(con); - if (!_cups_strncasecmp(con->http.fields[HTTP_FIELD_CONNECTION], "Keep-Alive", - 10) && KeepAlive) + if (!_cups_strncasecmp(con->http.fields[HTTP_FIELD_CONNECTION], + "Keep-Alive", 10) && KeepAlive) con->http.keep_alive = HTTP_KEEPALIVE_ON; - else if (!_cups_strncasecmp(con->http.fields[HTTP_FIELD_CONNECTION], "close", 5)) + else if (!_cups_strncasecmp(con->http.fields[HTTP_FIELD_CONNECTION], + "close", 5)) con->http.keep_alive = HTTP_KEEPALIVE_OFF; if (!con->http.fields[HTTP_FIELD_HOST][0] && @@ -1093,7 +1069,9 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ if (!cupsdSendError(con, HTTP_BAD_REQUEST, CUPSD_AUTH_NONE)) { - cupsdLogMessage(CUPSD_LOG_ERROR, "Missing Host: field in request!"); + cupsdLogMessage(CUPSD_LOG_ERROR, + "[Client %d] Missing Host: field in request.", + con->http.fd); cupsdCloseClient(con); return; } @@ -1106,8 +1084,9 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ */ cupsdLogMessage(CUPSD_LOG_ERROR, - "Request from \"%s\" using invalid Host: field \"%s\"", - con->http.hostname, con->http.fields[HTTP_FIELD_HOST]); + "[Client %d] Request from \"%s\" using invalid Host: " + "field \"%s\"", con->http.fd, con->http.hostname, + con->http.fields[HTTP_FIELD_HOST]); if (!cupsdSendError(con, HTTP_BAD_REQUEST, CUPSD_AUTH_NONE)) { @@ -1155,7 +1134,7 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ return; } - if (!encrypt_client(con)) + if (!cupsdStartTLS(con)) { cupsdCloseClient(con); return; @@ -1192,7 +1171,8 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ */ cupsdLogMessage(CUPSD_LOG_ERROR, - "Request for non-absolute resource \"%s\"!", con->uri); + "[Client %d] Request for non-absolute resource \"%s\".", + con->http.fd, con->uri); if (!cupsdSendError(con, HTTP_FORBIDDEN, CUPSD_AUTH_NONE)) { @@ -1202,15 +1182,16 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ } else { - if (!_cups_strcasecmp(con->http.fields[HTTP_FIELD_CONNECTION], "Upgrade") && - con->http.tls == NULL) + if (!_cups_strcasecmp(con->http.fields[HTTP_FIELD_CONNECTION], + "Upgrade") && con->http.tls == NULL) { #ifdef HAVE_SSL /* * Do encryption stuff... */ - if (!cupsdSendHeader(con, HTTP_SWITCHING_PROTOCOLS, NULL, CUPSD_AUTH_NONE)) + if (!cupsdSendHeader(con, HTTP_SWITCHING_PROTOCOLS, NULL, + CUPSD_AUTH_NONE)) { cupsdCloseClient(con); return; @@ -1227,7 +1208,7 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ return; } - if (!encrypt_client(con)) + if (!cupsdStartTLS(con)) { cupsdCloseClient(con); return; @@ -1290,7 +1271,8 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ switch (con->http.state) { case HTTP_GET_SEND : - if (!strncmp(con->uri, "/printers/", 10) && + if ((!strncmp(con->uri, "/ppd/", 5) || + !strncmp(con->uri, "/printers/", 10)) && !strcmp(con->uri + strlen(con->uri) - 4, ".ppd")) { /* @@ -1300,8 +1282,15 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ con->uri[strlen(con->uri) - 4] = '\0'; /* Drop ".ppd" */ - if ((p = cupsdFindPrinter(con->uri + 10)) != NULL) + if (!strncmp(con->uri, "/ppd/", 5)) + p = cupsdFindPrinter(con->uri + 5); + else + p = cupsdFindPrinter(con->uri + 10); + + if (p) + { snprintf(con->uri, sizeof(con->uri), "/ppd/%s.ppd", p->name); + } else { if (!cupsdSendError(con, HTTP_NOT_FOUND, CUPSD_AUTH_NONE)) @@ -1313,7 +1302,8 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ break; } } - else if ((!strncmp(con->uri, "/printers/", 10) || + else if ((!strncmp(con->uri, "/icons/", 7) || + !strncmp(con->uri, "/printers/", 10) || !strncmp(con->uri, "/classes/", 9)) && !strcmp(con->uri + strlen(con->uri) - 4, ".png")) { @@ -1324,7 +1314,9 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ con->uri[strlen(con->uri) - 4] = '\0'; /* Drop ".png" */ - if (!strncmp(con->uri, "/printers/", 10)) + if (!strncmp(con->uri, "/icons/", 7)) + p = cupsdFindPrinter(con->uri + 7); + else if (!strncmp(con->uri, "/printers/", 10)) p = cupsdFindPrinter(con->uri + 10); else p = cupsdFindClass(con->uri + 9); @@ -1685,17 +1677,15 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ * Validate the resource name... */ - if (strncmp(con->uri, "/admin/conf/", 12) || - strchr(con->uri + 12, '/') || - strlen(con->uri) == 12) + if (strcmp(con->uri, "/admin/conf/cupsd.conf")) { /* - * PUT can only be done to configuration files under - * /admin/conf... + * PUT can only be done to the cupsd.conf file... */ cupsdLogMessage(CUPSD_LOG_ERROR, - "Request for subdirectory \"%s\"!", con->uri); + "[Client %d] Disallowed PUT request for \"%s\".", + con->http.fd, con->uri); if (!cupsdSendError(con, HTTP_FORBIDDEN, CUPSD_AUTH_NONE)) { @@ -1753,8 +1743,9 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ if (con->file < 0) { cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to create request file %s: %s", - con->filename, strerror(errno)); + "[Client %d] Unable to create request file " + "\"%s\": %s", con->http.fd, con->filename, + strerror(errno)); if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE, CUPSD_AUTH_NONE)) { @@ -1890,7 +1881,8 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ */ cupsdLogMessage(CUPSD_LOG_ERROR, - "Request for subdirectory \"%s\"!", con->uri); + "[Client %d] Request for subdirectory \"%s\".", + con->http.fd, con->uri); if (!cupsdSendError(con, HTTP_FORBIDDEN, CUPSD_AUTH_NONE)) { @@ -1991,12 +1983,12 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ { if (con->http.error && con->http.error != EPIPE) cupsdLogMessage(CUPSD_LOG_DEBUG, - "cupsdReadClient: %d PUT_RECV Closing for error " + "[Client %d] HTTP_PUT_RECV Closing for error " "%d (%s)", con->http.fd, con->http.error, strerror(con->http.error)); else cupsdLogMessage(CUPSD_LOG_DEBUG, - "cupsdReadClient: %d PUT_RECV Closing on EOF", + "[Client %d] HTTP_PUT_RECV Closing on EOF", con->http.fd); cupsdCloseClient(con); @@ -2009,8 +2001,9 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ if (write(con->file, line, bytes) < bytes) { cupsdLogMessage(CUPSD_LOG_ERROR, - "cupsdReadClient: Unable to write %d bytes to %s: %s", - bytes, con->filename, strerror(errno)); + "[Client %d] Unable to write %d bytes to " + "\"%s\": %s", con->http.fd, bytes, con->filename, + strerror(errno)); close(con->file); con->file = -1; @@ -2059,7 +2052,7 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ * Install the configuration file... */ - status = install_conf_file(con); + status = install_cupsd_conf(con); /* * Return the status to the client... @@ -2085,8 +2078,8 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ if ((ipp_state = ippRead(&(con->http), con->request)) == IPP_ERROR) { cupsdLogMessage(CUPSD_LOG_ERROR, - "cupsdReadClient: %d IPP Read Error!", - con->http.fd); + "[Client %d] IPP read error: %s", con->http.fd, + cupsLastErrorString()); cupsdSendError(con, HTTP_BAD_REQUEST, CUPSD_AUTH_NONE); cupsdCloseClient(con); @@ -2105,7 +2098,7 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ } else { - cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdReadClient: %d %d.%d %s %d", + cupsdLogMessage(CUPSD_LOG_DEBUG, "[Client %d] %d.%d %s %d", con->http.fd, con->request->request.op.version[0], con->request->request.op.version[1], ippOpString(con->request->request.op.operation_id), @@ -2127,8 +2120,9 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ if (con->file < 0) { cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to create request file %s: %s", - con->filename, strerror(errno)); + "[Client %d] Unable to create request file " + "\"%s\": %s", con->http.fd, con->filename, + strerror(errno)); if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE, CUPSD_AUTH_NONE)) { @@ -2148,12 +2142,12 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ { if (con->http.error && con->http.error != EPIPE) cupsdLogMessage(CUPSD_LOG_DEBUG, - "cupsdReadClient: %d POST_SEND Closing for " + "[Client %d] HTTP_POST_SEND Closing for " "error %d (%s)", con->http.fd, con->http.error, strerror(con->http.error)); else cupsdLogMessage(CUPSD_LOG_DEBUG, - "cupsdReadClient: %d POST_SEND Closing on EOF", + "[Client %d] HTTP_POST_SEND Closing on EOF", con->http.fd); cupsdCloseClient(con); @@ -2166,9 +2160,9 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ if (write(con->file, line, bytes) < bytes) { cupsdLogMessage(CUPSD_LOG_ERROR, - "cupsdReadClient: Unable to write %d bytes to " - "%s: %s", bytes, con->filename, - strerror(errno)); + "[Client %d] Unable to write %d bytes to " + "\"%s\": %s", con->http.fd, bytes, + con->filename, strerror(errno)); close(con->file); con->file = -1; @@ -2188,8 +2182,8 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ else if (con->http.state != HTTP_POST_SEND) { cupsdLogMessage(CUPSD_LOG_DEBUG, - "cupsdReadClient: %d Closing on unknown HTTP " - "state %d", con->http.fd, con->http.state); + "[Client %d] Closing on unexpected state %s.", + con->http.fd, http_states[con->http.state]); cupsdCloseClient(con); return; } @@ -2281,7 +2275,7 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ if (!con->http.keep_alive) { cupsdLogMessage(CUPSD_LOG_DEBUG, - "cupsdReadClient: %d Closing because Keep-Alive disabled", + "[Client %d] Closing because Keep-Alive disabled", con->http.fd); cupsdCloseClient(con); } @@ -2315,7 +2309,7 @@ cupsdSendCommand( if (fd < 0) { cupsdLogMessage(CUPSD_LOG_ERROR, - "cupsdSendCommand: %d Unable to open \"%s\" for reading: %s", + "[Client %d] Unable to open \"%s\" for reading: %s", con->http.fd, con->filename ? con->filename : "/dev/null", strerror(errno)); return (0); @@ -2331,11 +2325,11 @@ cupsdSendCommand( if (fd >= 0) close(fd); - cupsdLogMessage(CUPSD_LOG_INFO, "Started \"%s\" (pid=%d)", command, - con->pipe_pid); + cupsdLogMessage(CUPSD_LOG_INFO, "[Client %d] Started \"%s\" (pid=%d)", + con->http.fd, command, con->pipe_pid); - cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdSendCommand: %d file=%d", - con->http.fd, con->file); + cupsdLogMessage(CUPSD_LOG_DEBUG, "[Client %d] file=%d", con->http.fd, + con->file); if (con->pipe_pid == 0) return (0); @@ -2363,7 +2357,7 @@ cupsdSendError(cupsd_client_t *con, /* I - Connection */ int auth_type)/* I - Authentication type */ { cupsdLogMessage(CUPSD_LOG_DEBUG2, - "cupsdSendError(con=%p(%d), code=%d, auth_type=%d", con, + "[Client %d] cupsdSendError code=%d, auth_type=%d", con->http.fd, code, auth_type); #ifdef HAVE_SSL @@ -2519,10 +2513,6 @@ cupsdSendHeader( int auth_type) /* I - Type of authentication */ { char auth_str[1024]; /* Authorization string */ -#if 0 /* def HAVE_GSSAPI */ - static char *gss_buf = NULL; /* Kerberos auth data buffer */ - static int gss_bufsize = 0; /* Size of Kerberos auth data buffer */ -#endif /* HAVE_GSSAPI */ /* @@ -2577,7 +2567,7 @@ cupsdSendHeader( if (auth_type == CUPSD_AUTH_NONE) { if (!con->best || con->best->type <= CUPSD_AUTH_NONE) - auth_type = DefaultAuthType; + auth_type = cupsdDefaultAuthType(); else auth_type = con->best->type; } @@ -2609,7 +2599,7 @@ cupsdSendHeader( * requests when the request requires system group membership - then the * client knows the root certificate can/should be used. * - * Also, for Mac OS X we also look for @AUTHKEY and add an "authkey" + * Also, for OS X we also look for @AUTHKEY and add an "authkey" * parameter as needed... */ @@ -2652,7 +2642,7 @@ cupsdSendHeader( if (auth_str[0]) { cupsdLogMessage(CUPSD_LOG_DEBUG, - "cupsdSendHeader: %d WWW-Authenticate: %s", con->http.fd, + "[Client %d] WWW-Authenticate: %s", con->http.fd, auth_str); if (httpPrintf(HTTP(con), "WWW-Authenticate: %s\r\n", auth_str) < 0) @@ -2733,11 +2723,23 @@ cupsdWriteClient(cupsd_client_t *con) /* I - Client connection */ cupsdLogMessage(CUPSD_LOG_DEBUG2, - "cupsdWriteClient(con=%p(%d)) response=%p(%d), file=%d " - "pipe_pid=%d state=%d", - con, con->http.fd, con->response, - con->response ? con->response->state : -1, - con->file, con->pipe_pid, con->http.state); + "[Client %d] cupsdWriteClient " + "error=%d, " + "used=%d, " + "state=%s, " + "data_encoding=HTTP_ENCODE_%s, " + "data_remaining=" CUPS_LLFMT ", " + "response=%p(%s), " + "pipe_pid=%d, " + "file=%d", + con->http.fd, con->http.error, con->http.used, + http_states[con->http.state], + con->http.data_encoding == HTTP_ENCODE_CHUNKED ? + "CHUNKED" : "LENGTH", + CUPS_LLCAST con->http.data_remaining, + con->response, + con->response ? ipp_states[con->response->state] : "", + con->pipe_pid, con->file); if (con->http.state != HTTP_GET_SEND && con->http.state != HTTP_POST_SEND) @@ -2748,8 +2750,8 @@ cupsdWriteClient(cupsd_client_t *con) /* I - Client connection */ */ cupsdLogMessage(CUPSD_LOG_DEBUG, - "cupsdWriteClient: %d Closing on unknown HTTP state %d", - con->http.fd, con->http.state); + "[Client %d] Closing on unexpected HTTP state %s.", + con->http.fd, http_states[con->http.state]); cupsdCloseClient(con); return; } @@ -2902,7 +2904,7 @@ cupsdWriteClient(cupsd_client_t *con) /* I - Client connection */ if (httpWrite2(HTTP(con), con->header, con->header_used) < 0) { cupsdLogMessage(CUPSD_LOG_DEBUG, - "cupsdWriteClient: %d Closing for error %d (%s)", + "[Client %d] Closing for error %d (%s)", con->http.fd, con->http.error, strerror(con->http.error)); cupsdCloseClient(con); @@ -2939,7 +2941,7 @@ cupsdWriteClient(cupsd_client_t *con) /* I - Client connection */ if (httpWrite2(HTTP(con), "", 0) < 0) { cupsdLogMessage(CUPSD_LOG_DEBUG, - "cupsdWriteClient: %d Closing for error %d (%s)", + "[Client %d] Closing for error %d (%s)", con->http.fd, con->http.error, strerror(con->http.error)); cupsdCloseClient(con); @@ -2989,7 +2991,7 @@ cupsdWriteClient(cupsd_client_t *con) /* I - Client connection */ if (!con->http.keep_alive) { cupsdLogMessage(CUPSD_LOG_DEBUG, - "cupsdWriteClient: %d Closing because Keep-Alive disabled", + "[Client %d] Closing because Keep-Alive disabled.", con->http.fd); cupsdCloseClient(con); return; @@ -3027,9 +3029,9 @@ check_if_modified( return (1); cupsdLogMessage(CUPSD_LOG_DEBUG2, - "check_if_modified(con=%p(%d), " + "[Client %d] check_if_modified " "filestats=%p(" CUPS_LLFMT ", %d)) If-Modified-Since=\"%s\"", - con, con->http.fd, filestats, CUPS_LLCAST filestats->st_size, + con->http.fd, filestats, CUPS_LLCAST filestats->st_size, (int)filestats->st_mtime, ptr); while (*ptr != '\0') @@ -3081,274 +3083,6 @@ compare_clients(cupsd_client_t *a, /* I - First client */ } -#ifdef HAVE_CDSASSL -/* - * 'copy_cdsa_certificate()' - Copy a SSL/TLS certificate from the System - * keychain. - */ - -static CFArrayRef /* O - Array of certificates */ -copy_cdsa_certificate( - cupsd_client_t *con) /* I - Client connection */ -{ - OSStatus err; /* Error info */ - SecKeychainRef keychain = NULL;/* Keychain reference */ - SecIdentitySearchRef search = NULL; /* Search reference */ - SecIdentityRef identity = NULL;/* Identity */ - CFArrayRef certificates = NULL; - /* Certificate array */ -# if HAVE_SECPOLICYCREATESSL - SecPolicyRef policy = NULL; /* Policy ref */ - CFStringRef servername = NULL; - /* Server name */ - CFMutableDictionaryRef query = NULL; /* Query qualifiers */ - char localname[1024];/* Local hostname */ -# elif defined(HAVE_SECIDENTITYSEARCHCREATEWITHPOLICY) - SecPolicyRef policy = NULL; /* Policy ref */ - SecPolicySearchRef policy_search = NULL; - /* Policy search ref */ - CSSM_DATA options; /* Policy options */ - CSSM_APPLE_TP_SSL_OPTIONS - ssl_options; /* SSL Option for hostname */ - char localname[1024];/* Local hostname */ -# endif /* HAVE_SECPOLICYCREATESSL */ - - - cupsdLogMessage(CUPSD_LOG_DEBUG, - "copy_cdsa_certificate: Looking for certs for \"%s\"...", - con->servername); - - if ((err = SecKeychainOpen(ServerCertificate, &keychain))) - { - cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot open keychain \"%s\" - %s (%d)", - ServerCertificate, cssmErrorString(err), (int)err); - goto cleanup; - } - -# if HAVE_SECPOLICYCREATESSL - servername = CFStringCreateWithCString(kCFAllocatorDefault, con->servername, - kCFStringEncodingUTF8); - - policy = SecPolicyCreateSSL(1, servername); - - if (servername) - CFRelease(servername); - - if (!policy) - { - cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot create ssl policy reference"); - goto cleanup; - } - - if (!(query = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks))) - { - cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot create query dictionary"); - goto cleanup; - } - - CFDictionaryAddValue(query, kSecClass, kSecClassIdentity); - CFDictionaryAddValue(query, kSecMatchPolicy, policy); - CFDictionaryAddValue(query, kSecReturnRef, kCFBooleanTrue); - CFDictionaryAddValue(query, kSecMatchLimit, kSecMatchLimitOne); - - err = SecItemCopyMatching(query, (CFTypeRef *)&identity); - - if (err && DNSSDHostName) - { - /* - * Search for the connection server name failed; try the DNS-SD .local - * hostname instead... - */ - - snprintf(localname, sizeof(localname), "%s.local", DNSSDHostName); - - cupsdLogMessage(CUPSD_LOG_DEBUG, - "copy_cdsa_certificate: Looking for certs for \"%s\"...", - localname); - - servername = CFStringCreateWithCString(kCFAllocatorDefault, localname, - kCFStringEncodingUTF8); - - CFRelease(policy); - - policy = SecPolicyCreateSSL(1, servername); - - if (servername) - CFRelease(servername); - - if (!policy) - { - cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot create ssl policy reference"); - goto cleanup; - } - - CFDictionarySetValue(query, kSecMatchPolicy, policy); - - err = SecItemCopyMatching(query, (CFTypeRef *)&identity); - } - - if (err) - { - cupsdLogMessage(CUPSD_LOG_DEBUG, - "Cannot find signing key in keychain \"%s\": %s (%d)", - ServerCertificate, cssmErrorString(err), (int)err); - goto cleanup; - } - -# elif defined(HAVE_SECIDENTITYSEARCHCREATEWITHPOLICY) - /* - * Use a policy to search for valid certificates whose common name matches the - * servername... - */ - - if (SecPolicySearchCreate(CSSM_CERT_X_509v3, &CSSMOID_APPLE_TP_SSL, - NULL, &policy_search)) - { - cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot create a policy search reference"); - goto cleanup; - } - - if (SecPolicySearchCopyNext(policy_search, &policy)) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "Cannot find a policy to use for searching"); - goto cleanup; - } - - memset(&ssl_options, 0, sizeof(ssl_options)); - ssl_options.Version = CSSM_APPLE_TP_SSL_OPTS_VERSION; - ssl_options.ServerName = con->servername; - ssl_options.ServerNameLen = strlen(con->servername); - - options.Data = (uint8 *)&ssl_options; - options.Length = sizeof(ssl_options); - - if (SecPolicySetValue(policy, &options)) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "Cannot set policy value to use for searching"); - goto cleanup; - } - - if ((err = SecIdentitySearchCreateWithPolicy(policy, NULL, CSSM_KEYUSE_SIGN, - keychain, FALSE, &search))) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "Cannot create identity search reference: %s (%d)", - cssmErrorString(err), (int)err); - goto cleanup; - } - - err = SecIdentitySearchCopyNext(search, &identity); - - if (err && DNSSDHostName) - { - /* - * Search for the connection server name failed; try the DNS-SD .local - * hostname instead... - */ - - snprintf(localname, sizeof(localname), "%s.local", DNSSDHostName); - - ssl_options.ServerName = localname; - ssl_options.ServerNameLen = strlen(localname); - - cupsdLogMessage(CUPSD_LOG_DEBUG, - "copy_cdsa_certificate: Looking for certs for \"%s\"...", - localname); - - if (SecPolicySetValue(policy, &options)) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "Cannot set policy value to use for searching"); - goto cleanup; - } - - CFRelease(search); - search = NULL; - if ((err = SecIdentitySearchCreateWithPolicy(policy, NULL, CSSM_KEYUSE_SIGN, - keychain, FALSE, &search))) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "Cannot create identity search reference: %s (%d)", - cssmErrorString(err), (int)err); - goto cleanup; - } - - err = SecIdentitySearchCopyNext(search, &identity); - - } - - if (err) - { - cupsdLogMessage(CUPSD_LOG_DEBUG, - "Cannot find signing key in keychain \"%s\": %s (%d)", - ServerCertificate, cssmErrorString(err), (int)err); - goto cleanup; - } - -# else - /* - * Assume there is exactly one SecIdentity in the keychain... - */ - - if ((err = SecIdentitySearchCreate(keychain, CSSM_KEYUSE_SIGN, &search))) - { - cupsdLogMessage(CUPSD_LOG_DEBUG, - "Cannot create identity search reference (%d)", (int)err); - goto cleanup; - } - - if ((err = SecIdentitySearchCopyNext(search, &identity))) - { - cupsdLogMessage(CUPSD_LOG_DEBUG, - "Cannot find signing key in keychain \"%s\": %s (%d)", - ServerCertificate, cssmErrorString(err), (int)err); - goto cleanup; - } -# endif /* HAVE_SECPOLICYCREATESSL */ - - if (CFGetTypeID(identity) != SecIdentityGetTypeID()) - { - cupsdLogMessage(CUPSD_LOG_ERROR, "SecIdentity CFTypeID failure!"); - goto cleanup; - } - - if ((certificates = CFArrayCreate(NULL, (const void **)&identity, - 1, &kCFTypeArrayCallBacks)) == NULL) - { - cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot create certificate array"); - goto cleanup; - } - - cleanup : - - if (keychain) - CFRelease(keychain); - if (search) - CFRelease(search); - if (identity) - CFRelease(identity); - -# if HAVE_SECPOLICYCREATESSL - if (policy) - CFRelease(policy); - if (query) - CFRelease(query); -# elif defined(HAVE_SECIDENTITYSEARCHCREATEWITHPOLICY) - if (policy) - CFRelease(policy); - if (policy_search) - CFRelease(policy_search); -# endif /* HAVE_SECPOLICYCREATESSL */ - - return (certificates); -} -#endif /* HAVE_CDSASSL */ - - /* * 'data_ready()' - Check whether data is available from a client. */ @@ -3380,245 +3114,6 @@ data_ready(cupsd_client_t *con) /* I - Client */ } -#ifdef HAVE_SSL -/* - * 'encrypt_client()' - Enable encryption for the client... - */ - -static int /* O - 1 on success, 0 on error */ -encrypt_client(cupsd_client_t *con) /* I - Client to encrypt */ -{ -# ifdef HAVE_LIBSSL - SSL_CTX *context; /* Context for encryption */ - BIO *bio; /* BIO data */ - unsigned long error; /* Error code */ - - - cupsdLogMessage(CUPSD_LOG_DEBUG2, "encrypt_client(con=%p(%d))", con, - con->http.fd); - - /* - * Verify that we have a certificate... - */ - - if (access(ServerKey, 0) || access(ServerCertificate, 0)) - { - /* - * Nope, make a self-signed certificate... - */ - - if (!make_certificate(con)) - return (0); - } - - /* - * Create the SSL context and accept the connection... - */ - - context = SSL_CTX_new(SSLv23_server_method()); - - SSL_CTX_set_options(context, SSL_OP_NO_SSLv2); /* Only use SSLv3 or TLS */ - if (SSLOptions & CUPSD_SSL_NOEMPTY) - SSL_CTX_set_options(context, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS); - SSL_CTX_use_PrivateKey_file(context, ServerKey, SSL_FILETYPE_PEM); - SSL_CTX_use_certificate_chain_file(context, ServerCertificate); - - bio = BIO_new(_httpBIOMethods()); - BIO_ctrl(bio, BIO_C_SET_FILE_PTR, 0, (char *)HTTP(con)); - - con->http.tls = SSL_new(context); - SSL_set_bio(con->http.tls, bio, bio); - - if (SSL_accept(con->http.tls) != 1) - { - cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to encrypt connection from %s.", - con->http.hostname); - - while ((error = ERR_get_error()) != 0) - cupsdLogMessage(CUPSD_LOG_ERROR, "%s", ERR_error_string(error, NULL)); - - SSL_CTX_free(context); - SSL_free(con->http.tls); - con->http.tls = NULL; - return (0); - } - - cupsdLogMessage(CUPSD_LOG_DEBUG, "Connection from %s now encrypted.", - con->http.hostname); - - return (1); - -# elif defined(HAVE_GNUTLS) - int status; /* Error code */ - gnutls_certificate_server_credentials *credentials; - /* TLS credentials */ - - - cupsdLogMessage(CUPSD_LOG_DEBUG2, "encrypt_client(con=%p(%d))", con, - con->http.fd); - - /* - * Verify that we have a certificate... - */ - - if (access(ServerKey, 0) || access(ServerCertificate, 0)) - { - /* - * Nope, make a self-signed certificate... - */ - - if (!make_certificate(con)) - return (0); - } - - /* - * Create the SSL object and perform the SSL handshake... - */ - - credentials = (gnutls_certificate_server_credentials *) - malloc(sizeof(gnutls_certificate_server_credentials)); - if (credentials == NULL) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to encrypt connection from %s - %s", - con->http.hostname, strerror(errno)); - - return (0); - } - - gnutls_certificate_allocate_credentials(credentials); - gnutls_certificate_set_x509_key_file(*credentials, ServerCertificate, - ServerKey, GNUTLS_X509_FMT_PEM); - - gnutls_init(&con->http.tls, GNUTLS_SERVER); - gnutls_set_default_priority(con->http.tls); - - gnutls_credentials_set(con->http.tls, GNUTLS_CRD_CERTIFICATE, *credentials); - gnutls_transport_set_ptr(con->http.tls, (gnutls_transport_ptr)HTTP(con)); - gnutls_transport_set_pull_function(con->http.tls, _httpReadGNUTLS); - gnutls_transport_set_push_function(con->http.tls, _httpWriteGNUTLS); - - while ((status = gnutls_handshake(con->http.tls)) != GNUTLS_E_SUCCESS) - { - if (gnutls_error_is_fatal(status)) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to encrypt connection from %s - %s", - con->http.hostname, gnutls_strerror(status)); - - gnutls_deinit(con->http.tls); - gnutls_certificate_free_credentials(*credentials); - con->http.tls = NULL; - free(credentials); - return (0); - } - } - - cupsdLogMessage(CUPSD_LOG_DEBUG, "Connection from %s now encrypted.", - con->http.hostname); - - con->http.tls_credentials = credentials; - return (1); - -# elif defined(HAVE_CDSASSL) - OSStatus error = 0; /* Error code */ - CFArrayRef peerCerts; /* Peer certificates */ - - - cupsdLogMessage(CUPSD_LOG_DEBUG2, "encrypt_client(con=%p(%d))", con, - con->http.fd); - - con->http.tls_credentials = copy_cdsa_certificate(con); - - if (!con->http.tls_credentials) - { - /* - * No keychain (yet), make a self-signed certificate... - */ - - if (make_certificate(con)) - con->http.tls_credentials = copy_cdsa_certificate(con); - } - - if (!con->http.tls_credentials) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "Could not find signing key in keychain \"%s\"", - ServerCertificate); - error = errSSLBadCert; /* errSSLBadConfiguration is a better choice, but not available on 10.2.x */ - } - - if (!error) - error = SSLNewContext(true, &con->http.tls); - - if (!error) - error = SSLSetIOFuncs(con->http.tls, _httpReadCDSA, _httpWriteCDSA); - - if (!error) - error = SSLSetConnection(con->http.tls, HTTP(con)); - - if (!error) - error = SSLSetAllowsExpiredCerts(con->http.tls, true); - - if (!error) - error = SSLSetAllowsAnyRoot(con->http.tls, true); - - if (!error) - error = SSLSetCertificate(con->http.tls, con->http.tls_credentials); - - if (!error) - { - /* - * Perform SSL/TLS handshake - */ - - while ((error = SSLHandshake(con->http.tls)) == errSSLWouldBlock) - usleep(1000); - } - - if (error) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to encrypt connection from %s - %s (%d)", - con->http.hostname, cssmErrorString(error), (int)error); - - con->http.error = error; - con->http.status = HTTP_ERROR; - - if (con->http.tls) - { - SSLDisposeContext(con->http.tls); - con->http.tls = NULL; - } - - if (con->http.tls_credentials) - { - CFRelease(con->http.tls_credentials); - con->http.tls_credentials = NULL; - } - - return (0); - } - - cupsdLogMessage(CUPSD_LOG_DEBUG, "Connection from %s now encrypted.", - con->http.hostname); - - if (!SSLCopyPeerCertificates(con->http.tls, &peerCerts) && peerCerts) - { - cupsdLogMessage(CUPSD_LOG_DEBUG, "Received %d peer certificates!", - (int)CFArrayGetCount(peerCerts)); - CFRelease(peerCerts); - } - else - cupsdLogMessage(CUPSD_LOG_DEBUG, "Received NO peer certificates!"); - - return (1); - -# endif /* HAVE_LIBSSL */ -} -#endif /* HAVE_SSL */ - - /* * 'get_file()' - Get a filename and state info. */ @@ -3802,8 +3297,8 @@ get_file(cupsd_client_t *con, /* I - Client connection */ } cupsdLogMessage(CUPSD_LOG_DEBUG2, - "get_file(con=%p(%d), filestats=%p, filename=%p, len=%d) = " - "%s", con, con->http.fd, filestats, filename, len, + "[Client %d] get_file filestats=%p, filename=%p, len=%d, " + "returning \"%s\".", con->http.fd, filestats, filename, len, status ? "(null)" : filename); if (status) @@ -3814,14 +3309,13 @@ get_file(cupsd_client_t *con, /* I - Client connection */ /* - * 'install_conf_file()' - Install a configuration file. + * 'install_cupsd_conf()' - Install a configuration file. */ static http_status_t /* O - Status */ -install_conf_file(cupsd_client_t *con) /* I - Connection */ +install_cupsd_conf(cupsd_client_t *con) /* I - Connection */ { char filename[1024]; /* Configuration filename */ - mode_t mode; /* Permissions */ cups_file_t *in, /* Input file */ *out; /* Output file */ char buffer[16384]; /* Copy buffer */ @@ -3843,19 +3337,14 @@ install_conf_file(cupsd_client_t *con) /* I - Connection */ * Open the new config file... */ - snprintf(filename, sizeof(filename), "%s%s", ServerRoot, con->uri + 11); - if (!strcmp(con->uri, "/admin/conf/printers.conf")) - mode = ConfigFilePerm & 0600; - else - mode = ConfigFilePerm; - - if ((out = cupsdCreateConfFile(filename, mode)) == NULL) + if ((out = cupsdCreateConfFile(ConfigurationFile, ConfigFilePerm)) == NULL) { cupsFileClose(in); return (HTTP_SERVER_ERROR); } - cupsdLogMessage(CUPSD_LOG_INFO, "Installing config file \"%s\"...", filename); + cupsdLogMessage(CUPSD_LOG_INFO, "Installing config file \"%s\"...", + ConfigurationFile); /* * Copy from the request to the new config file... @@ -3866,12 +3355,12 @@ install_conf_file(cupsd_client_t *con) /* I - Connection */ { cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to copy to config file \"%s\": %s", - filename, strerror(errno)); + ConfigurationFile, strerror(errno)); cupsFileClose(in); cupsFileClose(out); - snprintf(filename, sizeof(filename), "%s%s.N", ServerRoot, con->uri + 11); + snprintf(filename, sizeof(filename), "%s.N", ConfigurationFile); cupsdRemoveFile(filename); return (HTTP_SERVER_ERROR); @@ -3883,7 +3372,7 @@ install_conf_file(cupsd_client_t *con) /* I - Connection */ cupsFileClose(in); - if (cupsdCloseCreatedConfFile(out, filename)) + if (cupsdCloseCreatedConfFile(out, ConfigurationFile)) return (HTTP_SERVER_ERROR); /* @@ -3894,14 +3383,10 @@ install_conf_file(cupsd_client_t *con) /* I - Connection */ cupsdClearString(&con->filename); /* - * If the cupsd.conf file was updated, set the NeedReload flag... + * Set the NeedReload flag... */ - if (!strcmp(con->uri, "/admin/conf/cupsd.conf")) - NeedReload = RELOAD_CUPSD; - else - NeedReload = RELOAD_ALL; - + NeedReload = RELOAD_CUPSD; ReloadTime = time(NULL); /* @@ -3942,9 +3427,9 @@ is_cgi(cupsd_client_t *con, /* I - Client connection */ if (!type || _cups_strcasecmp(type->super, "application")) { cupsdLogMessage(CUPSD_LOG_DEBUG2, - "is_cgi(con=%p(%d), filename=\"%s\", filestats=%p, " - "type=%s/%s) = 0", con, con->http.fd, filename, filestats, - type ? type->super : "unknown", + "[Client %d] is_cgi filename=\"%s\", filestats=%p, " + "type=%s/%s, returning 0", con->http.fd, filename, + filestats, type ? type->super : "unknown", type ? type->type : "unknown"); return (0); } @@ -3962,9 +3447,9 @@ is_cgi(cupsd_client_t *con, /* I - Client connection */ cupsdSetStringf(&con->options, " %s", options); cupsdLogMessage(CUPSD_LOG_DEBUG2, - "is_cgi(con=%p(%d), filename=\"%s\", filestats=%p, " - "type=%s/%s) = 1", con, con->http.fd, filename, filestats, - type->super, type->type); + "[Client %d] is_cgi filename=\"%s\", filestats=%p, " + "type=%s/%s, returning 1", con->http.fd, filename, + filestats, type->super, type->type); return (1); } #ifdef HAVE_JAVA @@ -3982,9 +3467,9 @@ is_cgi(cupsd_client_t *con, /* I - Client connection */ cupsdSetStringf(&con->options, " %s", filename); cupsdLogMessage(CUPSD_LOG_DEBUG2, - "is_cgi(con=%p(%d), filename=\"%s\", filestats=%p, " - "type=%s/%s) = 1", con, con->http.fd, filename, filestats, - type->super, type->type); + "[Client %d] is_cgi filename=\"%s\", filestats=%p, " + "type=%s/%s, returning 1", con->http.fd, filename, + filestats, type->super, type->type); return (1); } #endif /* HAVE_JAVA */ @@ -4003,9 +3488,9 @@ is_cgi(cupsd_client_t *con, /* I - Client connection */ cupsdSetStringf(&con->options, " %s", filename); cupsdLogMessage(CUPSD_LOG_DEBUG2, - "is_cgi(con=%p(%d), filename=\"%s\", filestats=%p, " - "type=%s/%s) = 1", con, con->http.fd, filename, filestats, - type->super, type->type); + "[Client %d] is_cgi filename=\"%s\", filestats=%p, " + "type=%s/%s, returning 1", con->http.fd, filename, + filestats, type->super, type->type); return (1); } #endif /* HAVE_PERL */ @@ -4024,9 +3509,9 @@ is_cgi(cupsd_client_t *con, /* I - Client connection */ cupsdSetStringf(&con->options, " %s", filename); cupsdLogMessage(CUPSD_LOG_DEBUG2, - "is_cgi(con=%p(%d), filename=\"%s\", filestats=%p, " - "type=%s/%s) = 1", con, con->http.fd, filename, filestats, - type->super, type->type); + "[Client %d] is_cgi filename=\"%s\", filestats=%p, " + "type=%s/%s, returning 1", con->http.fd, filename, + filestats, type->super, type->type); return (1); } #endif /* HAVE_PHP */ @@ -4045,17 +3530,17 @@ is_cgi(cupsd_client_t *con, /* I - Client connection */ cupsdSetStringf(&con->options, " %s", filename); cupsdLogMessage(CUPSD_LOG_DEBUG2, - "is_cgi(con=%p(%d), filename=\"%s\", filestats=%p, " - "type=%s/%s) = 1", con, con->http.fd, filename, filestats, - type->super, type->type); + "[Client %d] is_cgi filename=\"%s\", filestats=%p, " + "type=%s/%s, returning 1", con->http.fd, filename, + filestats, type->super, type->type); return (1); } #endif /* HAVE_PYTHON */ cupsdLogMessage(CUPSD_LOG_DEBUG2, - "is_cgi(con=%p(%d), filename=\"%s\", filestats=%p, " - "type=%s/%s) = 0", con, con->http.fd, filename, filestats, - type->super, type->type); + "[Client %d] is_cgi filename=\"%s\", filestats=%p, " + "type=%s/%s, returning 0", con->http.fd, filename, + filestats, type->super, type->type); return (0); } @@ -4095,475 +3580,6 @@ is_path_absolute(const char *path) /* I - Input path */ } -#ifdef HAVE_SSL -/* - * 'make_certificate()' - Make a self-signed SSL/TLS certificate. - */ - -static int /* O - 1 on success, 0 on failure */ -make_certificate(cupsd_client_t *con) /* I - Client connection */ -{ -#if defined(HAVE_LIBSSL) && defined(HAVE_WAITPID) - int pid, /* Process ID of command */ - status; /* Status of command */ - char command[1024], /* Command */ - *argv[12], /* Command-line arguments */ - *envp[MAX_ENV + 1], /* Environment variables */ - infofile[1024], /* Type-in information for cert */ - seedfile[1024]; /* Random number seed file */ - int envc, /* Number of environment variables */ - bytes; /* Bytes written */ - cups_file_t *fp; /* Seed/info file */ - int infofd; /* Info file descriptor */ - - - /* - * Run the "openssl" command to seed the random number generator and - * generate a self-signed certificate that is good for 10 years: - * - * openssl rand -rand seedfile 1 - * - * openssl req -new -x509 -keyout ServerKey \ - * -out ServerCertificate -days 3650 -nodes - * - * The seeding step is crucial in ensuring that the openssl command - * does not block on systems without sufficient entropy... - */ - - if (!cupsFileFind("openssl", getenv("PATH"), 1, command, sizeof(command))) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "No SSL certificate and openssl command not found!"); - return (0); - } - - if (access("/dev/urandom", 0)) - { - /* - * If the system doesn't provide /dev/urandom, then any random source - * will probably be blocking-style, so generate some random data to - * use as a seed for the certificate. Note that we have already - * seeded the random number generator in cupsdInitCerts()... - */ - - cupsdLogMessage(CUPSD_LOG_INFO, - "Seeding the random number generator..."); - - /* - * Write the seed file... - */ - - if ((fp = cupsTempFile2(seedfile, sizeof(seedfile))) == NULL) - { - cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create seed file %s - %s", - seedfile, strerror(errno)); - return (0); - } - - for (bytes = 0; bytes < 262144; bytes ++) - cupsFilePutChar(fp, random()); - - cupsFileClose(fp); - - /* - * Run the openssl command to seed its random number generator... - */ - - argv[0] = "openssl"; - argv[1] = "rand"; - argv[2] = "-rand"; - argv[3] = seedfile; - argv[4] = "1"; - argv[5] = NULL; - - envc = cupsdLoadEnv(envp, MAX_ENV); - envp[envc] = NULL; - - if (!cupsdStartProcess(command, argv, envp, -1, -1, -1, -1, -1, 1, NULL, - NULL, &pid)) - { - unlink(seedfile); - return (0); - } - - while (waitpid(pid, &status, 0) < 0) - if (errno != EINTR) - { - status = 1; - break; - } - - cupsdFinishProcess(pid, command, sizeof(command), NULL); - - /* - * Remove the seed file, as it is no longer needed... - */ - - unlink(seedfile); - - if (status) - { - if (WIFEXITED(status)) - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to seed random number generator - " - "the openssl command stopped with status %d!", - WEXITSTATUS(status)); - else - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to seed random number generator - " - "the openssl command crashed on signal %d!", - WTERMSIG(status)); - - return (0); - } - } - - /* - * Create a file with the certificate information fields... - * - * Note: This assumes that the default questions are asked by the openssl - * command... - */ - - if ((fp = cupsTempFile2(infofile, sizeof(infofile))) == NULL) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to create certificate information file %s - %s", - infofile, strerror(errno)); - return (0); - } - - cupsFilePrintf(fp, ".\n.\n.\n%s\n.\n%s\n%s\n", - ServerName, ServerName, ServerAdmin); - cupsFileClose(fp); - - cupsdLogMessage(CUPSD_LOG_INFO, - "Generating SSL server key and certificate..."); - - argv[0] = "openssl"; - argv[1] = "req"; - argv[2] = "-new"; - argv[3] = "-x509"; - argv[4] = "-keyout"; - argv[5] = ServerKey; - argv[6] = "-out"; - argv[7] = ServerCertificate; - argv[8] = "-days"; - argv[9] = "3650"; - argv[10] = "-nodes"; - argv[11] = NULL; - - cupsdLoadEnv(envp, MAX_ENV); - - infofd = open(infofile, O_RDONLY); - - if (!cupsdStartProcess(command, argv, envp, infofd, -1, -1, -1, -1, 1, NULL, - NULL, &pid)) - { - close(infofd); - unlink(infofile); - return (0); - } - - close(infofd); - unlink(infofile); - - while (waitpid(pid, &status, 0) < 0) - if (errno != EINTR) - { - status = 1; - break; - } - - cupsdFinishProcess(pid, command, sizeof(command), NULL); - - if (status) - { - if (WIFEXITED(status)) - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to create SSL server key and certificate - " - "the openssl command stopped with status %d!", - WEXITSTATUS(status)); - else - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to create SSL server key and certificate - " - "the openssl command crashed on signal %d!", - WTERMSIG(status)); - } - else - { - cupsdLogMessage(CUPSD_LOG_INFO, "Created SSL server key file \"%s\"...", - ServerKey); - cupsdLogMessage(CUPSD_LOG_INFO, - "Created SSL server certificate file \"%s\"...", - ServerCertificate); - } - - return (!status); - -#elif defined(HAVE_GNUTLS) - gnutls_x509_crt crt; /* Self-signed certificate */ - gnutls_x509_privkey key; /* Encryption key */ - cups_lang_t *language; /* Default language info */ - cups_file_t *fp; /* Key/cert file */ - unsigned char buffer[8192]; /* Buffer for x509 data */ - size_t bytes; /* Number of bytes of data */ - unsigned char serial[4]; /* Serial number buffer */ - time_t curtime; /* Current time */ - int result; /* Result of GNU TLS calls */ - - - /* - * Create the encryption key... - */ - - cupsdLogMessage(CUPSD_LOG_INFO, "Generating SSL server key..."); - - gnutls_x509_privkey_init(&key); - gnutls_x509_privkey_generate(key, GNUTLS_PK_RSA, 2048, 0); - - /* - * Save it... - */ - - bytes = sizeof(buffer); - - if ((result = gnutls_x509_privkey_export(key, GNUTLS_X509_FMT_PEM, - buffer, &bytes)) < 0) - { - cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to export SSL server key - %s", - gnutls_strerror(result)); - gnutls_x509_privkey_deinit(key); - return (0); - } - else if ((fp = cupsFileOpen(ServerKey, "w")) != NULL) - { - cupsFileWrite(fp, (char *)buffer, bytes); - cupsFileClose(fp); - - cupsdLogMessage(CUPSD_LOG_INFO, "Created SSL server key file \"%s\"...", - ServerKey); - } - else - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to create SSL server key file \"%s\" - %s", - ServerKey, strerror(errno)); - gnutls_x509_privkey_deinit(key); - return (0); - } - - /* - * Create the self-signed certificate... - */ - - cupsdLogMessage(CUPSD_LOG_INFO, "Generating self-signed SSL certificate..."); - - language = cupsLangDefault(); - curtime = time(NULL); - serial[0] = curtime >> 24; - serial[1] = curtime >> 16; - serial[2] = curtime >> 8; - serial[3] = curtime; - - gnutls_x509_crt_init(&crt); - if (strlen(language->language) == 5) - gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_COUNTRY_NAME, 0, - language->language + 3, 2); - else - gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_COUNTRY_NAME, 0, - "US", 2); - gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_COMMON_NAME, 0, - ServerName, strlen(ServerName)); - gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_ORGANIZATION_NAME, 0, - ServerName, strlen(ServerName)); - gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_ORGANIZATIONAL_UNIT_NAME, - 0, "Unknown", 7); - gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_STATE_OR_PROVINCE_NAME, 0, - "Unknown", 7); - gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_LOCALITY_NAME, 0, - "Unknown", 7); - gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_PKCS9_EMAIL, 0, - ServerAdmin, strlen(ServerAdmin)); - gnutls_x509_crt_set_key(crt, key); - gnutls_x509_crt_set_serial(crt, serial, sizeof(serial)); - gnutls_x509_crt_set_activation_time(crt, curtime); - gnutls_x509_crt_set_expiration_time(crt, curtime + 10 * 365 * 86400); - gnutls_x509_crt_set_ca_status(crt, 0); - gnutls_x509_crt_set_subject_alternative_name(crt, GNUTLS_SAN_DNSNAME, - ServerName); - gnutls_x509_crt_set_key_purpose_oid(crt, GNUTLS_KP_TLS_WWW_SERVER, 0); - gnutls_x509_crt_set_key_usage(crt, GNUTLS_KEY_KEY_ENCIPHERMENT); - gnutls_x509_crt_set_version(crt, 3); - - bytes = sizeof(buffer); - if (gnutls_x509_crt_get_key_id(crt, 0, buffer, &bytes) >= 0) - gnutls_x509_crt_set_subject_key_id(crt, buffer, bytes); - - gnutls_x509_crt_sign(crt, crt, key); - - /* - * Save it... - */ - - bytes = sizeof(buffer); - if ((result = gnutls_x509_crt_export(crt, GNUTLS_X509_FMT_PEM, - buffer, &bytes)) < 0) - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to export SSL server certificate - %s", - gnutls_strerror(result)); - else if ((fp = cupsFileOpen(ServerCertificate, "w")) != NULL) - { - cupsFileWrite(fp, (char *)buffer, bytes); - cupsFileClose(fp); - - cupsdLogMessage(CUPSD_LOG_INFO, - "Created SSL server certificate file \"%s\"...", - ServerCertificate); - } - else - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to create SSL server certificate file \"%s\" - %s", - ServerCertificate, strerror(errno)); - - /* - * Cleanup... - */ - - gnutls_x509_crt_deinit(crt); - gnutls_x509_privkey_deinit(key); - - return (1); - -#elif defined(HAVE_CDSASSL) && defined(HAVE_WAITPID) - int pid, /* Process ID of command */ - status; /* Status of command */ - char command[1024], /* Command */ - *argv[4], /* Command-line arguments */ - *envp[MAX_ENV + 1], /* Environment variables */ - keychain[1024], /* Keychain argument */ - infofile[1024], /* Type-in information for cert */ - localname[1024], /* Local hostname */ - *servername; /* Name of server in cert */ - cups_file_t *fp; /* Seed/info file */ - int infofd; /* Info file descriptor */ - - - if (con->servername && isdigit(con->servername[0] & 255) && DNSSDHostName) - { - snprintf(localname, sizeof(localname), "%s.local", DNSSDHostName); - servername = localname; - } - else - servername = con->servername; - - /* - * Run the "certtool" command to generate a self-signed certificate... - */ - - if (!cupsFileFind("certtool", getenv("PATH"), 1, command, sizeof(command))) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "No SSL certificate and certtool command not found!"); - return (0); - } - - /* - * Create a file with the certificate information fields... - * - * Note: This assumes that the default questions are asked by the certtool - * command... - */ - - if ((fp = cupsTempFile2(infofile, sizeof(infofile))) == NULL) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to create certificate information file %s - %s", - infofile, strerror(errno)); - return (0); - } - - cupsFilePrintf(fp, - "%s\n" /* Enter key and certificate label */ - "r\n" /* Generate RSA key pair */ - "2048\n" /* Key size in bits */ - "y\n" /* OK (y = yes) */ - "b\n" /* Usage (b=signing/encryption) */ - "s\n" /* Sign with SHA1 */ - "y\n" /* OK (y = yes) */ - "%s\n" /* Common name */ - "\n" /* Country (default) */ - "\n" /* Organization (default) */ - "\n" /* Organizational unit (default) */ - "\n" /* State/Province (default) */ - "%s\n" /* Email address */ - "y\n", /* OK (y = yes) */ - servername, servername, ServerAdmin); - cupsFileClose(fp); - - cupsdLogMessage(CUPSD_LOG_INFO, - "Generating SSL server key and certificate..."); - - snprintf(keychain, sizeof(keychain), "k=%s", ServerCertificate); - - argv[0] = "certtool"; - argv[1] = "c"; - argv[2] = keychain; - argv[3] = NULL; - - cupsdLoadEnv(envp, MAX_ENV); - - infofd = open(infofile, O_RDONLY); - - if (!cupsdStartProcess(command, argv, envp, infofd, -1, -1, -1, -1, 1, NULL, - NULL, &pid)) - { - close(infofd); - unlink(infofile); - return (0); - } - - close(infofd); - unlink(infofile); - - while (waitpid(pid, &status, 0) < 0) - if (errno != EINTR) - { - status = 1; - break; - } - - cupsdFinishProcess(pid, command, sizeof(command), NULL); - - if (status) - { - if (WIFEXITED(status)) - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to create SSL server key and certificate - " - "the certtool command stopped with status %d!", - WEXITSTATUS(status)); - else - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to create SSL server key and certificate - " - "the certtool command crashed on signal %d!", - WTERMSIG(status)); - } - else - { - cupsdLogMessage(CUPSD_LOG_INFO, - "Created SSL server certificate file \"%s\"...", - ServerCertificate); - } - - return (!status); - -#else - return (0); -#endif /* HAVE_LIBSSL && HAVE_WAITPID */ -} -#endif /* HAVE_SSL */ - - /* * 'pipe_command()' - Pipe the output of a command to the remote client. */ @@ -4603,7 +3619,6 @@ pipe_command(cupsd_client_t *con, /* I - Client connection */ server_name[1024], /* SERVER_NAME environment variable */ server_port[1024]; /* SERVER_PORT environment variable */ ipp_attribute_t *attr; /* attributes-natural-language attribute */ - void *ccache = NULL; /* Kerberos credentials */ /* @@ -4625,9 +3640,9 @@ pipe_command(cupsd_client_t *con, /* I - Client connection */ */ cupsdLogMessage(CUPSD_LOG_DEBUG2, - "pipe_command(con=%p(%d), infile=%d, outfile=%p, " - "command=\"%s\", options=\"%s\", root=%d)", - con, con->http.fd, infile, outfile, command, + "[Client %d] pipe_command infile=%d, outfile=%p, " + "command=\"%s\", options=\"%s\", root=%d", + con->http.fd, infile, outfile, command, options ? options : "(null)", root); argv[0] = command; @@ -4955,7 +3970,7 @@ pipe_command(cupsd_client_t *con, /* I - Client connection */ */ if (con->username[0]) - cupsdAddCert(pid, con->username, ccache); + cupsdAddCert(pid, con->username, con->type); cupsdLogMessage(CUPSD_LOG_DEBUG, "[CGI] Started %s (PID %d)", command, pid); @@ -5003,16 +4018,26 @@ valid_host(cupsd_client_t *con) /* I - Client connection */ !strncmp(host, "[::1]:", 6)); } -#ifdef HAVE_DNSSD +#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) /* * Check if the hostname is something.local (Bonjour); if so, allow it. */ - if ((end = strrchr(host, '.')) != NULL && - (!_cups_strcasecmp(end, ".local") || !_cups_strncasecmp(end, ".local:", 7) || - !_cups_strcasecmp(end, ".local.") || !_cups_strncasecmp(end, ".local.:", 8))) + if ((end = strrchr(host, '.')) != NULL && end > host && + (!end[1] || end[1] == ':')) + { + /* + * "." on end, work back to second-to-last "."... + */ + for (end --; end > host && *end != '.'; end --); + } + + if (end && (!_cups_strcasecmp(end, ".local") || + !_cups_strncasecmp(end, ".local:", 7) || + !_cups_strcasecmp(end, ".local.") || + !_cups_strncasecmp(end, ".local.:", 8))) return (1); -#endif /* HAVE_DNSSD */ +#endif /* HAVE_DNSSD || HAVE_AVAHI */ /* * Check if the hostname is an IP address... @@ -5073,7 +4098,7 @@ valid_host(cupsd_client_t *con) /* I - Client connection */ } } -#ifdef HAVE_DNSSD +#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) for (a = (cupsd_alias_t *)cupsArrayFirst(DNSSDAlias); a; a = (cupsd_alias_t *)cupsArrayNext(DNSSDAlias)) @@ -5098,7 +4123,7 @@ valid_host(cupsd_client_t *con) /* I - Client connection */ return (1); } } -#endif /* HAVE_DNSSD */ +#endif /* HAVE_DNSSD || HAVE_AVAHI */ /* * Check for interface hostname matches... @@ -5140,8 +4165,8 @@ write_file(cupsd_client_t *con, /* I - Client connection */ con->file = open(filename, O_RDONLY); cupsdLogMessage(CUPSD_LOG_DEBUG2, - "write_file(con=%p(%d), code=%d, filename=\"%s\" (%d), " - "type=\"%s\", filestats=%p)", con, con->http.fd, + "[Client %d] write_file code=%d, filename=\"%s\" (%d), " + "type=\"%s\", filestats=%p", con->http.fd, code, filename, con->file, type ? type : "(null)", filestats); if (con->file < 0) @@ -5189,8 +4214,8 @@ static void write_pipe(cupsd_client_t *con) /* I - Client connection */ { cupsdLogMessage(CUPSD_LOG_DEBUG2, - "write_pipe(con=%p(%d)) CGI output on fd %d", - con, con->http.fd, con->file); + "[Client %d] write_pipe CGI output on fd %d", + con->http.fd, con->file); con->file_ready = 1; @@ -5200,5 +4225,5 @@ write_pipe(cupsd_client_t *con) /* I - Client connection */ /* - * End of "$Id: client.c 10338 2012-03-07 06:05:39Z mike $". + * End of "$Id: client.c 11173 2013-07-23 12:31:34Z msweet $". */ diff --git a/scheduler/client.h b/scheduler/client.h index 7beb4aa..106e43e 100644 --- a/scheduler/client.h +++ b/scheduler/client.h @@ -1,5 +1,5 @@ /* - * "$Id: client.h 9652 2011-03-25 21:25:38Z mike $" + * "$Id: client.h 11173 2013-07-23 12:31:34Z msweet $" * * Client definitions for the CUPS scheduler. * @@ -32,8 +32,10 @@ struct cupsd_client_s http_state_t operation; /* Request operation */ off_t bytes; /* Bytes transferred for this request */ int type; /* AuthType for username */ - char username[256], /* Username from Authorization: line */ - password[33], /* Password from Authorization: line */ + char username[HTTP_MAX_VALUE], + /* Username from Authorization: line */ + password[HTTP_MAX_VALUE], + /* Password from Authorization: line */ uri[HTTP_MAX_URI], /* Localized URL/URI for GET/PUT */ *filename, /* Filename of output file */ @@ -131,7 +133,12 @@ extern void cupsdStopListening(void); extern void cupsdUpdateCGI(void); extern void cupsdWriteClient(cupsd_client_t *con); +#ifdef HAVE_SSL +extern int cupsdEndTLS(cupsd_client_t *con); +extern int cupsdStartTLS(cupsd_client_t *con); +#endif /* HAVE_SSL */ + /* - * End of "$Id: client.h 9652 2011-03-25 21:25:38Z mike $". + * End of "$Id: client.h 11173 2013-07-23 12:31:34Z msweet $". */ diff --git a/scheduler/colorman.c b/scheduler/colorman.c new file mode 100644 index 0000000..be064b6 --- /dev/null +++ b/scheduler/colorman.c @@ -0,0 +1,1542 @@ +/* + * "$Id: colorman.c 11173 2013-07-23 12:31:34Z msweet $" + * + * Color management routines for the CUPS scheduler. + * + * Copyright 2007-2013 by Apple Inc. + * Copyright 1997-2007 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Apple Inc. and are protected by Federal copyright + * law. Distribution and use rights are outlined in the file "LICENSE.txt" + * which should have been included with this file. If this file is + * file is missing or damaged, see the license at "http://www.cups.org/". + * + * Original DBUS/colord code is Copyright 2011 Red Hat, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Contents: + * + * cupsdRegisterColor() - Register vendor color profiles in a PPD + * file. + * cupsdStartColor() - Initialize color management. + * cupsdStopColor() - Shutdown color management. + * cupsdUnregisterColor() - Unregister vendor color profiles in a PPD + * file. + * apple_init_profile() - Initialize a color profile. + * apple_register_profiles() - Register color profiles for a printer. + * apple_unregister_profiles() - Remove color profiles for the specified + * printer. + * colord_create_device() - Create a device and register profiles. + * colord_create_profile() - Create a color profile for a printer. + * colord_delete_device() - Delete a device + * colord_device_add_profile() - Assign a profile to a device. + * colord_dict_add_strings() - Add two strings to a dictionary. + * colord_find_device() - Finds a device + * colord_get_qualifier_format() - Get the qualifier format. + * colord_register_printer() - Register profiles for a printer. + * colord_unregister_printer() - Unregister profiles for a printer. + */ + +/* + * Include necessary headers... + */ + +#include "cupsd.h" +#include <cups/ppd-private.h> + +#ifdef __APPLE__ +# include <ApplicationServices/ApplicationServices.h> +extern CFUUIDRef ColorSyncCreateUUIDFromUInt32(unsigned id); +# include <CoreFoundation/CoreFoundation.h> +#elif defined(HAVE_DBUS) +# include <dbus/dbus.h> + +/* + * Defines used by colord. See the reference docs for further details: + * + * http://colord.hughsie.com/api/ref-dbus.html + */ + +# define COLORD_SCOPE_NORMAL "normal" + /* System scope */ +# define COLORD_SCOPE_TEMP "temp" /* Process scope */ +# define COLORD_SCOPE_DISK "disk" /* Lives forever, as stored in DB */ + +# define COLORD_RELATION_SOFT "soft" /* Mapping is not default */ +# define COLORD_RELATION_HARD "hard" /* Explicitly mapped profile */ + +# define COLORD_SPACE_RGB "rgb" /* RGB colorspace */ +# define COLORD_SPACE_CMYK "cmyk" /* CMYK colorspace */ +# define COLORD_SPACE_GRAY "gray" /* Gray colorspace */ +# define COLORD_SPACE_UNKNOWN "unknown" + /* Unknown colorspace */ + +# define COLORD_MODE_PHYSICAL "physical" + /* Actual device */ +# define COLORD_MODE_VIRTUAL "virtual" + /* Virtual device with no hardware */ + +# define COLORD_KIND_PRINTER "printer" + /* printing output device */ + +# define COLORD_DBUS_SERVICE "org.freedesktop.ColorManager" +# define COLORD_DBUS_INTERFACE "org.freedesktop.ColorManager" +# define COLORD_DBUS_INTERFACE_DEVICE "org.freedesktop.ColorManager.Device" +# define COLORD_DBUS_PATH "/org/freedesktop/ColorManager" + /* Path for color management system */ +# define COLORD_DBUS_TIMEOUT 5000 /* Timeout for connecting to colord in ms */ +#endif /* __APPLE__ */ + + +/* + * Local globals... + */ + +#if !defined(__APPLE__) && defined(HAVE_DBUS) +static DBusConnection *colord_con = NULL; + /* DBUS connection for colord */ +#endif /* !__APPLE__ && HAVE_DBUS */ + + +/* + * Local functions... + */ + +#ifdef __APPLE__ +static void apple_init_profile(ppd_file_t *ppd, cups_array_t *languages, + CFMutableDictionaryRef profile, + unsigned id, const char *name, + const char *text, const char *iccfile); +static void apple_register_profiles(cupsd_printer_t *p); +static void apple_unregister_profiles(cupsd_printer_t *p); + +#elif defined(HAVE_DBUS) +static void colord_create_device(cupsd_printer_t *p, ppd_file_t *ppd, + cups_array_t *profiles, + const char *colorspace, char **format, + const char *relation, const char *scope); +static void colord_create_profile(cups_array_t *profiles, + const char *printer_name, + const char *qualifier, + const char *colorspace, + char **format, const char *iccfile, + const char *scope); +static void colord_delete_device(const char *device_id); +static void colord_device_add_profile(const char *device_path, + const char *profile_path, + const char *relation); +static void colord_dict_add_strings(DBusMessageIter *dict, + const char *key, const char *value); +static char *colord_find_device(const char *device_id); +static void colord_get_qualifier_format(ppd_file_t *ppd, char *format[3]); +static void colord_register_printer(cupsd_printer_t *p); +static void colord_unregister_printer(cupsd_printer_t *p); +#endif /* __APPLE__ */ + + +/* + * 'cupsdRegisterColor()' - Register vendor color profiles in a PPD file. + */ + +void +cupsdRegisterColor(cupsd_printer_t *p) /* I - Printer */ +{ +#ifdef __APPLE__ + if (!RunUser) + { + apple_unregister_profiles(p); + apple_register_profiles(p); + } + +#elif defined(HAVE_DBUS) + colord_unregister_printer(p); + colord_register_printer(p); +#endif /* __APPLE__ */ +} + + +/* + * 'cupsdStartColor()' - Initialize color management. + */ + +void +cupsdStartColor(void) +{ +#if !defined(__APPLE__) && defined(HAVE_DBUS) + cupsd_printer_t *p; /* Current printer */ + + + colord_con = dbus_bus_get(DBUS_BUS_SYSTEM, NULL); + + for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); + p; + p = (cupsd_printer_t *)cupsArrayNext(Printers)) + cupsdRegisterColor(p); +#endif /* !__APPLE__ && HAVE_DBUS */ +} + + +/* + * 'cupsdStopColor()' - Shutdown color management. + */ + +void +cupsdStopColor(void) +{ +#if !defined(__APPLE__) && defined(HAVE_DBUS) + dbus_connection_unref(colord_con); + colord_con = NULL; +#endif /* !__APPLE__ && HAVE_DBUS */ +} + + +/* + * 'cupsdUnregisterColor()' - Unregister vendor color profiles in a PPD file. + */ + +void +cupsdUnregisterColor(cupsd_printer_t *p)/* I - Printer */ +{ +#ifdef __APPLE__ + if (!RunUser) + apple_unregister_profiles(p); + +#elif defined(HAVE_DBUS) + colord_unregister_printer(p); +#endif /* __APPLE__ */ +} + + +#ifdef __APPLE__ +/* + * 'apple_init_profile()' - Initialize a color profile. + */ + +static void +apple_init_profile( + ppd_file_t *ppd, /* I - PPD file */ + cups_array_t *languages, /* I - Languages in the PPD file */ + CFMutableDictionaryRef profile, /* I - Profile dictionary */ + unsigned id, /* I - Profile ID */ + const char *name, /* I - Profile name */ + const char *text, /* I - Profile UI text */ + const char *iccfile) /* I - ICC filename */ +{ + CFURLRef url; /* URL for profile filename */ + CFMutableDictionaryRef dict; /* Dictionary for name */ + char *language; /* Current language */ + ppd_attr_t *attr; /* Profile attribute */ + CFStringRef cflang, /* Language string */ + cftext; /* Localized text */ + + + (void)id; + + /* + * Build the profile name dictionary... + */ + + dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + if (!dict) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to initialize profile \"%s\".", + iccfile); + return; + } + + cftext = CFStringCreateWithCString(kCFAllocatorDefault, text, + kCFStringEncodingUTF8); + + if (cftext) + { + CFDictionarySetValue(dict, CFSTR("en_US"), cftext); + CFRelease(cftext); + } + + if (languages) + { + /* + * Find localized names for the color profiles... + */ + + cupsArraySave(ppd->sorted_attrs); + + for (language = (char *)cupsArrayFirst(languages); + language; + language = (char *)cupsArrayNext(languages)) + { + if (iccfile) + { + if ((attr = _ppdLocalizedAttr(ppd, "cupsICCProfile", name, + language)) == NULL) + attr = _ppdLocalizedAttr(ppd, "APTiogaProfile", name, language); + } + else + attr = _ppdLocalizedAttr(ppd, "ColorModel", name, language); + + if (attr && attr->text[0]) + { + cflang = CFStringCreateWithCString(kCFAllocatorDefault, language, + kCFStringEncodingUTF8); + cftext = CFStringCreateWithCString(kCFAllocatorDefault, attr->text, + kCFStringEncodingUTF8); + + if (cflang && cftext) + CFDictionarySetValue(dict, cflang, cftext); + + if (cflang) + CFRelease(cflang); + + if (cftext) + CFRelease(cftext); + } + } + + cupsArrayRestore(ppd->sorted_attrs); + } + + /* + * Fill in the profile data... + */ + + if (iccfile && *iccfile) + { + url = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, + (const UInt8 *)iccfile, + strlen(iccfile), false); + + if (url) + { + CFDictionarySetValue(profile, kColorSyncDeviceProfileURL, url); + CFRelease(url); + } + } + + CFDictionarySetValue(profile, kColorSyncDeviceModeDescriptions, dict); + CFRelease(dict); +} + + +/* + * 'apple_register_profiles()' - Register color profiles for a printer. + */ + +static void +apple_register_profiles( + cupsd_printer_t *p) /* I - Printer */ +{ + int i; /* Looping var */ + char ppdfile[1024], /* PPD filename */ + iccfile[1024], /* ICC filename */ + selector[PPD_MAX_NAME]; + /* Profile selection string */ + ppd_file_t *ppd; /* PPD file */ + ppd_attr_t *attr, /* Profile attributes */ + *profileid_attr,/* cupsProfileID attribute */ + *q1_attr, /* ColorModel (or other) qualifier */ + *q2_attr, /* MediaType (or other) qualifier */ + *q3_attr; /* Resolution (or other) qualifier */ + char q_keyword[PPD_MAX_NAME]; + /* Qualifier keyword */ + const char *q1_choice, /* ColorModel (or other) choice */ + *q2_choice, /* MediaType (or other) choice */ + *q3_choice; /* Resolution (or other) choice */ + ppd_option_t *cm_option; /* Color model option */ + ppd_choice_t *cm_choice; /* Color model choice */ + int num_profiles; /* Number of profiles */ + OSStatus error = 0; /* Last error */ + unsigned device_id, /* Printer device ID */ + profile_id = 0, /* Profile ID */ + default_profile_id = 0; + /* Default profile ID */ + CFMutableDictionaryRef device_name; /* Printer device name dictionary */ + CFStringRef printer_name; /* Printer name string */ + cups_array_t *languages; /* Languages array */ + CFMutableDictionaryRef profiles, /* Dictionary of profiles */ + profile; /* Current profile info dictionary */ + CFStringRef dict_key; /* Key in factory profile dictionary */ + + + /* + * Make sure ColorSync is available... + */ + + if (ColorSyncRegisterDevice == NULL) + return; + + /* + * Try opening the PPD file for this printer... + */ + + snprintf(ppdfile, sizeof(ppdfile), "%s/ppd/%s.ppd", ServerRoot, p->name); + if ((ppd = _ppdOpenFile(ppdfile, _PPD_LOCALIZATION_ICC_PROFILES)) == NULL) + return; + + /* + * See if we have any profiles... + */ + + for (num_profiles = 0, attr = ppdFindAttr(ppd, "cupsICCProfile", NULL); + attr; + attr = ppdFindNextAttr(ppd, "cupsICCProfile", NULL)) + if (attr->spec[0] && attr->value && attr->value[0]) + { + if (attr->value[0] != '/') + snprintf(iccfile, sizeof(iccfile), "%s/profiles/%s", DataDir, + attr->value); + else + strlcpy(iccfile, attr->value, sizeof(iccfile)); + + if (access(iccfile, 0)) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "%s: ICC Profile \"%s\" does not exist.", p->name, + iccfile); + cupsdSetPrinterReasons(p, "+cups-missing-filter-warning"); + continue; + } + + num_profiles ++; + } + + /* + * Create a dictionary for the factory profiles... + */ + + profiles = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + if (!profiles) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to allocate memory for factory profiles."); + ppdClose(ppd); + return; + } + + /* + * If we have profiles, add them... + */ + + if (num_profiles > 0) + { + /* + * For CUPS PPDs, figure out the default profile selector values... + */ + + if ((attr = ppdFindAttr(ppd, "cupsICCQualifier1", NULL)) != NULL && + attr->value && attr->value[0]) + { + snprintf(q_keyword, sizeof(q_keyword), "Default%s", attr->value); + q1_attr = ppdFindAttr(ppd, q_keyword, NULL); + } + else if ((q1_attr = ppdFindAttr(ppd, "DefaultColorModel", NULL)) == NULL) + q1_attr = ppdFindAttr(ppd, "DefaultColorSpace", NULL); + + if (q1_attr && q1_attr->value && q1_attr->value[0]) + q1_choice = q1_attr->value; + else + q1_choice = ""; + + if ((attr = ppdFindAttr(ppd, "cupsICCQualifier2", NULL)) != NULL && + attr->value && attr->value[0]) + { + snprintf(q_keyword, sizeof(q_keyword), "Default%s", attr->value); + q2_attr = ppdFindAttr(ppd, q_keyword, NULL); + } + else + q2_attr = ppdFindAttr(ppd, "DefaultMediaType", NULL); + + if (q2_attr && q2_attr->value && q2_attr->value[0]) + q2_choice = q2_attr->value; + else + q2_choice = NULL; + + if ((attr = ppdFindAttr(ppd, "cupsICCQualifier3", NULL)) != NULL && + attr->value && attr->value[0]) + { + snprintf(q_keyword, sizeof(q_keyword), "Default%s", attr->value); + q3_attr = ppdFindAttr(ppd, q_keyword, NULL); + } + else + q3_attr = ppdFindAttr(ppd, "DefaultResolution", NULL); + + if (q3_attr && q3_attr->value && q3_attr->value[0]) + q3_choice = q3_attr->value; + else + q3_choice = NULL; + + /* + * Loop through the profiles listed in the PPD... + */ + + languages = _ppdGetLanguages(ppd); + + for (attr = ppdFindAttr(ppd, "cupsICCProfile", NULL); + attr; + attr = ppdFindNextAttr(ppd, "cupsICCProfile", NULL)) + if (attr->spec[0] && attr->value && attr->value[0]) + { + /* + * Add this profile... + */ + + if (attr->value[0] != '/') + snprintf(iccfile, sizeof(iccfile), "%s/profiles/%s", DataDir, + attr->value); + else + strlcpy(iccfile, attr->value, sizeof(iccfile)); + + if (_cupsFileCheck(iccfile, _CUPS_FILE_CHECK_FILE, !RunUser, + cupsdLogFCMessage, p)) + iccfile[0] = '\0'; + + cupsArraySave(ppd->sorted_attrs); + + if ((profileid_attr = ppdFindAttr(ppd, "cupsProfileID", + attr->spec)) != NULL && + profileid_attr->value && isdigit(profileid_attr->value[0] & 255)) + profile_id = (unsigned)strtoul(profileid_attr->value, NULL, 10); + else + profile_id = _ppdHashName(attr->spec); + + cupsArrayRestore(ppd->sorted_attrs); + + profile = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + if (!profile) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to allocate memory for color profile."); + CFRelease(profiles); + ppdClose(ppd); + return; + } + + apple_init_profile(ppd, languages, profile, profile_id, attr->spec, + attr->text[0] ? attr->text : attr->spec, iccfile); + + dict_key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, + CFSTR("%u"), profile_id); + if (dict_key) + { + CFDictionarySetValue(profiles, dict_key, profile); + CFRelease(dict_key); + } + + CFRelease(profile); + + /* + * See if this is the default profile... + */ + + if (!default_profile_id && q1_choice && q2_choice && q3_choice) + { + snprintf(selector, sizeof(selector), "%s.%s.%s", q1_choice, q2_choice, + q3_choice); + if (!strcmp(selector, attr->spec)) + default_profile_id = profile_id; + } + + if (!default_profile_id && q1_choice && q2_choice) + { + snprintf(selector, sizeof(selector), "%s.%s.", q1_choice, q2_choice); + if (!strcmp(selector, attr->spec)) + default_profile_id = profile_id; + } + + if (!default_profile_id && q1_choice && q3_choice) + { + snprintf(selector, sizeof(selector), "%s..%s", q1_choice, q3_choice); + if (!strcmp(selector, attr->spec)) + default_profile_id = profile_id; + } + + if (!default_profile_id && q1_choice) + { + snprintf(selector, sizeof(selector), "%s..", q1_choice); + if (!strcmp(selector, attr->spec)) + default_profile_id = profile_id; + } + + if (!default_profile_id && q2_choice && q3_choice) + { + snprintf(selector, sizeof(selector), ".%s.%s", q2_choice, q3_choice); + if (!strcmp(selector, attr->spec)) + default_profile_id = profile_id; + } + + if (!default_profile_id && q2_choice) + { + snprintf(selector, sizeof(selector), ".%s.", q2_choice); + if (!strcmp(selector, attr->spec)) + default_profile_id = profile_id; + } + + if (!default_profile_id && q3_choice) + { + snprintf(selector, sizeof(selector), "..%s", q3_choice); + if (!strcmp(selector, attr->spec)) + default_profile_id = profile_id; + } + } + + _ppdFreeLanguages(languages); + } + else if ((cm_option = ppdFindOption(ppd, "ColorModel")) != NULL) + { + /* + * Extract profiles from ColorModel option... + */ + + const char *profile_name; /* Name of generic profile */ + + + num_profiles = cm_option->num_choices; + + for (i = cm_option->num_choices, cm_choice = cm_option->choices; + i > 0; + i --, cm_choice ++) + { + if (!strcmp(cm_choice->choice, "Gray") || + !strcmp(cm_choice->choice, "Black")) + profile_name = "Gray"; + else if (!strcmp(cm_choice->choice, "RGB") || + !strcmp(cm_choice->choice, "CMY")) + profile_name = "RGB"; + else if (!strcmp(cm_choice->choice, "CMYK") || + !strcmp(cm_choice->choice, "KCMY")) + profile_name = "CMYK"; + else + profile_name = "DeviceN"; + + snprintf(selector, sizeof(selector), "%s..", profile_name); + profile_id = _ppdHashName(selector); + + profile = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + if (!profile) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to allocate memory for color profile."); + CFRelease(profiles); + ppdClose(ppd); + return; + } + + apple_init_profile(ppd, NULL, profile, profile_id, cm_choice->choice, + cm_choice->text, NULL); + + dict_key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, + CFSTR("%u"), profile_id); + if (dict_key) + { + CFDictionarySetValue(profiles, dict_key, profile); + CFRelease(dict_key); + } + + CFRelease(profile); + + if (cm_choice->marked) + default_profile_id = profile_id; + } + } + else + { + /* + * Use the default colorspace... + */ + + attr = ppdFindAttr(ppd, "DefaultColorSpace", NULL); + + num_profiles = (attr && ppd->colorspace == PPD_CS_GRAY) ? 1 : 2; + + /* + * Add the grayscale profile first. We always have a grayscale profile. + */ + + profile = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + + if (!profile) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to allocate memory for color profile."); + CFRelease(profiles); + ppdClose(ppd); + return; + } + + profile_id = _ppdHashName("Gray.."); + apple_init_profile(ppd, NULL, profile, profile_id, "Gray", "Gray", NULL); + + dict_key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%u"), + profile_id); + if (dict_key) + { + CFDictionarySetValue(profiles, dict_key, profile); + CFRelease(dict_key); + } + + CFRelease(profile); + + /* + * Then add the RGB/CMYK/DeviceN color profile... + */ + + profile = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + + if (!profile) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to allocate memory for color profile."); + CFRelease(profiles); + ppdClose(ppd); + return; + } + + switch (ppd->colorspace) + { + default : + case PPD_CS_RGB : + case PPD_CS_CMY : + profile_id = _ppdHashName("RGB.."); + apple_init_profile(ppd, NULL, profile, profile_id, "RGB", "RGB", + NULL); + break; + + case PPD_CS_RGBK : + case PPD_CS_CMYK : + profile_id = _ppdHashName("CMYK.."); + apple_init_profile(ppd, NULL, profile, profile_id, "CMYK", "CMYK", + NULL); + break; + + case PPD_CS_GRAY : + if (attr) + break; + + case PPD_CS_N : + profile_id = _ppdHashName("DeviceN.."); + apple_init_profile(ppd, NULL, profile, profile_id, "DeviceN", + "DeviceN", NULL); + break; + } + + if (CFDictionaryGetCount(profile) > 0) + { + dict_key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, + CFSTR("%u"), profile_id); + if (dict_key) + { + CFDictionarySetValue(profiles, dict_key, profile); + CFRelease(dict_key); + } + } + + CFRelease(profile); + } + + if (num_profiles > 0) + { + /* + * Make sure we have a default profile ID... + */ + + if (!default_profile_id) + default_profile_id = profile_id; /* Last profile */ + + dict_key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%u"), + default_profile_id); + if (dict_key) + { + CFDictionarySetValue(profiles, kColorSyncDeviceDefaultProfileID, + dict_key); + CFRelease(dict_key); + } + + /* + * Get the device ID hash and pathelogical name dictionary. + */ + + cupsdLogMessage(CUPSD_LOG_INFO, "Registering ICC color profiles for \"%s\"", + p->name); + + device_id = _ppdHashName(p->name); + device_name = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + printer_name = CFStringCreateWithCString(kCFAllocatorDefault, + p->name, kCFStringEncodingUTF8); + + if (device_name && printer_name) + { + /* + * Register the device with ColorSync... + */ + + CFTypeRef deviceDictKeys[] = + { /* Device keys */ + kColorSyncDeviceDescriptions, + kColorSyncFactoryProfiles, + kColorSyncDeviceUserScope, + kColorSyncDeviceHostScope + }; + CFTypeRef deviceDictVals[] = + { /* Device values */ + device_name, + profiles, + kCFPreferencesAnyUser, + kCFPreferencesCurrentHost + }; + CFDictionaryRef deviceDict; /* Device dictionary */ + CFUUIDRef deviceUUID; /* Device UUID */ + + CFDictionarySetValue(device_name, CFSTR("en_US"), printer_name); + + deviceDict = CFDictionaryCreate(kCFAllocatorDefault, + (const void **)deviceDictKeys, + (const void **)deviceDictVals, + sizeof(deviceDictKeys) / + sizeof(deviceDictKeys[0]), + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + deviceUUID = ColorSyncCreateUUIDFromUInt32(device_id); + + if (!deviceDict || !deviceUUID || + !ColorSyncRegisterDevice(kColorSyncPrinterDeviceClass, deviceUUID, + deviceDict)) + error = 1001; + + if (deviceUUID) + CFRelease(deviceUUID); + + if (deviceDict) + CFRelease(deviceDict); + } + else + error = 1000; + + /* + * Clean up... + */ + + if (error != noErr) + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to register ICC color profiles for \"%s\": %d", + p->name, (int)error); + + if (printer_name) + CFRelease(printer_name); + + if (device_name) + CFRelease(device_name); + } + + /* + * Free any memory we used... + */ + + CFRelease(profiles); + + ppdClose(ppd); +} + + +/* + * 'apple_unregister_profiles()' - Remove color profiles for the specified + * printer. + */ + +static void +apple_unregister_profiles( + cupsd_printer_t *p) /* I - Printer */ +{ + /* + * Make sure ColorSync is available... + */ + + if (ColorSyncUnregisterDevice != NULL) + { + CFUUIDRef deviceUUID; /* Device UUID */ + + deviceUUID = ColorSyncCreateUUIDFromUInt32(_ppdHashName(p->name)); + if (deviceUUID) + { + ColorSyncUnregisterDevice(kColorSyncPrinterDeviceClass, deviceUUID); + CFRelease(deviceUUID); + } + } +} + + +#elif defined(HAVE_DBUS) +/* + * 'colord_create_device()' - Create a device and register profiles. + */ + +static void +colord_create_device( + cupsd_printer_t *p, /* I - Printer */ + ppd_file_t *ppd, /* I - PPD file */ + cups_array_t *profiles, /* I - Profiles array */ + const char *colorspace, /* I - Device colorspace, e.g. 'rgb' */ + char **format, /* I - Device qualifier format */ + const char *relation, /* I - Profile relation, either 'soft' + or 'hard' */ + const char *scope) /* I - The scope of the device, e.g. + 'normal', 'temp' or 'disk' */ +{ + DBusMessage *message = NULL; /* D-Bus request */ + DBusMessage *reply = NULL; /* D-Bus reply */ + DBusMessageIter args; /* D-Bus method arguments */ + DBusMessageIter dict; /* D-Bus method arguments */ + DBusError error; /* D-Bus error */ + const char *device_path; /* Device object path */ + const char *profile_path; /* Profile path */ + char *default_profile_path = NULL; + /* Default profile path */ + char device_id[1024]; /* Device ID as understood by colord */ + char format_str[1024]; /* Qualifier format as a string */ + + + /* + * Create the device... + */ + + snprintf(device_id, sizeof(device_id), "cups-%s", p->name); + device_path = device_id; + + message = dbus_message_new_method_call(COLORD_DBUS_SERVICE, + COLORD_DBUS_PATH, + COLORD_DBUS_INTERFACE, + "CreateDevice"); + + dbus_message_iter_init_append(message, &args); + dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &device_path); + dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &scope); + + snprintf(format_str, sizeof(format_str), "%s.%s.%s", format[0], format[1], + format[2]); + + dbus_message_iter_open_container(&args, DBUS_TYPE_ARRAY, "{ss}", &dict); + colord_dict_add_strings(&dict, "Colorspace", colorspace); + colord_dict_add_strings(&dict, "Mode", COLORD_MODE_PHYSICAL); + if (ppd->manufacturer) + colord_dict_add_strings(&dict, "Vendor", ppd->manufacturer); + if (ppd->modelname) + colord_dict_add_strings(&dict, "Model", ppd->modelname); + if (p->sanitized_device_uri) + colord_dict_add_strings(&dict, "Serial", p->sanitized_device_uri); + colord_dict_add_strings(&dict, "Format", format_str); + colord_dict_add_strings(&dict, "Kind", COLORD_KIND_PRINTER); + dbus_message_iter_close_container(&args, &dict); + + /* + * Send the CreateDevice request synchronously... + */ + + dbus_error_init(&error); + cupsdLogMessage(CUPSD_LOG_DEBUG, "Calling CreateDevice(%s,%s)", device_id, + scope); + reply = dbus_connection_send_with_reply_and_block(colord_con, message, + COLORD_DBUS_TIMEOUT, + &error); + if (!reply) + { + cupsdLogMessage(CUPSD_LOG_WARN, "CreateDevice failed: %s:%s", error.name, + error.message); + dbus_error_free(&error); + goto out; + } + + /* + * Get reply data... + */ + + dbus_message_iter_init(reply, &args); + if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH) + { + cupsdLogMessage(CUPSD_LOG_WARN, + "CreateDevice failed: Incorrect reply type."); + goto out; + } + + dbus_message_iter_get_basic(&args, &device_path); + cupsdLogMessage(CUPSD_LOG_DEBUG, "Created device \"%s\".", device_path); + + /* + * Add profiles... + */ + + for (profile_path = cupsArrayFirst(profiles); + profile_path; + profile_path = cupsArrayNext(profiles)) + { + colord_device_add_profile(device_path, profile_path, relation); + } + +out: + + if (default_profile_path) + free(default_profile_path); + + if (message) + dbus_message_unref(message); + + if (reply) + dbus_message_unref(reply); +} + + +/* + * 'colord_create_profile()' - Create a color profile for a printer. + */ + +static void +colord_create_profile( + cups_array_t *profiles, /* I - Profiles array */ + const char *printer_name, /* I - Printer name */ + const char *qualifier, /* I - Profile qualifier */ + const char *colorspace, /* I - Profile colorspace */ + char **format, /* I - Profile qualifier format */ + const char *iccfile, /* I - ICC filename */ + const char *scope) /* I - The scope of the profile, e.g. + 'normal', 'temp' or 'disk' */ +{ + DBusMessage *message = NULL; /* D-Bus request */ + DBusMessage *reply = NULL; /* D-Bus reply */ + DBusMessageIter args; /* D-Bus method arguments */ + DBusMessageIter dict; /* D-Bus method arguments */ + DBusError error; /* D-Bus error */ + char *idstr; /* Profile ID string */ + size_t idstrlen; /* Profile ID allocated length */ + const char *profile_path; /* Device object path */ + char format_str[1024]; /* Qualifier format as a string */ + + + /* + * Create the profile... + */ + + message = dbus_message_new_method_call(COLORD_DBUS_SERVICE, + COLORD_DBUS_PATH, + COLORD_DBUS_INTERFACE, + "CreateProfile"); + + idstrlen = strlen(printer_name) + 1 + strlen(qualifier) + 1; + if ((idstr = malloc(idstrlen)) == NULL) + goto out; + snprintf(idstr, idstrlen, "%s-%s", printer_name, qualifier); + cupsdLogMessage(CUPSD_LOG_DEBUG, "Using profile ID \"%s\".", idstr); + + dbus_message_iter_init_append(message, &args); + dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &idstr); + dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &scope); + + snprintf(format_str, sizeof(format_str), "%s.%s.%s", format[0], format[1], + format[2]); + + dbus_message_iter_open_container(&args, DBUS_TYPE_ARRAY, "{ss}", &dict); + colord_dict_add_strings(&dict, "Qualifier", qualifier); + colord_dict_add_strings(&dict, "Format", format_str); + colord_dict_add_strings(&dict, "Colorspace", colorspace); + if (iccfile) + colord_dict_add_strings(&dict, "Filename", iccfile); + dbus_message_iter_close_container(&args, &dict); + + /* + * Send the CreateProfile request synchronously... + */ + + dbus_error_init(&error); + cupsdLogMessage(CUPSD_LOG_DEBUG, "Calling CreateProfile(%s,%s)", idstr, + scope); + reply = dbus_connection_send_with_reply_and_block(colord_con, message, + COLORD_DBUS_TIMEOUT, + &error); + if (!reply) + { + cupsdLogMessage(CUPSD_LOG_WARN, "CreateProfile failed: %s:%s", error.name, + error.message); + dbus_error_free(&error); + goto out; + } + + /* + * Get reply data... + */ + + dbus_message_iter_init(reply, &args); + if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH) + { + cupsdLogMessage(CUPSD_LOG_WARN, + "CreateProfile failed: Incorrect reply type."); + goto out; + } + + dbus_message_iter_get_basic(&args, &profile_path); + cupsdLogMessage(CUPSD_LOG_DEBUG, "Created profile \"%s\".", profile_path); + cupsArrayAdd(profiles, strdup(profile_path)); + +out: + + if (message) + dbus_message_unref(message); + + if (reply) + dbus_message_unref(reply); + + if (idstr) + free(idstr); +} + + +/* + * 'colord_delete_device()' - Delete a device + */ + +static void +colord_delete_device( + const char *device_id) /* I - Device ID string */ +{ + DBusMessage *message = NULL; /* D-Bus request */ + DBusMessage *reply = NULL; /* D-Bus reply */ + DBusMessageIter args; /* D-Bus method arguments */ + DBusError error; /* D-Bus error */ + char *device_path; /* Device object path */ + + + /* + * Find the device... + */ + + if ((device_path = colord_find_device(device_id)) == NULL) + goto out; + + /* + * Delete the device... + */ + + message = dbus_message_new_method_call(COLORD_DBUS_SERVICE, + COLORD_DBUS_PATH, + COLORD_DBUS_INTERFACE, + "DeleteDevice"); + + dbus_message_iter_init_append(message, &args); + dbus_message_iter_append_basic(&args, DBUS_TYPE_OBJECT_PATH, &device_path); + + /* + * Send the DeleteDevice request synchronously... + */ + + dbus_error_init(&error); + cupsdLogMessage(CUPSD_LOG_DEBUG, "Calling DeleteDevice(%s)", device_path); + reply = dbus_connection_send_with_reply_and_block(colord_con, message, + COLORD_DBUS_TIMEOUT, + &error); + if (!reply) + { + cupsdLogMessage(CUPSD_LOG_DEBUG, "DeleteDevice failed: %s:%s", error.name, + error.message); + dbus_error_free(&error); + goto out; + } + +out: + + if (device_path) + free(device_path); + + if (message) + dbus_message_unref(message); + + if (reply) + dbus_message_unref(reply); +} + + +/* + * 'colord_device_add_profile()' - Assign a profile to a device. + */ + +static void +colord_device_add_profile( + const char *device_path, /* I - Device object path */ + const char *profile_path, /* I - Profile object path */ + const char *relation) /* I - Device relation, either + 'soft' or 'hard' */ +{ + DBusMessage *message = NULL; /* D-Bus request */ + DBusMessage *reply = NULL; /* D-Bus reply */ + DBusMessageIter args; /* D-Bus method arguments */ + DBusError error; /* D-Bus error */ + + + message = dbus_message_new_method_call(COLORD_DBUS_SERVICE, + device_path, + COLORD_DBUS_INTERFACE_DEVICE, + "AddProfile"); + + dbus_message_iter_init_append(message, &args); + dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &relation); + dbus_message_iter_append_basic(&args, DBUS_TYPE_OBJECT_PATH, &profile_path); + cupsdLogMessage(CUPSD_LOG_DEBUG, "Calling %s:AddProfile(%s) [%s]", + device_path, profile_path, relation); + + /* + * Send the AddProfile request synchronously... + */ + + dbus_error_init(&error); + reply = dbus_connection_send_with_reply_and_block(colord_con, message, + COLORD_DBUS_TIMEOUT, + &error); + if (!reply) + { + cupsdLogMessage(CUPSD_LOG_WARN, "AddProfile failed: %s:%s", error.name, + error.message); + dbus_error_free(&error); + goto out; + } + +out: + + if (message) + dbus_message_unref(message); + + if (reply) + dbus_message_unref(reply); +} + + +/* + * 'colord_dict_add_strings()' - Add two strings to a dictionary. + */ + +static void +colord_dict_add_strings( + DBusMessageIter *dict, /* I - Dictionary */ + const char *key, /* I - Key string */ + const char *value) /* I - Value string */ +{ + DBusMessageIter entry; /* Entry to add */ + + + dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY, NULL, &entry); + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key); + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &value); + dbus_message_iter_close_container(dict, &entry); +} + + +/* + * 'colord_find_device()' - Finds a device + */ + +static char * /* O - Device path or NULL */ +colord_find_device( + const char *device_id) /* I - Device ID string */ +{ + DBusMessage *message = NULL; /* D-Bus request */ + DBusMessage *reply = NULL; /* D-Bus reply */ + DBusMessageIter args; /* D-Bus method arguments */ + DBusError error; /* D-Bus error */ + const char *device_path_tmp; /* Device object path */ + char *device_path = NULL; /* Device object path */ + + + message = dbus_message_new_method_call(COLORD_DBUS_SERVICE, + COLORD_DBUS_PATH, + COLORD_DBUS_INTERFACE, + "FindDeviceById"); + + dbus_message_iter_init_append(message, &args); + dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &device_id); + + /* + * Send the FindDeviceById request synchronously... + */ + + dbus_error_init(&error); + cupsdLogMessage(CUPSD_LOG_DEBUG, "Calling FindDeviceById(%s)", device_id); + reply = dbus_connection_send_with_reply_and_block(colord_con, message, + COLORD_DBUS_TIMEOUT, + &error); + if (!reply) + { + cupsdLogMessage(CUPSD_LOG_DEBUG, "FindDeviceById failed: %s:%s", + error.name, error.message); + dbus_error_free(&error); + goto out; + } + + /* + * Get reply data... + */ + + dbus_message_iter_init(reply, &args); + if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH) + { + cupsdLogMessage(CUPSD_LOG_WARN, + "FindDeviceById failed: Incorrect reply type."); + goto out; + } + + dbus_message_iter_get_basic(&args, &device_path_tmp); + if (device_path_tmp) + device_path = strdup(device_path_tmp); + +out: + + if (message) + dbus_message_unref(message); + + if (reply) + dbus_message_unref(reply); + + return (device_path); +} + + +/* + * 'colord_get_qualifier_format()' - Get the qualifier format. + * + * Note: Returns a value of "ColorSpace.MediaType.Resolution" by default. + */ + +static void +colord_get_qualifier_format( + ppd_file_t *ppd, /* I - PPD file data */ + char *format[3]) /* I - Format tuple */ +{ + const char *tmp; /* Temporary string */ + ppd_attr_t *attr; /* Profile attributes */ + + + /* + * Get 1st section... + */ + + if ((attr = ppdFindAttr(ppd, "cupsICCQualifier1", NULL)) != NULL) + tmp = attr->value; + else if (ppdFindAttr(ppd, "DefaultColorModel", NULL)) + tmp = "ColorModel"; + else if (ppdFindAttr(ppd, "DefaultColorSpace", NULL)) + tmp = "ColorSpace"; + else + tmp = ""; + + format[0] = strdup(tmp); + + /* + * Get 2nd section... + */ + + if ((attr = ppdFindAttr(ppd, "cupsICCQualifier2", NULL)) != NULL) + tmp = attr->value; + else + tmp = "MediaType"; + + format[1] = strdup(tmp); + + /* + * Get 3rd section... + */ + + if ((attr = ppdFindAttr(ppd, "cupsICCQualifier3", NULL)) != NULL) + tmp = attr->value; + else + tmp = "Resolution"; + + format[2] = strdup(tmp); +} + + +/* + * 'colord_register_printer()' - Register profiles for a printer. + */ + +static void +colord_register_printer( + cupsd_printer_t *p) /* I - printer */ +{ + char ppdfile[1024], /* PPD filename */ + iccfile[1024]; /* ICC filename */ + ppd_file_t *ppd; /* PPD file */ + cups_array_t *profiles; /* Profile paths array */ + ppd_attr_t *attr; /* Profile attributes */ + const char *device_colorspace; /* Device colorspace */ + char *format[3]; /* Qualifier format tuple */ + + + /* + * Ensure we have a D-Bus connection... + */ + + if (!colord_con) + return; + + /* + * Try opening the PPD file for this printer... + */ + + snprintf(ppdfile, sizeof(ppdfile), "%s/ppd/%s.ppd", ServerRoot, p->name); + if ((ppd = _ppdOpenFile(ppdfile, _PPD_LOCALIZATION_ICC_PROFILES)) == NULL) + return; + + /* + * Find out the qualifier format + */ + + colord_get_qualifier_format(ppd, format); + + /* + * See if we have any embedded profiles... + */ + + profiles = cupsArrayNew3(NULL, NULL, NULL, 0, (cups_acopy_func_t)strdup, + (cups_afree_func_t)free); + for (attr = ppdFindAttr(ppd, "cupsICCProfile", NULL); + attr; + attr = ppdFindNextAttr(ppd, "cupsICCProfile", NULL)) + if (attr->spec[0] && attr->value && attr->value[0]) + { + if (attr->value[0] != '/') + snprintf(iccfile, sizeof(iccfile), "%s/profiles/%s", DataDir, + attr->value); + else + strlcpy(iccfile, attr->value, sizeof(iccfile)); + + if (_cupsFileCheck(iccfile, _CUPS_FILE_CHECK_FILE, !RunUser, + cupsdLogFCMessage, p)) + continue; + + colord_create_profile(profiles, p->name, attr->spec, COLORD_SPACE_UNKNOWN, + format, iccfile, COLORD_SCOPE_TEMP); + } + + /* + * Add the grayscale profile first. We always have a grayscale profile. + */ + + colord_create_profile(profiles, p->name, "Gray..", COLORD_SPACE_GRAY, + format, NULL, COLORD_SCOPE_TEMP); + + /* + * Then add the RGB/CMYK/DeviceN color profile... + */ + + device_colorspace = "unknown"; + switch (ppd->colorspace) + { + case PPD_CS_RGB : + case PPD_CS_CMY : + device_colorspace = COLORD_SPACE_RGB; + colord_create_profile(profiles, p->name, "RGB..", COLORD_SPACE_RGB, + format, NULL, COLORD_SCOPE_TEMP); + break; + + case PPD_CS_RGBK : + case PPD_CS_CMYK : + device_colorspace = COLORD_SPACE_CMYK; + colord_create_profile(profiles, p->name, "CMYK..", COLORD_SPACE_CMYK, + format, NULL, COLORD_SCOPE_TEMP); + break; + + case PPD_CS_GRAY : + device_colorspace = COLORD_SPACE_GRAY; + break; + + case PPD_CS_N : + colord_create_profile(profiles, p->name, "DeviceN..", + COLORD_SPACE_UNKNOWN, format, NULL, + COLORD_SCOPE_TEMP); + break; + } + + /* + * Register the device with colord. + */ + + cupsdLogMessage(CUPSD_LOG_INFO, "Registering ICC color profiles for \"%s\".", + p->name); + colord_create_device(p, ppd, profiles, device_colorspace, format, + COLORD_RELATION_SOFT, COLORD_SCOPE_TEMP); + + /* + * Free any memory we used... + */ + + cupsArrayDelete(profiles); + + free(format[0]); + free(format[1]); + free(format[2]); + + ppdClose(ppd); +} + + +/* + * 'colord_unregister_printer()' - Unregister profiles for a printer. + */ + +static void +colord_unregister_printer( + cupsd_printer_t *p) /* I - printer */ +{ + char device_id[1024]; /* Device ID as understood by colord */ + + + /* + * Ensure we have a D-Bus connection... + */ + + if (!colord_con) + return; + + /* + * Just delete the device itself, and leave the profiles registered + */ + + snprintf(device_id, sizeof(device_id), "cups-%s", p->name); + colord_delete_device(device_id); +} +#endif /* __APPLE__ */ + + +/* + * End of "$Id: colorman.c 11173 2013-07-23 12:31:34Z msweet $". + */ diff --git a/scheduler/colorman.h b/scheduler/colorman.h new file mode 100644 index 0000000..a95adcf --- /dev/null +++ b/scheduler/colorman.h @@ -0,0 +1,28 @@ +/* + * "$Id: colorman.h 11173 2013-07-23 12:31:34Z msweet $" + * + * Color management definitions for the CUPS scheduler. + * + * Copyright 2007-2012 by Apple Inc. + * Copyright 1997-2007 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Apple Inc. and are protected by Federal copyright + * law. Distribution and use rights are outlined in the file "LICENSE.txt" + * which should have been included with this file. If this file is + * file is missing or damaged, see the license at "http://www.cups.org/". + */ + +/* + * Prototypes... + */ + +extern void cupsdRegisterColor(cupsd_printer_t *p); +extern void cupsdStartColor(void); +extern void cupsdStopColor(void); +extern void cupsdUnregisterColor(cupsd_printer_t *p); + + +/* + * End of "$Id: colorman.h 11173 2013-07-23 12:31:34Z msweet $". + */ diff --git a/scheduler/conf.c b/scheduler/conf.c index 3ddcdcd..7ae8fed 100644 --- a/scheduler/conf.c +++ b/scheduler/conf.c @@ -1,9 +1,9 @@ /* - * "$Id: conf.c 10121 2011-11-16 15:28:11Z mike $" + * "$Id: conf.c 11221 2013-08-06 16:16:01Z msweet $" * * Configuration routines for the CUPS scheduler. * - * Copyright 2007-2011 by Apple Inc. + * Copyright 2007-2013 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -14,22 +14,25 @@ * * Contents: * - * cupsdAddAlias() - Add a host alias. + * cupsdAddAlias() - Add a host alias. * cupsdCheckPermissions() - Fix the mode and ownership of a file or - * directory. + * directory. + * cupsdDefaultAuthType() - Get the default AuthType. * cupsdFreeAliases() - Free all of the alias entries. * cupsdReadConfiguration() - Read the cupsd.conf file. - * get_address() - Get an address + port number from a line. + * get_address() - Get an address + port number from a line. * get_addr_and_mask() - Get an IP address and netmask. - * mime_error_cb() - Log a MIME error. - * parse_aaa() - Parse authentication, authorization, and access - * control lines. + * mime_error_cb() - Log a MIME error. + * parse_aaa() - Parse authentication, authorization, and access + * control lines. * parse_fatal_errors() - Parse FatalErrors values in a string. - * parse_groups() - Parse system group names in a string. - * parse_protocols() - Parse browse protocols in a string. - * read_configuration() - Read a configuration file. - * read_location() - Read a <Location path> definition. - * read_policy() - Read a <Policy name> definition. + * parse_groups() - Parse system group names in a string. + * parse_protocols() - Parse browse protocols in a string. + * parse_variable() - Parse a variable line. + * read_cupsd_conf() - Read the cupsd.conf configuration file. + * read_cups_files_conf() - Read the cups-files.conf configuration file. + * read_location() - Read a <Location path> definition. + * read_policy() - Read a <Policy name> definition. * set_policy_defaults() - Set default policy values as needed. */ @@ -64,6 +67,7 @@ typedef enum { CUPSD_VARTYPE_INTEGER, /* Integer option */ + CUPSD_VARTYPE_TIME, /* Time interval option */ CUPSD_VARTYPE_STRING, /* String option */ CUPSD_VARTYPE_BOOLEAN, /* Boolean option */ CUPSD_VARTYPE_PATHNAME /* File/directory name option */ @@ -71,7 +75,7 @@ typedef enum typedef struct { - char *name; /* Name of variable */ + const char *name; /* Name of variable */ void *ptr; /* Pointer to variable */ cupsd_vartype_t type; /* Type (int, string, address) */ } cupsd_var_t; @@ -81,92 +85,85 @@ typedef struct * Local globals... */ -static const cupsd_var_t variables[] = +static const cupsd_var_t cupsd_vars[] = { - { "AccessLog", &AccessLog, CUPSD_VARTYPE_STRING }, { "AutoPurgeJobs", &JobAutoPurge, CUPSD_VARTYPE_BOOLEAN }, -#ifdef HAVE_DNSSD - { "BrowseDNSSDRegType", &DNSSDRegType, CUPSD_VARTYPE_STRING }, -#endif /* HAVE_DNSSD */ - { "BrowseInterval", &BrowseInterval, CUPSD_VARTYPE_INTEGER }, -#ifdef HAVE_LDAP - { "BrowseLDAPBindDN", &BrowseLDAPBindDN, CUPSD_VARTYPE_STRING }, -# ifdef HAVE_LDAP_SSL - { "BrowseLDAPCACertFile", &BrowseLDAPCACertFile, CUPSD_VARTYPE_PATHNAME }, -# endif /* HAVE_LDAP_SSL */ - { "BrowseLDAPDN", &BrowseLDAPDN, CUPSD_VARTYPE_STRING }, - { "BrowseLDAPPassword", &BrowseLDAPPassword, CUPSD_VARTYPE_STRING }, - { "BrowseLDAPServer", &BrowseLDAPServer, CUPSD_VARTYPE_STRING }, -#endif /* HAVE_LDAP */ - { "BrowseLocalOptions", &BrowseLocalOptions, CUPSD_VARTYPE_STRING }, - { "BrowsePort", &BrowsePort, CUPSD_VARTYPE_INTEGER }, - { "BrowseRemoteOptions", &BrowseRemoteOptions, CUPSD_VARTYPE_STRING }, - { "BrowseShortNames", &BrowseShortNames, CUPSD_VARTYPE_BOOLEAN }, - { "BrowseTimeout", &BrowseTimeout, CUPSD_VARTYPE_INTEGER }, +#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) + { "BrowseDNSSDSubTypes", &DNSSDSubTypes, CUPSD_VARTYPE_STRING }, +#endif /* HAVE_DNSSD || HAVE_AVAHI */ { "BrowseWebIF", &BrowseWebIF, CUPSD_VARTYPE_BOOLEAN }, { "Browsing", &Browsing, CUPSD_VARTYPE_BOOLEAN }, - { "CacheDir", &CacheDir, CUPSD_VARTYPE_STRING }, { "Classification", &Classification, CUPSD_VARTYPE_STRING }, { "ClassifyOverride", &ClassifyOverride, CUPSD_VARTYPE_BOOLEAN }, - { "ConfigFilePerm", &ConfigFilePerm, CUPSD_VARTYPE_INTEGER }, - { "DataDir", &DataDir, CUPSD_VARTYPE_STRING }, { "DefaultLanguage", &DefaultLanguage, CUPSD_VARTYPE_STRING }, - { "DefaultLeaseDuration", &DefaultLeaseDuration, CUPSD_VARTYPE_INTEGER }, + { "DefaultLeaseDuration", &DefaultLeaseDuration, CUPSD_VARTYPE_TIME }, { "DefaultPaperSize", &DefaultPaperSize, CUPSD_VARTYPE_STRING }, { "DefaultPolicy", &DefaultPolicy, CUPSD_VARTYPE_STRING }, { "DefaultShared", &DefaultShared, CUPSD_VARTYPE_BOOLEAN }, - { "DirtyCleanInterval", &DirtyCleanInterval, CUPSD_VARTYPE_INTEGER }, - { "DocumentRoot", &DocumentRoot, CUPSD_VARTYPE_STRING }, - { "ErrorLog", &ErrorLog, CUPSD_VARTYPE_STRING }, + { "DirtyCleanInterval", &DirtyCleanInterval, CUPSD_VARTYPE_TIME }, { "ErrorPolicy", &ErrorPolicy, CUPSD_VARTYPE_STRING }, - { "FileDevice", &FileDevice, CUPSD_VARTYPE_BOOLEAN }, { "FilterLimit", &FilterLimit, CUPSD_VARTYPE_INTEGER }, { "FilterNice", &FilterNice, CUPSD_VARTYPE_INTEGER }, - { "FontPath", &FontPath, CUPSD_VARTYPE_STRING }, - { "HideImplicitMembers", &HideImplicitMembers, CUPSD_VARTYPE_BOOLEAN }, - { "ImplicitClasses", &ImplicitClasses, CUPSD_VARTYPE_BOOLEAN }, - { "ImplicitAnyClasses", &ImplicitAnyClasses, CUPSD_VARTYPE_BOOLEAN }, - { "JobKillDelay", &JobKillDelay, CUPSD_VARTYPE_INTEGER }, +#ifdef HAVE_GSSAPI + { "GSSServiceName", &GSSServiceName, CUPSD_VARTYPE_STRING }, +#endif /* HAVE_GSSAPI */ + { "JobKillDelay", &JobKillDelay, CUPSD_VARTYPE_TIME }, { "JobRetryLimit", &JobRetryLimit, CUPSD_VARTYPE_INTEGER }, - { "JobRetryInterval", &JobRetryInterval, CUPSD_VARTYPE_INTEGER }, - { "KeepAliveTimeout", &KeepAliveTimeout, CUPSD_VARTYPE_INTEGER }, + { "JobRetryInterval", &JobRetryInterval, CUPSD_VARTYPE_TIME }, + { "KeepAliveTimeout", &KeepAliveTimeout, CUPSD_VARTYPE_TIME }, { "KeepAlive", &KeepAlive, CUPSD_VARTYPE_BOOLEAN }, #ifdef HAVE_LAUNCHD - { "LaunchdTimeout", &LaunchdTimeout, CUPSD_VARTYPE_INTEGER }, + { "LaunchdTimeout", &LaunchdTimeout, CUPSD_VARTYPE_TIME }, #endif /* HAVE_LAUNCHD */ { "LimitRequestBody", &MaxRequestSize, CUPSD_VARTYPE_INTEGER }, { "ListenBackLog", &ListenBackLog, CUPSD_VARTYPE_INTEGER }, { "LogDebugHistory", &LogDebugHistory, CUPSD_VARTYPE_INTEGER }, - { "LogFilePerm", &LogFilePerm, CUPSD_VARTYPE_INTEGER }, - { "LPDConfigFile", &LPDConfigFile, CUPSD_VARTYPE_STRING }, { "MaxActiveJobs", &MaxActiveJobs, CUPSD_VARTYPE_INTEGER }, { "MaxClients", &MaxClients, CUPSD_VARTYPE_INTEGER }, { "MaxClientsPerHost", &MaxClientsPerHost, CUPSD_VARTYPE_INTEGER }, { "MaxCopies", &MaxCopies, CUPSD_VARTYPE_INTEGER }, { "MaxEvents", &MaxEvents, CUPSD_VARTYPE_INTEGER }, + { "MaxHoldTime", &MaxHoldTime, CUPSD_VARTYPE_TIME }, { "MaxJobs", &MaxJobs, CUPSD_VARTYPE_INTEGER }, { "MaxJobsPerPrinter", &MaxJobsPerPrinter, CUPSD_VARTYPE_INTEGER }, { "MaxJobsPerUser", &MaxJobsPerUser, CUPSD_VARTYPE_INTEGER }, - { "MaxLeaseDuration", &MaxLeaseDuration, CUPSD_VARTYPE_INTEGER }, + { "MaxJobTime", &MaxJobTime, CUPSD_VARTYPE_INTEGER }, + { "MaxLeaseDuration", &MaxLeaseDuration, CUPSD_VARTYPE_TIME }, { "MaxLogSize", &MaxLogSize, CUPSD_VARTYPE_INTEGER }, { "MaxRequestSize", &MaxRequestSize, CUPSD_VARTYPE_INTEGER }, { "MaxSubscriptions", &MaxSubscriptions, CUPSD_VARTYPE_INTEGER }, { "MaxSubscriptionsPerJob", &MaxSubscriptionsPerJob, CUPSD_VARTYPE_INTEGER }, { "MaxSubscriptionsPerPrinter",&MaxSubscriptionsPerPrinter, CUPSD_VARTYPE_INTEGER }, { "MaxSubscriptionsPerUser", &MaxSubscriptionsPerUser, CUPSD_VARTYPE_INTEGER }, - { "MultipleOperationTimeout", &MultipleOperationTimeout, CUPSD_VARTYPE_INTEGER }, - { "PageLog", &PageLog, CUPSD_VARTYPE_STRING }, + { "MultipleOperationTimeout", &MultipleOperationTimeout, CUPSD_VARTYPE_TIME }, { "PageLogFormat", &PageLogFormat, CUPSD_VARTYPE_STRING }, - { "PreserveJobFiles", &JobFiles, CUPSD_VARTYPE_BOOLEAN }, - { "PreserveJobHistory", &JobHistory, CUPSD_VARTYPE_BOOLEAN }, + { "PreserveJobFiles", &JobFiles, CUPSD_VARTYPE_TIME }, + { "PreserveJobHistory", &JobHistory, CUPSD_VARTYPE_TIME }, + { "ReloadTimeout", &ReloadTimeout, CUPSD_VARTYPE_TIME }, + { "RIPCache", &RIPCache, CUPSD_VARTYPE_STRING }, + { "RootCertDuration", &RootCertDuration, CUPSD_VARTYPE_TIME }, + { "ServerAdmin", &ServerAdmin, CUPSD_VARTYPE_STRING }, + { "ServerName", &ServerName, CUPSD_VARTYPE_STRING }, + { "StrictConformance", &StrictConformance, CUPSD_VARTYPE_BOOLEAN }, + { "Timeout", &Timeout, CUPSD_VARTYPE_TIME }, + { "WebInterface", &WebInterface, CUPSD_VARTYPE_BOOLEAN } +}; +static const cupsd_var_t cupsfiles_vars[] = +{ + { "AccessLog", &AccessLog, CUPSD_VARTYPE_STRING }, + { "CacheDir", &CacheDir, CUPSD_VARTYPE_STRING }, + { "ConfigFilePerm", &ConfigFilePerm, CUPSD_VARTYPE_INTEGER }, + { "DataDir", &DataDir, CUPSD_VARTYPE_STRING }, + { "DocumentRoot", &DocumentRoot, CUPSD_VARTYPE_STRING }, + { "ErrorLog", &ErrorLog, CUPSD_VARTYPE_STRING }, + { "FileDevice", &FileDevice, CUPSD_VARTYPE_BOOLEAN }, + { "FontPath", &FontPath, CUPSD_VARTYPE_STRING }, + { "LogFilePerm", &LogFilePerm, CUPSD_VARTYPE_INTEGER }, + { "LPDConfigFile", &LPDConfigFile, CUPSD_VARTYPE_STRING }, + { "PageLog", &PageLog, CUPSD_VARTYPE_STRING }, { "Printcap", &Printcap, CUPSD_VARTYPE_STRING }, - { "PrintcapGUI", &PrintcapGUI, CUPSD_VARTYPE_STRING }, - { "ReloadTimeout", &ReloadTimeout, CUPSD_VARTYPE_INTEGER }, { "RemoteRoot", &RemoteRoot, CUPSD_VARTYPE_STRING }, { "RequestRoot", &RequestRoot, CUPSD_VARTYPE_STRING }, - { "RIPCache", &RIPCache, CUPSD_VARTYPE_STRING }, - { "RootCertDuration", &RootCertDuration, CUPSD_VARTYPE_INTEGER }, - { "ServerAdmin", &ServerAdmin, CUPSD_VARTYPE_STRING }, { "ServerBin", &ServerBin, CUPSD_VARTYPE_PATHNAME }, #ifdef HAVE_SSL { "ServerCertificate", &ServerCertificate, CUPSD_VARTYPE_PATHNAME }, @@ -174,20 +171,18 @@ static const cupsd_var_t variables[] = { "ServerKey", &ServerKey, CUPSD_VARTYPE_PATHNAME }, # endif /* HAVE_LIBSSL || HAVE_GNUTLS */ #endif /* HAVE_SSL */ - { "ServerName", &ServerName, CUPSD_VARTYPE_STRING }, { "ServerRoot", &ServerRoot, CUPSD_VARTYPE_PATHNAME }, { "SMBConfigFile", &SMBConfigFile, CUPSD_VARTYPE_STRING }, { "StateDir", &StateDir, CUPSD_VARTYPE_STRING }, + { "SyncOnClose", &SyncOnClose, CUPSD_VARTYPE_BOOLEAN }, #ifdef HAVE_AUTHORIZATION_H { "SystemGroupAuthKey", &SystemGroupAuthKey, CUPSD_VARTYPE_STRING }, #endif /* HAVE_AUTHORIZATION_H */ - { "TempDir", &TempDir, CUPSD_VARTYPE_PATHNAME }, - { "Timeout", &Timeout, CUPSD_VARTYPE_INTEGER }, - { "UseNetworkDefault", &UseNetworkDefault, CUPSD_VARTYPE_BOOLEAN }, - { "WebInterface", &WebInterface, CUPSD_VARTYPE_BOOLEAN } + { "TempDir", &TempDir, CUPSD_VARTYPE_PATHNAME } }; -#define NUM_VARS (sizeof(variables) / sizeof(variables[0])) +static int default_auth_type = CUPSD_AUTH_AUTO; + /* Default AuthType, if not specified */ static const unsigned ones[4] = { @@ -212,7 +207,12 @@ static int parse_aaa(cupsd_location_t *loc, char *line, static int parse_fatal_errors(const char *s); static int parse_groups(const char *s); static int parse_protocols(const char *s); -static int read_configuration(cups_file_t *fp); +static int parse_variable(const char *filename, int linenum, + const char *line, const char *value, + size_t num_vars, + const cupsd_var_t *vars); +static int read_cupsd_conf(cups_file_t *fp); +static int read_cups_files_conf(cups_file_t *fp); static int read_location(cups_file_t *fp, char *name, int linenum); static int read_policy(cups_file_t *fp, char *name, int linenum); static void set_policy_defaults(cupsd_policy_t *pol); @@ -394,6 +394,118 @@ cupsdCheckPermissions( /* + * 'cupsdDefaultAuthType()' - Get the default AuthType. + * + * When the default_auth_type is "auto", this function tries to get the GSS + * credentials for the server. If that succeeds we use Kerberos authentication, + * otherwise we do a fallback to Basic authentication against the local user + * accounts. + */ + +int /* O - Default AuthType value */ +cupsdDefaultAuthType(void) +{ +#ifdef HAVE_GSSAPI + OM_uint32 major_status, /* Major status code */ + minor_status; /* Minor status code */ + gss_name_t server_name; /* Server name */ + gss_buffer_desc token = GSS_C_EMPTY_BUFFER; + /* Service name token */ + char buf[1024]; /* Service name buffer */ +#endif /* HAVE_GSSAPI */ + + + /* + * If we have already determined the correct default AuthType, use it... + */ + + if (default_auth_type != CUPSD_AUTH_AUTO) + return (default_auth_type); + +#ifdef HAVE_GSSAPI +# ifdef __APPLE__ + /* + * If the weak-linked GSSAPI/Kerberos library is not present, don't try + * to use it... + */ + + if (gss_init_sec_context == NULL) + return (default_auth_type = CUPSD_AUTH_BASIC); +# endif /* __APPLE__ */ + + /* + * Try to obtain the server's GSS credentials (GSSServiceName@servername). If + * that fails we must use Basic... + */ + + snprintf(buf, sizeof(buf), "%s@%s", GSSServiceName, ServerName); + + token.value = buf; + token.length = strlen(buf); + server_name = GSS_C_NO_NAME; + major_status = gss_import_name(&minor_status, &token, + GSS_C_NT_HOSTBASED_SERVICE, + &server_name); + + memset(&token, 0, sizeof(token)); + + if (GSS_ERROR(major_status)) + { + cupsdLogGSSMessage(CUPSD_LOG_DEBUG, major_status, minor_status, + "cupsdDefaultAuthType: gss_import_name(%s) failed", buf); + return (default_auth_type = CUPSD_AUTH_BASIC); + } + + major_status = gss_display_name(&minor_status, server_name, &token, NULL); + + if (GSS_ERROR(major_status)) + { + cupsdLogGSSMessage(CUPSD_LOG_DEBUG, major_status, minor_status, + "cupsdDefaultAuthType: gss_display_name(%s) failed", + buf); + return (default_auth_type = CUPSD_AUTH_BASIC); + } + + cupsdLogMessage(CUPSD_LOG_DEBUG, + "cupsdDefaultAuthType: Attempting to acquire Kerberos " + "credentials for %s...", (char *)token.value); + + ServerCreds = GSS_C_NO_CREDENTIAL; + major_status = gss_acquire_cred(&minor_status, server_name, GSS_C_INDEFINITE, + GSS_C_NO_OID_SET, GSS_C_ACCEPT, + &ServerCreds, NULL, NULL); + if (GSS_ERROR(major_status)) + { + cupsdLogGSSMessage(CUPSD_LOG_DEBUG, major_status, minor_status, + "cupsdDefaultAuthType: gss_acquire_cred(%s) failed", + (char *)token.value); + gss_release_name(&minor_status, &server_name); + gss_release_buffer(&minor_status, &token); + return (default_auth_type = CUPSD_AUTH_BASIC); + } + + cupsdLogMessage(CUPSD_LOG_DEBUG, + "cupsdDefaultAuthType: Kerberos credentials acquired " + "successfully for %s.", (char *)token.value); + + gss_release_name(&minor_status, &server_name); + gss_release_buffer(&minor_status, &token); + + HaveServerCreds = 1; + + return (default_auth_type = CUPSD_AUTH_NEGOTIATE); + +#else + /* + * No Kerberos support compiled in so just use Basic all the time... + */ + + return (default_auth_type = CUPSD_AUTH_BASIC); +#endif /* HAVE_GSSAPI */ +} + + +/* * 'cupsdFreeAliases()' - Free all of the alias entries. */ @@ -451,31 +563,6 @@ cupsdReadConfiguration(void) cupsdDeleteAllLocations(); - if (NumBrowsers > 0) - { - free(Browsers); - Browsers = NULL; - - NumBrowsers = 0; - } - - if (NumPolled > 0) - { - free(Polled); - - NumPolled = 0; - } - - if (NumRelays > 0) - { - for (i = 0; i < NumRelays; i ++) - cupsArrayDelete(Relays[i].from); - - free(Relays); - - NumRelays = 0; - } - cupsdDeleteAllListeners(); old_remote_port = RemotePort; @@ -505,7 +592,7 @@ cupsdReadConfiguration(void) cupsdSetString(&PrintcapGUI, "/usr/bin/glpoptions"); cupsdSetString(&FontPath, CUPS_FONTPATH); cupsdSetString(&RemoteRoot, "remroot"); - cupsdSetStringf(&ServerHeader, "CUPS/%d.%d", CUPS_VERSION_MAJOR, + cupsdSetStringf(&ServerHeader, "CUPS/%d.%d IPP/2.1", CUPS_VERSION_MAJOR, CUPS_VERSION_MINOR); cupsdSetString(&StateDir, CUPS_STATEDIR); @@ -548,6 +635,21 @@ cupsdReadConfiguration(void) cupsdSetString(&TempDir, NULL); +#ifdef HAVE_GSSAPI + cupsdSetString(&GSSServiceName, CUPS_DEFAULT_GSSSERVICENAME); + + if (HaveServerCreds) + { + OM_uint32 minor_status; /* Minor status code */ + + gss_release_cred(&minor_status, &ServerCreds); + + HaveServerCreds = 0; + } + + ServerCreds = GSS_C_NO_CREDENTIAL; +#endif /* HAVE_GSSAPI */ + /* * Find the default user... */ @@ -604,7 +706,7 @@ cupsdReadConfiguration(void) AccessLogLevel = CUPSD_ACCESSLOG_ACTIONS; ConfigFilePerm = CUPS_DEFAULT_CONFIG_FILE_PERM; FatalErrors = parse_fatal_errors(CUPS_DEFAULT_FATAL_ERRORS); - DefaultAuthType = CUPSD_AUTH_BASIC; + default_auth_type = CUPSD_AUTH_BASIC; #ifdef HAVE_SSL DefaultEncryption = HTTP_ENCRYPT_REQUIRED; SSLOptions = CUPSD_SSL_NONE; @@ -618,9 +720,6 @@ cupsdReadConfiguration(void) FilterLimit = 0; FilterNice = 0; HostNameLookups = FALSE; - ImplicitClasses = CUPS_DEFAULT_IMPLICIT_CLASSES; - ImplicitAnyClasses = FALSE; - HideImplicitMembers = TRUE; KeepAlive = TRUE; KeepAliveTimeout = DEFAULT_KEEPALIVE; ListenBackLog = SOMAXCONN; @@ -633,58 +732,44 @@ cupsdReadConfiguration(void) MaxLogSize = 1024 * 1024; MaxRequestSize = 0; MultipleOperationTimeout = DEFAULT_TIMEOUT; + NumSystemGroups = 0; ReloadTimeout = DEFAULT_KEEPALIVE; RootCertDuration = 300; + StrictConformance = FALSE; + SyncOnClose = FALSE; Timeout = DEFAULT_TIMEOUT; - NumSystemGroups = 0; WebInterface = CUPS_DEFAULT_WEBIF; - BrowseInterval = DEFAULT_INTERVAL; - BrowsePort = ippPort(); BrowseLocalProtocols = parse_protocols(CUPS_DEFAULT_BROWSE_LOCAL_PROTOCOLS); - BrowseRemoteProtocols = parse_protocols(CUPS_DEFAULT_BROWSE_REMOTE_PROTOCOLS); - BrowseShortNames = CUPS_DEFAULT_BROWSE_SHORT_NAMES; - BrowseTimeout = DEFAULT_TIMEOUT; BrowseWebIF = FALSE; Browsing = CUPS_DEFAULT_BROWSING; DefaultShared = CUPS_DEFAULT_DEFAULT_SHARED; -#ifdef HAVE_DNSSD - cupsdSetString(&DNSSDRegType, "_ipp._tcp,_cups"); -#endif /* HAVE_DNSSD */ +#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) + cupsdSetString(&DNSSDSubTypes, "_cups,_print"); +#endif /* HAVE_DNSSD || HAVE_AVAHI */ cupsdSetString(&LPDConfigFile, CUPS_DEFAULT_LPD_CONFIG_FILE); cupsdSetString(&SMBConfigFile, CUPS_DEFAULT_SMB_CONFIG_FILE); - cupsdClearString(&BrowseLocalOptions); - cupsdClearString(&BrowseRemoteOptions); - cupsdSetString(&ErrorPolicy, "stop-printer"); -#ifdef HAVE_LDAP - cupsdClearString(&BrowseLDAPBindDN); - cupsdClearString(&BrowseLDAPDN); - cupsdClearString(&BrowseLDAPPassword); - cupsdClearString(&BrowseLDAPServer); -# ifdef HAVE_LDAP_SSL - cupsdClearString(&BrowseLDAPCACertFile); -# endif /* HAVE_LDAP_SSL */ -#endif /* HAVE_LDAP */ - JobHistory = DEFAULT_HISTORY; JobFiles = DEFAULT_FILES; JobAutoPurge = 0; + MaxHoldTime = 0; MaxJobs = 500; MaxActiveJobs = 0; MaxJobsPerUser = 0; MaxJobsPerPrinter = 0; + MaxJobTime = 3 * 60 * 60; /* 3 hours */ MaxCopies = CUPS_DEFAULT_MAX_COPIES; cupsdDeleteAllPolicies(); cupsdClearString(&DefaultPolicy); #ifdef HAVE_AUTHORIZATION_H - cupsdClearString(&SystemGroupAuthKey); + cupsdSetString(&SystemGroupAuthKey, CUPS_DEFAULT_SYSTEM_AUTHKEY); #endif /* HAVE_AUTHORIZATION_H */ MaxSubscriptions = 100; @@ -695,7 +780,7 @@ cupsdReadConfiguration(void) MaxLeaseDuration = 0; #ifdef HAVE_LAUNCHD - LaunchdTimeout = DEFAULT_TIMEOUT + 10; + LaunchdTimeout = 10; #endif /* HAVE_LAUNCHD */ /* @@ -705,21 +790,63 @@ cupsdReadConfiguration(void) cupsdInitEnv(); /* - * Read the configuration file... + * Read the cups-files.conf file... + */ + + if ((fp = cupsFileOpen(CupsFilesFile, "r")) != NULL) + { + status = read_cups_files_conf(fp); + + cupsFileClose(fp); + + if (!status) + { + if (TestConfigFile) + printf("\"%s\" contains errors.\n", CupsFilesFile); + else + syslog(LOG_LPR, "Unable to read \"%s\" due to errors.", + CupsFilesFile); + + return (0); + } + } + else if (errno == ENOENT) + cupsdLogMessage(CUPSD_LOG_INFO, "No %s, using defaults.", CupsFilesFile); + else + { + syslog(LOG_LPR, "Unable to open \"%s\": %s", CupsFilesFile, + strerror(errno)); + return (0); + } + + if (!ErrorLog) + cupsdSetString(&ErrorLog, CUPS_LOGDIR "/error_log"); + + /* + * Read the cupsd.conf file... */ if ((fp = cupsFileOpen(ConfigurationFile, "r")) == NULL) + { + syslog(LOG_LPR, "Unable to open \"%s\": %s", ConfigurationFile, + strerror(errno)); return (0); + } - status = read_configuration(fp); + status = read_cupsd_conf(fp); cupsFileClose(fp); if (!status) - return (0); + { + if (TestConfigFile) + printf("\"%s\" contains errors.\n", ConfigurationFile); + else + syslog(LOG_LPR, "Unable to read \"%s\" due to errors.", + ConfigurationFile); - if (!ErrorLog) - cupsdSetString(&ErrorLog, CUPS_LOGDIR "/error_log"); + return (0); + } RunUser = getuid(); @@ -833,10 +960,11 @@ cupsdReadConfiguration(void) } /* - * Get the access control list for browsing... + * Make sure ConfigFilePerm and LogFilePerm have sane values... */ - BrowseACL = cupsdFindLocation("CUPS_INTERNAL_BROWSE_ACL"); + ConfigFilePerm &= 0664; + LogFilePerm &= 0664; /* * Open the system log for cupsd if necessary... @@ -999,7 +1127,9 @@ cupsdReadConfiguration(void) Group, 1, 1) < 0 || cupsdCheckPermissions(ServerRoot, "ssl", 0700, RunUser, Group, 1, 0) < 0 || - cupsdCheckPermissions(ServerRoot, "cupsd.conf", ConfigFilePerm, RunUser, + cupsdCheckPermissions(ConfigurationFile, NULL, ConfigFilePerm, RunUser, + Group, 0, 0) < 0 || + cupsdCheckPermissions(CupsFilesFile, NULL, ConfigFilePerm, RunUser, Group, 0, 0) < 0 || cupsdCheckPermissions(ServerRoot, "classes.conf", 0600, RunUser, Group, 0, 0) < 0 || @@ -1014,11 +1144,20 @@ cupsdReadConfiguration(void) * Update TempDir to the default if it hasn't been set already... */ +#ifdef __APPLE__ + if (TempDir && !RunUser && + (!strncmp(TempDir, "/private/tmp", 12) || !strncmp(TempDir, "/tmp", 4))) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot use %s for TempDir.", TempDir); + cupsdClearString(&TempDir); + } +#endif /* __APPLE__ */ + if (!TempDir) { #ifdef __APPLE__ if ((tmpdir = getenv("TMPDIR")) != NULL && - strncmp(tmpdir, "/private/tmp", 12)) + strncmp(tmpdir, "/private/tmp", 12) && strncmp(tmpdir, "/tmp", 4)) #else if ((tmpdir = getenv("TMPDIR")) != NULL) #endif /* __APPLE__ */ @@ -1041,13 +1180,13 @@ cupsdReadConfiguration(void) else cupsdSetString(&TempDir, tmpdir); } + } - if (!TempDir) - { - cupsdLogMessage(CUPSD_LOG_INFO, "Using default TempDir of %s/tmp...", - RequestRoot); - cupsdSetStringf(&TempDir, "%s/tmp", RequestRoot); - } + if (!TempDir) + { + cupsdLogMessage(CUPSD_LOG_INFO, "Using default TempDir of %s/tmp...", + RequestRoot); + cupsdSetStringf(&TempDir, "%s/tmp", RequestRoot); } /* @@ -1156,24 +1295,6 @@ cupsdReadConfiguration(void) MaxClientsPerHost); /* - * Make sure that BrowseTimeout is at least twice the interval... - */ - - if (BrowseTimeout < (2 * BrowseInterval) || BrowseTimeout <= 0) - { - cupsdLogMessage(CUPSD_LOG_ALERT, "Invalid BrowseTimeout value %d.", - BrowseTimeout); - - if (BrowseInterval) - BrowseTimeout = BrowseInterval * 2; - else - BrowseTimeout = DEFAULT_TIMEOUT; - - cupsdLogMessage(CUPSD_LOG_ALERT, "Reset BrowseTimeout to %d.", - BrowseTimeout); - } - - /* * Update the default policy, as needed... */ @@ -1477,7 +1598,6 @@ cupsdReadConfiguration(void) cupsdLoadAllPrinters(); cupsdLoadAllClasses(); - cupsdLoadRemoteCache(); cupsdCreateCommonData(); @@ -1511,6 +1631,12 @@ cupsdReadConfiguration(void) cupsdCreateCommonData(); /* + * Update all jobs as needed... + */ + + cupsdUpdateJobs(); + + /* * Update all printers as needed... */ @@ -2474,20 +2600,10 @@ parse_protocols(const char *s) /* I - Space-delimited protocols */ * Add the protocol to the bitmask... */ - if (!_cups_strcasecmp(valstart, "cups")) - protocols |= BROWSE_CUPS; - else if (!_cups_strcasecmp(valstart, "slp")) - protocols |= BROWSE_SLP; - else if (!_cups_strcasecmp(valstart, "ldap")) - protocols |= BROWSE_LDAP; - else if (!_cups_strcasecmp(valstart, "dnssd") || - !_cups_strcasecmp(valstart, "dns-sd") || - !_cups_strcasecmp(valstart, "bonjour")) + if (!_cups_strcasecmp(valstart, "dnssd") || + !_cups_strcasecmp(valstart, "dns-sd") || + !_cups_strcasecmp(valstart, "bonjour")) protocols |= BROWSE_DNSSD; - else if (!_cups_strcasecmp(valstart, "lpd")) - protocols |= BROWSE_LPD; - else if (!_cups_strcasecmp(valstart, "smb")) - protocols |= BROWSE_SMB; else if (!_cups_strcasecmp(valstart, "all")) protocols |= BROWSE_ALL; else if (_cups_strcasecmp(valstart, "none")) @@ -2504,33 +2620,256 @@ parse_protocols(const char *s) /* I - Space-delimited protocols */ /* - * 'read_configuration()' - Read a configuration file. + * 'parse_variable()' - Parse a variable line. */ static int /* O - 1 on success, 0 on failure */ -read_configuration(cups_file_t *fp) /* I - File to read from */ +parse_variable( + const char *filename, /* I - Name of configuration file */ + int linenum, /* I - Line in configuration file */ + const char *line, /* I - Line from configuration file */ + const char *value, /* I - Value from configuration file */ + size_t num_vars, /* I - Number of variables */ + const cupsd_var_t *vars) /* I - Variables */ +{ + size_t i; /* Looping var */ + const cupsd_var_t *var; /* Variables */ + char temp[1024]; /* Temporary string */ + + + for (i = num_vars, var = vars; i > 0; i --, var ++) + if (!_cups_strcasecmp(line, var->name)) + break; + + if (i == 0) + { + /* + * Unknown directive! Output an error message and continue... + */ + + if (!value) + cupsdLogMessage(CUPSD_LOG_ERROR, "Missing value for %s on line %d of %s.", + line, linenum, filename); + else + cupsdLogMessage(CUPSD_LOG_ERROR, "Unknown directive %s on line %d of %s.", + line, linenum, filename); + + return (0); + } + + switch (var->type) + { + case CUPSD_VARTYPE_INTEGER : + if (!value) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Missing integer value for %s on line %d of %s.", + line, linenum, filename); + return (0); + } + else if (!isdigit(*value & 255)) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Bad integer value for %s on line %d of %s.", + line, linenum, filename); + return (0); + } + else + { + int n; /* Number */ + char *units; /* Units */ + + n = strtol(value, &units, 0); + + if (units && *units) + { + if (tolower(units[0] & 255) == 'g') + n *= 1024 * 1024 * 1024; + else if (tolower(units[0] & 255) == 'm') + n *= 1024 * 1024; + else if (tolower(units[0] & 255) == 'k') + n *= 1024; + else if (tolower(units[0] & 255) == 't') + n *= 262144; + else + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unknown integer value for %s on line %d of %s.", + line, linenum, filename); + return (0); + } + } + + if (n < 0) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Bad negative integer value for %s on line %d of " + "%s.", line, linenum, filename); + return (0); + } + else + { + *((int *)var->ptr) = n; + } + } + break; + + case CUPSD_VARTYPE_TIME : + if (!value) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Missing time interval value for %s on line %d of " + "%s.", line, linenum, filename); + return (0); + } + else if (!_cups_strncasecmp(line, "PreserveJob", 11) && + (!_cups_strcasecmp(value, "true") || + !_cups_strcasecmp(value, "on") || + !_cups_strcasecmp(value, "enabled") || + !_cups_strcasecmp(value, "yes"))) + { + *((int *)var->ptr) = INT_MAX; + } + else if (!_cups_strcasecmp(value, "false") || + !_cups_strcasecmp(value, "off") || + !_cups_strcasecmp(value, "disabled") || + !_cups_strcasecmp(value, "no")) + { + *((int *)var->ptr) = 0; + } + else if (!isdigit(*value & 255)) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unknown time interval value for %s on line %d of " + "%s.", line, linenum, filename); + return (0); + } + else + { + double n; /* Number */ + char *units; /* Units */ + + n = strtod(value, &units); + + if (units && *units) + { + if (tolower(units[0] & 255) == 'w') + n *= 7 * 24 * 60 * 60; + else if (tolower(units[0] & 255) == 'd') + n *= 24 * 60 * 60; + else if (tolower(units[0] & 255) == 'h') + n *= 60 * 60; + else if (tolower(units[0] & 255) == 'm') + n *= 60; + else + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unknown time interval value for %s on line " + "%d of %s.", line, linenum, filename); + return (0); + } + } + + if (n < 0.0 || n > INT_MAX) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Bad time value for %s on line %d of %s.", + line, linenum, filename); + return (0); + } + else + { + *((int *)var->ptr) = (int)n; + } + } + break; + + case CUPSD_VARTYPE_BOOLEAN : + if (!value) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Missing boolean value for %s on line %d of %s.", + line, linenum, filename); + return (0); + } + else if (!_cups_strcasecmp(value, "true") || + !_cups_strcasecmp(value, "on") || + !_cups_strcasecmp(value, "enabled") || + !_cups_strcasecmp(value, "yes") || + atoi(value) != 0) + { + *((int *)var->ptr) = TRUE; + } + else if (!_cups_strcasecmp(value, "false") || + !_cups_strcasecmp(value, "off") || + !_cups_strcasecmp(value, "disabled") || + !_cups_strcasecmp(value, "no") || + !_cups_strcasecmp(value, "0")) + { + *((int *)var->ptr) = FALSE; + } + else + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unknown boolean value %s on line %d of %s.", + value, linenum, filename); + return (0); + } + break; + + case CUPSD_VARTYPE_PATHNAME : + if (!value) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Missing pathname value for %s on line %d of %s.", + line, linenum, filename); + return (0); + } + + if (value[0] == '/') + strlcpy(temp, value, sizeof(temp)); + else + snprintf(temp, sizeof(temp), "%s/%s", ServerRoot, value); + + if (access(temp, 0)) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "File or directory for \"%s %s\" on line %d of %s " + "does not exist.", line, value, linenum, filename); + return (0); + } + + cupsdSetString((char **)var->ptr, temp); + break; + + case CUPSD_VARTYPE_STRING : + cupsdSetString((char **)var->ptr, value); + break; + } + + return (1); +} + + +/* + * 'read_cupsd_conf()' - Read the cupsd.conf configuration file. + */ + +static int /* O - 1 on success, 0 on failure */ +read_cupsd_conf(cups_file_t *fp) /* I - File to read from */ { - int i; /* Looping var */ int linenum; /* Current line number */ char line[HTTP_MAX_BUFFER], /* Line from file */ temp[HTTP_MAX_BUFFER], /* Temporary buffer for value */ - *ptr, /* Pointer into line/temp */ *value, /* Pointer to value */ *valueptr; /* Pointer into value */ int valuelen; /* Length of value */ - cupsd_var_t const *var; /* Current variable */ http_addrlist_t *addrlist, /* Address list */ *addr; /* Current address */ - unsigned ip[4], /* Address value */ - mask[4]; /* Netmask value */ - cupsd_dirsvc_relay_t *relay; /* Relay data */ - cupsd_dirsvc_poll_t *pollp; /* Polling data */ - cupsd_location_t *location; /* Browse location */ cups_file_t *incfile; /* Include file */ char incname[1024]; /* Include filename */ - struct group *group; /* Group */ /* @@ -2562,7 +2901,7 @@ read_configuration(cups_file_t *fp) /* I - File to read from */ incname, strerror(errno)); else { - read_configuration(incfile); + read_cupsd_conf(incfile); cupsFileClose(incfile); } } @@ -2586,8 +2925,6 @@ read_configuration(cups_file_t *fp) /* I - File to read from */ if (linenum == 0) return (0); } - else if (!_cups_strcasecmp(line, "FatalErrors")) - FatalErrors = parse_fatal_errors(value); else if (!_cups_strcasecmp(line, "FaxRetryInterval") && value) { JobRetryInterval = atoi(value); @@ -2711,117 +3048,12 @@ read_configuration(cups_file_t *fp) /* I - File to read from */ httpAddrFreeList(addrlist); } - else if (!_cups_strcasecmp(line, "BrowseAddress") && value) - { - /* - * Add a browse address to the list... - */ - - cupsd_dirsvc_addr_t *dira; /* New browse address array */ - - - if (NumBrowsers == 0) - dira = malloc(sizeof(cupsd_dirsvc_addr_t)); - else - dira = realloc(Browsers, (NumBrowsers + 1) * sizeof(cupsd_dirsvc_addr_t)); - - if (!dira) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to allocate BrowseAddress at line %d - %s.", - linenum, strerror(errno)); - continue; - } - - Browsers = dira; - dira += NumBrowsers; - - memset(dira, 0, sizeof(cupsd_dirsvc_addr_t)); - - if (!_cups_strcasecmp(value, "@LOCAL")) - { - /* - * Send browse data to all local interfaces... - */ - - strcpy(dira->iface, "*"); - NumBrowsers ++; - } - else if (!_cups_strncasecmp(value, "@IF(", 4)) - { - /* - * Send browse data to the named interface... - */ - - strlcpy(dira->iface, value + 4, sizeof(Browsers[0].iface)); - - ptr = dira->iface + strlen(dira->iface) - 1; - if (*ptr == ')') - *ptr = '\0'; - - NumBrowsers ++; - } - else if ((addrlist = get_address(value, BrowsePort)) != NULL) - { - /* - * Only IPv4 addresses are supported... - */ - - for (addr = addrlist; addr; addr = addr->next) - if (_httpAddrFamily(&(addr->addr)) == AF_INET) - break; - - if (addr) - { - memcpy(&(dira->to), &(addrlist->addr), sizeof(dira->to)); - httpAddrString(&(dira->to), temp, sizeof(temp)); - - cupsdLogMessage(CUPSD_LOG_INFO, - "Sending browsing info to %s:%d (IPv4)", - temp, _httpAddrPort(&(dira->to))); - - NumBrowsers ++; - } - else - cupsdLogMessage(CUPSD_LOG_ERROR, "Bad BrowseAddress %s at line %d.", - value, linenum); - - httpAddrFreeList(addrlist); - } - else - cupsdLogMessage(CUPSD_LOG_ERROR, "Bad BrowseAddress %s at line %d.", - value, linenum); - } - else if (!_cups_strcasecmp(line, "BrowseOrder") && value) - { - /* - * "BrowseOrder Deny,Allow" or "BrowseOrder Allow,Deny"... - */ - - if ((location = cupsdFindLocation("CUPS_INTERNAL_BROWSE_ACL")) == NULL) - if ((location = cupsdNewLocation("CUPS_INTERNAL_BROWSE_ACL")) != NULL) - cupsdAddLocation(location); - - if (location == NULL) - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to initialize browse access control list."); - else if (!_cups_strncasecmp(value, "deny", 4)) - location->order_type = CUPSD_AUTH_ALLOW; - else if (!_cups_strncasecmp(value, "allow", 5)) - location->order_type = CUPSD_AUTH_DENY; - else - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unknown BrowseOrder value %s on line %d.", - value, linenum); - } else if (!_cups_strcasecmp(line, "BrowseProtocols") || - !_cups_strcasecmp(line, "BrowseLocalProtocols") || - !_cups_strcasecmp(line, "BrowseRemoteProtocols")) + !_cups_strcasecmp(line, "BrowseLocalProtocols")) { /* * "BrowseProtocols name [... name]" * "BrowseLocalProtocols name [... name]" - * "BrowseRemoteProtocols name [... name]" */ int protocols = parse_protocols(value); @@ -2834,367 +3066,7 @@ read_configuration(cups_file_t *fp) /* I - File to read from */ break; } - if (_cups_strcasecmp(line, "BrowseLocalProtocols")) - BrowseRemoteProtocols = protocols; - if (_cups_strcasecmp(line, "BrowseRemoteProtocols")) - BrowseLocalProtocols = protocols; - } - else if ((!_cups_strcasecmp(line, "BrowseAllow") || - !_cups_strcasecmp(line, "BrowseDeny")) && value) - { - /* - * BrowseAllow [From] host/ip... - * BrowseDeny [From] host/ip... - */ - - if ((location = cupsdFindLocation("CUPS_INTERNAL_BROWSE_ACL")) == NULL) - if ((location = cupsdNewLocation("CUPS_INTERNAL_BROWSE_ACL")) != NULL) - cupsdAddLocation(location); - - - if (location == NULL) - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to initialize browse access control list."); - else - { - if (!_cups_strncasecmp(value, "from", 4)) - { - /* - * Skip leading "from"... - */ - - value += 4; - } - - while (*value) - { - /* - * Skip leading whitespace... - */ - - while (_cups_isspace(*value)) - value ++; - - if (!*value) - break; - - /* - * Find the end of the value... - */ - - for (valueptr = value; - *valueptr && !_cups_isspace(*valueptr); - valueptr ++); - - while (_cups_isspace(*valueptr)) - *valueptr++ = '\0'; - - /* - * Figure out what form the allow/deny address takes: - * - * All - * None - * *.domain.com - * .domain.com - * host.domain.com - * nnn.* - * nnn.nnn.* - * nnn.nnn.nnn.* - * nnn.nnn.nnn.nnn - * nnn.nnn.nnn.nnn/mm - * nnn.nnn.nnn.nnn/mmm.mmm.mmm.mmm - */ - - if (!_cups_strcasecmp(value, "all")) - { - /* - * All hosts... - */ - - if (!_cups_strcasecmp(line, "BrowseAllow")) - cupsdAddIPMask(&(location->allow), zeros, zeros); - else - cupsdAddIPMask(&(location->deny), zeros, zeros); - } - else if (!_cups_strcasecmp(value, "none")) - { - /* - * No hosts... - */ - - if (!_cups_strcasecmp(line, "BrowseAllow")) - cupsdAddIPMask(&(location->allow), ones, zeros); - else - cupsdAddIPMask(&(location->deny), ones, zeros); - } -#ifdef AF_INET6 - else if (value[0] == '*' || value[0] == '.' || - (!isdigit(value[0] & 255) && value[0] != '[')) -#else - else if (value[0] == '*' || value[0] == '.' || - !isdigit(value[0] & 255)) -#endif /* AF_INET6 */ - { - /* - * Host or domain name... - */ - - if (!_cups_strcasecmp(line, "BrowseAllow")) - cupsdAddNameMask(&(location->allow), value); - else - cupsdAddNameMask(&(location->deny), value); - } - else - { - /* - * One of many IP address forms... - */ - - if (!get_addr_and_mask(value, ip, mask)) - { - cupsdLogMessage(CUPSD_LOG_ERROR, "Bad netmask value %s on line %d.", - value, linenum); - break; - } - - if (!_cups_strcasecmp(line, "BrowseAllow")) - cupsdAddIPMask(&(location->allow), ip, mask); - else - cupsdAddIPMask(&(location->deny), ip, mask); - } - - /* - * Advance to next value... - */ - - value = valueptr; - } - } - } - else if (!_cups_strcasecmp(line, "BrowseRelay") && value) - { - /* - * BrowseRelay [from] source [to] destination - */ - - if (NumRelays == 0) - relay = malloc(sizeof(cupsd_dirsvc_relay_t)); - else - relay = realloc(Relays, (NumRelays + 1) * sizeof(cupsd_dirsvc_relay_t)); - - if (!relay) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to allocate BrowseRelay at line %d - %s.", - linenum, strerror(errno)); - continue; - } - - Relays = relay; - relay += NumRelays; - - memset(relay, 0, sizeof(cupsd_dirsvc_relay_t)); - - if (!_cups_strncasecmp(value, "from ", 5)) - { - /* - * Skip leading "from"... - */ - - value += 5; - - /* - * Skip leading whitespace... - */ - - while (_cups_isspace(*value)) - value ++; - } - - /* - * Find the end of the from value... - */ - - for (valueptr = value; - *valueptr && !_cups_isspace(*valueptr); - valueptr ++); - - while (_cups_isspace(*valueptr)) - *valueptr++ = '\0'; - - /* - * Figure out what form the from address takes: - * - * *.domain.com - * .domain.com - * host.domain.com - * nnn.* - * nnn.nnn.* - * nnn.nnn.nnn.* - * nnn.nnn.nnn.nnn - * nnn.nnn.nnn.nnn/mm - * nnn.nnn.nnn.nnn/mmm.mmm.mmm.mmm - */ - -#ifdef AF_INET6 - if (value[0] == '*' || value[0] == '.' || - (!isdigit(value[0] & 255) && value[0] != '[')) -#else - if (value[0] == '*' || value[0] == '.' || !isdigit(value[0] & 255)) -#endif /* AF_INET6 */ - { - /* - * Host or domain name... - */ - - if (!cupsdAddNameMask(&(relay->from), value)) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to allocate BrowseRelay name at line %d - %s.", - linenum, strerror(errno)); - continue; - } - } - else - { - /* - * One of many IP address forms... - */ - - if (!get_addr_and_mask(value, ip, mask)) - { - cupsdLogMessage(CUPSD_LOG_ERROR, "Bad netmask value %s on line %d.", - value, linenum); - break; - } - - if (!cupsdAddIPMask(&(relay->from), ip, mask)) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to allocate BrowseRelay IP at line %d - %s.", - linenum, strerror(errno)); - continue; - } - } - - /* - * Get "to" address and port... - */ - - if (!_cups_strncasecmp(valueptr, "to ", 3)) - { - /* - * Strip leading "to"... - */ - - valueptr += 3; - - while (_cups_isspace(*valueptr)) - valueptr ++; - } - - if ((addrlist = get_address(valueptr, BrowsePort)) != NULL) - { - /* - * Only IPv4 addresses are supported... - */ - - for (addr = addrlist; addr; addr = addr->next) - if (addr->addr.addr.sa_family == AF_INET) - break; - - if (addr) - { - memcpy(&(relay->to), &(addrlist->addr), sizeof(relay->to)); - - httpAddrString(&(relay->to), temp, sizeof(temp)); - - cupsdLogMessage(CUPSD_LOG_INFO, "Relaying from %s to %s:%d (IPv4)", - value, temp, _httpAddrPort(&(relay->to))); - - NumRelays ++; - } - else - { - cupsArrayDelete(relay->from); - relay->from = NULL; - - cupsdLogMessage(CUPSD_LOG_ERROR, "Bad relay address %s at line %d.", - valueptr, linenum); - } - - httpAddrFreeList(addrlist); - } - else - { - cupsArrayDelete(relay->from); - relay->from = NULL; - - cupsdLogMessage(CUPSD_LOG_ERROR, "Bad relay address %s at line %d.", - valueptr, linenum); - } - } - else if (!_cups_strcasecmp(line, "BrowsePoll") && value) - { - /* - * BrowsePoll address[:port] - */ - - char *portname; /* Port name */ - int portnum; /* Port number */ - struct servent *service; /* Service */ - - - /* - * Extract the port name from the address... - */ - - if ((portname = strrchr(value, ':')) != NULL && !strchr(portname, ']')) - { - *portname++ = '\0'; - - if (isdigit(*portname & 255)) - portnum = atoi(portname); - else if ((service = getservbyname(portname, NULL)) != NULL) - portnum = ntohs(service->s_port); - else - { - cupsdLogMessage(CUPSD_LOG_ERROR, "Lookup of service \"%s\" failed.", - portname); - continue; - } - } - else - portnum = ippPort(); - - /* - * Add the poll entry... - */ - - if (NumPolled == 0) - pollp = malloc(sizeof(cupsd_dirsvc_poll_t)); - else - pollp = realloc(Polled, (NumPolled + 1) * sizeof(cupsd_dirsvc_poll_t)); - - if (!pollp) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to allocate BrowsePoll at line %d - %s.", - linenum, strerror(errno)); - continue; - } - - Polled = pollp; - pollp += NumPolled; - - NumPolled ++; - memset(pollp, 0, sizeof(cupsd_dirsvc_poll_t)); - - strlcpy(pollp->hostname, value, sizeof(pollp->hostname)); - pollp->port = portnum; - - cupsdLogMessage(CUPSD_LOG_INFO, "Polling %s:%d", pollp->hostname, - pollp->port); + BrowseLocalProtocols = protocols; } else if (!_cups_strcasecmp(line, "DefaultAuthType") && value) { @@ -3203,17 +3075,19 @@ read_configuration(cups_file_t *fp) /* I - File to read from */ */ if (!_cups_strcasecmp(value, "none")) - DefaultAuthType = CUPSD_AUTH_NONE; + default_auth_type = CUPSD_AUTH_NONE; else if (!_cups_strcasecmp(value, "basic")) - DefaultAuthType = CUPSD_AUTH_BASIC; + default_auth_type = CUPSD_AUTH_BASIC; else if (!_cups_strcasecmp(value, "digest")) - DefaultAuthType = CUPSD_AUTH_DIGEST; + default_auth_type = CUPSD_AUTH_DIGEST; else if (!_cups_strcasecmp(value, "basicdigest")) - DefaultAuthType = CUPSD_AUTH_BASICDIGEST; + default_auth_type = CUPSD_AUTH_BASICDIGEST; #ifdef HAVE_GSSAPI else if (!_cups_strcasecmp(value, "negotiate")) - DefaultAuthType = CUPSD_AUTH_NEGOTIATE; + default_auth_type = CUPSD_AUTH_NEGOTIATE; #endif /* HAVE_GSSAPI */ + else if (!_cups_strcasecmp(value, "auto")) + default_auth_type = CUPSD_AUTH_AUTO; else { cupsdLogMessage(CUPSD_LOG_WARN, @@ -3246,81 +3120,6 @@ read_configuration(cups_file_t *fp) /* I - File to read from */ } } #endif /* HAVE_SSL */ - else if (!_cups_strcasecmp(line, "User") && value) - { - /* - * User ID to run as... - */ - - if (isdigit(value[0] & 255)) - { - int uid = atoi(value); - - if (!uid) - cupsdLogMessage(CUPSD_LOG_ERROR, - "Will not use User 0 as specified on line %d " - "for security reasons. You must use a non-" - "privileged account instead.", - linenum); - else - User = atoi(value); - } - else - { - struct passwd *p; /* Password information */ - - endpwent(); - p = getpwnam(value); - - if (p) - { - if (!p->pw_uid) - cupsdLogMessage(CUPSD_LOG_ERROR, - "Will not use User %s (UID=0) as specified on line " - "%d for security reasons. You must use a non-" - "privileged account instead.", - value, linenum); - else - User = p->pw_uid; - } - else - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unknown User \"%s\" on line %d, ignoring.", - value, linenum); - } - } - else if (!_cups_strcasecmp(line, "Group") && value) - { - /* - * Group ID to run as... - */ - - if (isdigit(value[0])) - Group = atoi(value); - else - { - endgrent(); - group = getgrnam(value); - - if (group != NULL) - Group = group->gr_gid; - else - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unknown Group \"%s\" on line %d, ignoring.", - value, linenum); - } - } - else if (!_cups_strcasecmp(line, "SystemGroup") && value) - { - /* - * SystemGroup (admin) group(s)... - */ - - if (!parse_groups(value)) - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unknown SystemGroup \"%s\" on line %d, ignoring.", - value, linenum); - } else if (!_cups_strcasecmp(line, "HostNameLookups") && value) { /* @@ -3399,22 +3198,6 @@ read_configuration(cups_file_t *fp) /* I - File to read from */ cupsdLogMessage(CUPSD_LOG_WARN, "Unknown LogTimeFormat %s on line %d.", value, linenum); } - else if (!_cups_strcasecmp(line, "PrintcapFormat") && value) - { - /* - * Format of printcap file? - */ - - if (!_cups_strcasecmp(value, "bsd")) - PrintcapFormat = PRINTCAP_BSD; - else if (!_cups_strcasecmp(value, "plist")) - PrintcapFormat = PRINTCAP_PLIST; - else if (!_cups_strcasecmp(value, "solaris")) - PrintcapFormat = PRINTCAP_SOLARIS; - else - cupsdLogMessage(CUPSD_LOG_WARN, "Unknown PrintcapFormat %s on line %d.", - value, linenum); - } else if (!_cups_strcasecmp(line, "ServerTokens") && value) { /* @@ -3427,19 +3210,20 @@ read_configuration(cups_file_t *fp) /* I - File to read from */ uname(&plat); if (!_cups_strcasecmp(value, "ProductOnly")) - cupsdSetString(&ServerHeader, "CUPS"); + cupsdSetString(&ServerHeader, "CUPS IPP"); else if (!_cups_strcasecmp(value, "Major")) - cupsdSetStringf(&ServerHeader, "CUPS/%d", CUPS_VERSION_MAJOR); + cupsdSetStringf(&ServerHeader, "CUPS/%d IPP/2", CUPS_VERSION_MAJOR); else if (!_cups_strcasecmp(value, "Minor")) - cupsdSetStringf(&ServerHeader, "CUPS/%d.%d", CUPS_VERSION_MAJOR, + cupsdSetStringf(&ServerHeader, "CUPS/%d.%d IPP/2.1", CUPS_VERSION_MAJOR, CUPS_VERSION_MINOR); else if (!_cups_strcasecmp(value, "Minimal")) - cupsdSetString(&ServerHeader, CUPS_MINIMAL); + cupsdSetString(&ServerHeader, CUPS_MINIMAL " IPP/2.1"); else if (!_cups_strcasecmp(value, "OS")) - cupsdSetStringf(&ServerHeader, CUPS_MINIMAL " (%s)", plat.sysname); + cupsdSetStringf(&ServerHeader, CUPS_MINIMAL " (%s %s) IPP/2.1", + plat.sysname, plat.release); else if (!_cups_strcasecmp(value, "Full")) - cupsdSetStringf(&ServerHeader, CUPS_MINIMAL " (%s) IPP/2.1", - plat.sysname); + cupsdSetStringf(&ServerHeader, CUPS_MINIMAL " (%s %s; %s) IPP/2.1", + plat.sysname, plat.release, plat.machine); else if (!_cups_strcasecmp(value, "None")) cupsdClearString(&ServerHeader); else @@ -3540,117 +3324,193 @@ read_configuration(cups_file_t *fp) /* I - File to read from */ "line %d.", value, linenum); } #endif /* HAVE_SSL */ + else if (!_cups_strcasecmp(line, "AccessLog") || + !_cups_strcasecmp(line, "CacheDir") || + !_cups_strcasecmp(line, "ConfigFilePerm") || + !_cups_strcasecmp(line, "DataDir") || + !_cups_strcasecmp(line, "DocumentRoot") || + !_cups_strcasecmp(line, "ErrorLog") || + !_cups_strcasecmp(line, "FatalErrors") || + !_cups_strcasecmp(line, "FileDevice") || + !_cups_strcasecmp(line, "FontPath") || + !_cups_strcasecmp(line, "Group") || + !_cups_strcasecmp(line, "LogFilePerm") || + !_cups_strcasecmp(line, "LPDConfigFile") || + !_cups_strcasecmp(line, "PageLog") || + !_cups_strcasecmp(line, "Printcap") || + !_cups_strcasecmp(line, "PrintcapFormat") || + !_cups_strcasecmp(line, "RemoteRoot") || + !_cups_strcasecmp(line, "RequestRoot") || + !_cups_strcasecmp(line, "ServerBin") || + !_cups_strcasecmp(line, "ServerCertificate") || + !_cups_strcasecmp(line, "ServerKey") || + !_cups_strcasecmp(line, "ServerRoot") || + !_cups_strcasecmp(line, "SMBConfigFile") || + !_cups_strcasecmp(line, "StateDir") || + !_cups_strcasecmp(line, "SystemGroup") || + !_cups_strcasecmp(line, "SystemGroupAuthKey") || + !_cups_strcasecmp(line, "TempDir") || + !_cups_strcasecmp(line, "User")) + { + cupsdLogMessage(CUPSD_LOG_INFO, + "Please move \"%s%s%s\" on line %d of %s to the %s file; " + "this will become an error in a future release.", + line, value ? " " : "", value ? value : "", linenum, + ConfigurationFile, CupsFilesFile); + } else + parse_variable(ConfigurationFile, linenum, line, value, + sizeof(cupsd_vars) / sizeof(cupsd_vars[0]), cupsd_vars); + } + + return (1); +} + + +/* + * 'read_cups_files_conf()' - Read the cups-files.conf configuration file. + */ + +static int /* O - 1 on success, 0 on failure */ +read_cups_files_conf(cups_file_t *fp) /* I - File to read from */ +{ + int linenum; /* Current line number */ + char line[HTTP_MAX_BUFFER], /* Line from file */ + *value; /* Value from line */ + struct group *group; /* Group */ + + + /* + * Loop through each line in the file... + */ + + linenum = 0; + + while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum)) + { + if (!_cups_strcasecmp(line, "FatalErrors")) + FatalErrors = parse_fatal_errors(value); + else if (!_cups_strcasecmp(line, "Group") && value) { /* - * Find a simple variable in the list... + * Group ID to run as... */ - for (i = NUM_VARS, var = variables; i > 0; i --, var ++) - if (!_cups_strcasecmp(line, var->name)) - break; - - if (i == 0) + if (isdigit(value[0])) + Group = atoi(value); + else { - /* - * Unknown directive! Output an error message and continue... - */ + endgrent(); + group = getgrnam(value); - if (!value) - cupsdLogMessage(CUPSD_LOG_ERROR, "Missing value for %s on line %d.", - line, linenum); + if (group != NULL) + Group = group->gr_gid; else - cupsdLogMessage(CUPSD_LOG_ERROR, "Unknown directive %s on line %d.", - line, linenum); - continue; + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unknown Group \"%s\" on line %d of %s.", value, + linenum, CupsFilesFile); + if (FatalErrors & CUPSD_FATAL_CONFIG) + return (0); + } } + } + else if (!_cups_strcasecmp(line, "PrintcapFormat") && value) + { + /* + * Format of printcap file? + */ - switch (var->type) + if (!_cups_strcasecmp(value, "bsd")) + PrintcapFormat = PRINTCAP_BSD; + else if (!_cups_strcasecmp(value, "plist")) + PrintcapFormat = PRINTCAP_PLIST; + else if (!_cups_strcasecmp(value, "solaris")) + PrintcapFormat = PRINTCAP_SOLARIS; + else { - case CUPSD_VARTYPE_INTEGER : - if (!value) - cupsdLogMessage(CUPSD_LOG_ERROR, - "Missing integer value for %s on line %d.", - line, linenum); - else - { - int n; /* Number */ - char *units; /* Units */ - - - n = strtol(value, &units, 0); - - if (units && *units) - { - if (tolower(units[0] & 255) == 'g') - n *= 1024 * 1024 * 1024; - else if (tolower(units[0] & 255) == 'm') - n *= 1024 * 1024; - else if (tolower(units[0] & 255) == 'k') - n *= 1024; - else if (tolower(units[0] & 255) == 't') - n *= 262144; - } - - if (n < 0) - cupsdLogMessage(CUPSD_LOG_ERROR, - "Bad negative integer value for %s on line %d.", - line, linenum); - else - *((int *)var->ptr) = n; - } - break; + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unknown PrintcapFormat \"%s\" on line %d of %s.", + value, linenum, CupsFilesFile); + if (FatalErrors & CUPSD_FATAL_CONFIG) + return (0); + } + } + else if (!_cups_strcasecmp(line, "SystemGroup") && value) + { + /* + * SystemGroup (admin) group(s)... + */ - case CUPSD_VARTYPE_BOOLEAN : - if (!value) - cupsdLogMessage(CUPSD_LOG_ERROR, - "Missing boolean value for %s on line %d.", - line, linenum); - else if (!_cups_strcasecmp(value, "true") || - !_cups_strcasecmp(value, "on") || - !_cups_strcasecmp(value, "enabled") || - !_cups_strcasecmp(value, "yes") || - atoi(value) != 0) - *((int *)var->ptr) = TRUE; - else if (!_cups_strcasecmp(value, "false") || - !_cups_strcasecmp(value, "off") || - !_cups_strcasecmp(value, "disabled") || - !_cups_strcasecmp(value, "no") || - !_cups_strcasecmp(value, "0")) - *((int *)var->ptr) = FALSE; - else - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unknown boolean value %s on line %d.", - value, linenum); - break; + if (!parse_groups(value)) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unknown SystemGroup \"%s\" on line %d of %s.", value, + linenum, CupsFilesFile); + if (FatalErrors & CUPSD_FATAL_CONFIG) + return (0); + } + } + else if (!_cups_strcasecmp(line, "User") && value) + { + /* + * User ID to run as... + */ - case CUPSD_VARTYPE_PATHNAME : - if (!value) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "Missing pathname value for %s on line %d.", - line, linenum); - break; - } + if (isdigit(value[0] & 255)) + { + int uid = atoi(value); - if (value[0] == '/') - strlcpy(temp, value, sizeof(temp)); - else - snprintf(temp, sizeof(temp), "%s/%s", ServerRoot, value); + if (!uid) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Will not use User 0 as specified on line %d of %s " + "for security reasons. You must use a non-" + "privileged account instead.", + linenum, CupsFilesFile); + if (FatalErrors & CUPSD_FATAL_CONFIG) + return (0); + } + else + User = atoi(value); + } + else + { + struct passwd *p; /* Password information */ - if (access(temp, 0)) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "File or directory for \"%s %s\" on line %d " - "does not exist.", line, value, linenum); - break; - } + endpwent(); + p = getpwnam(value); - case CUPSD_VARTYPE_STRING : - cupsdSetString((char **)var->ptr, value); - break; + if (p) + { + if (!p->pw_uid) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Will not use User %s (UID=0) as specified on line " + "%d of %s for security reasons. You must use a " + "non-privileged account instead.", + value, linenum, CupsFilesFile); + if (FatalErrors & CUPSD_FATAL_CONFIG) + return (0); + } + else + User = p->pw_uid; + } + else + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unknown User \"%s\" on line %d of %s.", + value, linenum, CupsFilesFile); + if (FatalErrors & CUPSD_FATAL_CONFIG) + return (0); + } } } + else if (!parse_variable(CupsFilesFile, linenum, line, value, + sizeof(cupsfiles_vars) / sizeof(cupsfiles_vars[0]), + cupsfiles_vars) && + (FatalErrors & CUPSD_FATAL_CONFIG)) + return (0); } return (1); @@ -3970,6 +3830,7 @@ read_policy(cups_file_t *fp, /* I - Configuration file */ cupsdAddString(&(pol->job_attrs), "job-name"); cupsdAddString(&(pol->job_attrs), "job-originating-host-name"); cupsdAddString(&(pol->job_attrs), "job-originating-user-name"); + cupsdAddString(&(pol->job_attrs), "phone"); } else cupsdAddString(&(pol->job_attrs), value); @@ -4194,6 +4055,7 @@ set_policy_defaults(cupsd_policy_t *pol)/* I - Policy */ cupsdAddString(&(pol->job_attrs), "job-name"); cupsdAddString(&(pol->job_attrs), "job-originating-host-name"); cupsdAddString(&(pol->job_attrs), "job-originating-user-name"); + cupsdAddString(&(pol->job_attrs), "phone"); } if (!pol->sub_access) @@ -4220,5 +4082,5 @@ set_policy_defaults(cupsd_policy_t *pol)/* I - Policy */ /* - * End of "$Id: conf.c 10121 2011-11-16 15:28:11Z mike $". + * End of "$Id: conf.c 11221 2013-08-06 16:16:01Z msweet $". */ diff --git a/scheduler/conf.h b/scheduler/conf.h index 0c05ced..8bf0749 100644 --- a/scheduler/conf.h +++ b/scheduler/conf.h @@ -1,9 +1,9 @@ /* - * "$Id: conf.h 9710 2011-04-22 17:47:03Z mike $" + * "$Id: conf.h 11221 2013-08-06 16:16:01Z msweet $" * * Configuration file definitions for the CUPS scheduler. * - * Copyright 2007-2011 by Apple Inc. + * Copyright 2007-2013 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -69,7 +69,7 @@ typedef enum #define PRINTCAP_BSD 0 /* Berkeley LPD format */ #define PRINTCAP_SOLARIS 1 /* Solaris lpsched format */ -#define PRINTCAP_PLIST 2 /* Mac OS X plist format */ +#define PRINTCAP_PLIST 2 /* OS X plist format */ /* @@ -96,7 +96,9 @@ typedef struct */ VAR char *ConfigurationFile VALUE(NULL), - /* Configuration file to use */ + /* cupsd.conf file to use */ + *CupsFilesFile VALUE(NULL), + /* cups-files.conf file to use */ *ServerName VALUE(NULL), /* FQDN for server */ *ServerAdmin VALUE(NULL), @@ -169,6 +171,10 @@ VAR int ClassifyOverride VALUE(0), /* Amount of automatic debug history */ FatalErrors VALUE(CUPSD_FATAL_CONFIG), /* Which errors are fatal? */ + StrictConformance VALUE(FALSE), + /* Require strict IPP conformance? */ + SyncOnClose VALUE(FALSE), + /* Call fsync() when closing files? */ LogFilePerm VALUE(0644); /* Permissions for log files */ VAR cupsd_loglevel_t LogLevel VALUE(CUPSD_LOG_WARN); @@ -193,12 +199,6 @@ VAR int MaxClients VALUE(100), /* Support the Keep-Alive option? */ KeepAliveTimeout VALUE(DEFAULT_KEEPALIVE), /* Timeout between requests */ - ImplicitClasses VALUE(TRUE), - /* Are classes implicitly created? */ - ImplicitAnyClasses VALUE(FALSE), - /* Create AnyPrinter classes? */ - HideImplicitMembers VALUE(TRUE), - /* Hide implicit class members? */ FileDevice VALUE(FALSE), /* Allow file: devices? */ FilterLimit VALUE(0), @@ -248,7 +248,7 @@ VAR int SSLOptions VALUE(CUPSD_SSL_NONE); #endif /* HAVE_SSL */ #ifdef HAVE_LAUNCHD -VAR int LaunchdTimeout VALUE(DEFAULT_KEEPALIVE); +VAR int LaunchdTimeout VALUE(10); /* Time after which an idle cupsd will exit */ #endif /* HAVE_LAUNCHD */ @@ -257,6 +257,14 @@ VAR char *SystemGroupAuthKey VALUE(NULL); /* System group auth key */ #endif /* HAVE_AUTHORIZATION_H */ +#ifdef HAVE_GSSAPI +VAR char *GSSServiceName VALUE(NULL); + /* GSS service name */ +int HaveServerCreds VALUE(0); + /* Do we have server credentials? */ +gss_cred_id_t ServerCreds; /* Server's GSS credentials */ +#endif /* HAVE_GSSAPI */ + /* * Prototypes... @@ -269,6 +277,7 @@ extern int cupsdCheckPermissions(const char *filename, int user, int group, int is_dir, int create_dir); extern int cupsdCheckProgram(const char *filename, cupsd_printer_t *p); +extern int cupsdDefaultAuthType(void); extern void cupsdFreeAliases(cups_array_t *aliases); extern char *cupsdGetDateTime(struct timeval *t, cupsd_time_t format); extern void cupsdLogFCMessage(void *context, _cups_fc_result_t result, @@ -278,16 +287,10 @@ extern int cupsdLogGSSMessage(int level, int major_status, int minor_status, const char *message, ...); #endif /* HAVE_GSSAPI */ -extern int cupsdLogJob(cupsd_job_t *job, int level, const char *message, ...) -#ifdef __GNUC__ -__attribute__ ((__format__ (__printf__, 3, 4))) -#endif /* __GNUC__ */ -; +extern int cupsdLogJob(cupsd_job_t *job, int level, const char *message, + ...) __attribute__((__format__(__printf__, 3, 4))); extern int cupsdLogMessage(int level, const char *message, ...) -#ifdef __GNUC__ -__attribute__ ((__format__ (__printf__, 2, 3))) -#endif /* __GNUC__ */ -; + __attribute__ ((__format__ (__printf__, 2, 3))); extern int cupsdLogPage(cupsd_job_t *job, const char *page); extern int cupsdLogRequest(cupsd_client_t *con, http_status_t code); extern int cupsdReadConfiguration(void); @@ -295,5 +298,5 @@ extern int cupsdWriteErrorLog(int level, const char *message); /* - * End of "$Id: conf.h 9710 2011-04-22 17:47:03Z mike $". + * End of "$Id: conf.h 11221 2013-08-06 16:16:01Z msweet $". */ diff --git a/scheduler/cups-deviced.c b/scheduler/cups-deviced.c index aa06ed3..7a5929f 100644 --- a/scheduler/cups-deviced.c +++ b/scheduler/cups-deviced.c @@ -1,5 +1,5 @@ /* - * "$Id: cups-deviced.c 9793 2011-05-20 03:49:49Z mike $" + * "$Id: cups-deviced.c 11173 2013-07-23 12:31:34Z msweet $" * * Device scanning mini-daemon for CUPS. * @@ -806,5 +806,5 @@ start_backend(const char *name, /* I - Backend to run */ /* - * End of "$Id: cups-deviced.c 9793 2011-05-20 03:49:49Z mike $". + * End of "$Id: cups-deviced.c 11173 2013-07-23 12:31:34Z msweet $". */ diff --git a/scheduler/cups-driverd.cxx b/scheduler/cups-driverd.cxx index 8500031..4a3d34f 100644 --- a/scheduler/cups-driverd.cxx +++ b/scheduler/cups-driverd.cxx @@ -1,5 +1,5 @@ /* - * "$Id: cups-driverd.cxx 10276 2012-02-13 22:48:22Z mike $" + * "$Id: cups-driverd.cxx 11173 2013-07-23 12:31:34Z msweet $" * * PPD/driver support for CUPS. * @@ -18,26 +18,31 @@ * * Contents: * - * main() - Scan for drivers and return an IPP response. - * add_ppd() - Add a PPD file. - * cat_drv() - Generate a PPD from a driver info file. - * cat_ppd() - Copy a PPD file to stdout. + * main() - Scan for drivers and return an IPP response. + * add_ppd() - Add a PPD file. + * cat_drv() - Generate a PPD from a driver info file. + * cat_ppd() - Copy a PPD file to stdout. * copy_static() - Copy a static PPD file to stdout. + * cat_tar() - Copy an archived PPD file to stdout. * compare_inodes() - Compare two inodes. * compare_matches() - Compare PPD match scores for sorting. * compare_names() - Compare PPD filenames for sorting. * compare_ppds() - Compare PPD file make and model names for sorting. * dump_ppds_dat() - Dump the contents of the ppds.dat file. * free_array() - Free an array of strings. + * get_file() - Get the filename associated with a request. * list_ppds() - List PPD files. * load_drv() - Load the PPDs from a driver information file. * load_drivers() - Load driver-generated PPD files. + * load_ppd() - Load a PPD file. * load_ppds() - Load PPD files recursively. * load_ppds_dat() - Load the ppds.dat file. + * load_tar() - Load archived PPD files. + * read_tar() - Read a file header from an archive. * regex_device_id() - Compile a regular expression based on the 1284 device - * ID. + * ID. * regex_string() - Construct a regular expression to compare a simple - * string. + * string. */ /* @@ -67,16 +72,23 @@ #define PPD_TYPE_FAX 3 /* Facsimile/MFD PPD */ #define PPD_TYPE_UNKNOWN 4 /* Other/hybrid PPD */ #define PPD_TYPE_DRV 5 /* Driver info file */ +#define PPD_TYPE_ARCHIVE 6 /* Archive file */ -static const char * const ppd_types[] = /* ppd-type values */ -{ - "postscript", - "pdf", - "raster", - "fax", - "unknown", - "drv" -}; +#define TAR_BLOCK 512 /* Number of bytes in a block */ +#define TAR_BLOCKS 10 /* Blocking factor */ + +#define TAR_MAGIC "ustar" /* 5 chars and a null */ +#define TAR_VERSION "00" /* POSIX tar version */ + +#define TAR_OLDNORMAL '\0' /* Normal disk file, Unix compat */ +#define TAR_NORMAL '0' /* Normal disk file */ +#define TAR_LINK '1' /* Link to previously dumped file */ +#define TAR_SYMLINK '2' /* Symbolic link */ +#define TAR_CHR '3' /* Character special file */ +#define TAR_BLK '4' /* Block special file */ +#define TAR_DIR '5' /* Directory */ +#define TAR_FIFO '6' /* FIFO special file */ +#define TAR_CONTIG '7' /* Contiguous file */ /* @@ -110,15 +122,51 @@ typedef struct /**** In-memory record ****/ ppd_rec_t record; /* PPDs.dat record */ } ppd_info_t; +typedef union /**** TAR record format ****/ +{ + unsigned char all[TAR_BLOCK]; /* Raw data block */ + struct + { + char pathname[100], /* Destination path */ + mode[8], /* Octal file permissions */ + uid[8], /* Octal user ID */ + gid[8], /* Octal group ID */ + size[12], /* Octal size in bytes */ + mtime[12], /* Octal modification time */ + chksum[8], /* Octal checksum value */ + linkflag, /* File type */ + linkname[100], /* Source path for link */ + magic[6], /* Magic string */ + version[2], /* Format version */ + uname[32], /* User name */ + gname[32], /* Group name */ + devmajor[8], /* Octal device major number */ + devminor[8], /* Octal device minor number */ + prefix[155]; /* Prefix for long filenames */ + } header; +} tar_rec_t; + /* * Globals... */ -cups_array_t *Inodes = NULL, /* Inodes of directories we've visited */ - *PPDsByName = NULL, /* PPD files sorted by filename and name */ - *PPDsByMakeModel = NULL;/* PPD files sorted by make and model */ -int ChangedPPD; /* Did we change the PPD database? */ +static cups_array_t *Inodes = NULL, /* Inodes of directories we've visited */ + *PPDsByName = NULL, + /* PPD files sorted by filename and name */ + *PPDsByMakeModel = NULL; + /* PPD files sorted by make and model */ +static int ChangedPPD; /* Did we change the PPD database? */ +static const char * const PPDTypes[] = /* ppd-type values */ + { + "postscript", + "pdf", + "raster", + "fax", + "unknown", + "drv", + "archive" + }; /* @@ -135,6 +183,7 @@ static ppd_info_t *add_ppd(const char *filename, const char *name, static int cat_drv(const char *name, int request_id); static int cat_ppd(const char *name, int request_id); static int cat_static(const char *name, int request_id); +static int cat_tar(const char *name, int request_id); static int compare_inodes(struct stat *a, struct stat *b); static int compare_matches(const ppd_info_t *p0, const ppd_info_t *p1); @@ -142,16 +191,26 @@ static int compare_names(const ppd_info_t *p0, const ppd_info_t *p1); static int compare_ppds(const ppd_info_t *p0, const ppd_info_t *p1); -static int dump_ppds_dat(void); +static int dump_ppds_dat(const char *filename); static void free_array(cups_array_t *a); +static cups_file_t *get_file(const char *name, int request_id, + const char *subdir, char *buffer, + size_t bufsize, char **subfile); static int list_ppds(int request_id, int limit, const char *opt); static int load_drivers(cups_array_t *include, cups_array_t *exclude); static int load_drv(const char *filename, const char *name, cups_file_t *fp, time_t mtime, off_t size); +static void load_ppd(const char *filename, const char *name, + const char *scheme, struct stat *fileinfo, + ppd_info_t *ppd, cups_file_t *fp, off_t end); static int load_ppds(const char *d, const char *p, int descend); static void load_ppds_dat(char *filename, size_t filesize, int verbose); +static int load_tar(const char *filename, const char *name, + cups_file_t *fp, time_t mtime, off_t size); +static int read_tar(cups_file_t *fp, char *name, size_t namesize, + struct stat *info); static regex_t *regex_device_id(const char *device_id); static regex_t *regex_string(const char *s); @@ -174,8 +233,8 @@ main(int argc, /* I - Number of command-line args */ if (argc == 3 && !strcmp(argv[1], "cat")) return (cat_ppd(argv[2], 0)); - else if (argc == 2 && !strcmp(argv[1], "dump")) - return (dump_ppds_dat()); + else if ((argc == 2 || argc == 3) && !strcmp(argv[1], "dump")) + return (dump_ppds_dat(argv[2])); else if (argc == 4 && !strcmp(argv[1], "get")) return (cat_ppd(argv[3], atoi(argv[2]))); else if (argc == 5 && !strcmp(argv[1], "list")) @@ -281,7 +340,7 @@ static int /* O - Exit code */ cat_drv(const char *name, /* I - PPD name */ int request_id) /* I - Request ID for response? */ { - const char *datadir; // CUPS_DATADIR env var + cups_file_t *fp; // File pointer ppdcSource *src; // PPD source file data ppdcDriver *d; // Current driver cups_file_t *out; // Stdout via CUPS file API @@ -295,23 +354,16 @@ cat_drv(const char *name, /* I - PPD name */ int port; // Port number (unused) - // Determine where CUPS has installed the data files... - if ((datadir = getenv("CUPS_DATADIR")) == NULL) - datadir = CUPS_DATADIR; - // Pull out the path to the .drv file... if (httpSeparateURI(HTTP_URI_CODING_ALL, name, scheme, sizeof(scheme), userpass, sizeof(userpass), host, sizeof(host), &port, - resource, sizeof(resource)) < HTTP_URI_OK || - strstr(resource, "../") || - (pc_file_name = strrchr(resource, '/')) == NULL || - pc_file_name == resource) + resource, sizeof(resource)) < HTTP_URI_OK) { - fprintf(stderr, "ERROR: Bad PPD name \"%s\"!\n", name); + fprintf(stderr, "ERROR: Bad PPD name \"%s\".\n", name); if (request_id) { - snprintf(message, sizeof(message), "Bad PPD name \"%s\"!", name); + snprintf(message, sizeof(message), "Bad PPD name \"%s\".", name); cupsdSendIPPHeader(IPP_NOT_FOUND, request_id); cupsdSendIPPGroup(IPP_TAG_OPERATION); @@ -325,21 +377,11 @@ cat_drv(const char *name, /* I - PPD name */ return (1); } - *pc_file_name++ = '\0'; - -#ifdef __APPLE__ - if (!strncmp(resource, "/Library/Printers/PPDs/Contents/Resources/", 42) || - !strncmp(resource, "/System/Library/Printers/PPDs/Contents/Resources/", 49)) - strlcpy(filename, resource, sizeof(filename)); - else -#endif // __APPLE__ - { - snprintf(filename, sizeof(filename), "%s/drv%s", datadir, resource); - if (access(filename, 0)) - snprintf(filename, sizeof(filename), "%s/model%s", datadir, resource); - } + if ((fp = get_file(resource, request_id, "drv", filename, sizeof(filename), + &pc_file_name)) == NULL) + return (1); - src = new ppdcSource(filename); + src = new ppdcSource(filename, fp); for (d = (ppdcDriver *)src->drivers->first(); d; @@ -387,11 +429,11 @@ cat_drv(const char *name, /* I - PPD name */ } else { - fprintf(stderr, "ERROR: PPD \"%s\" not found!\n", name); + fprintf(stderr, "ERROR: PPD \"%s\" not found.\n", name); if (request_id) { - snprintf(message, sizeof(message), "PPD \"%s\" not found!", name); + snprintf(message, sizeof(message), "PPD \"%s\" not found.", name); cupsdSendIPPHeader(IPP_NOT_FOUND, request_id); cupsdSendIPPGroup(IPP_TAG_OPERATION); @@ -404,6 +446,7 @@ cat_drv(const char *name, /* I - PPD name */ } src->release(); + cupsFileClose(fp); return (!d); } @@ -439,7 +482,12 @@ cat_ppd(const char *name, /* I - PPD name */ */ name += 5; - scheme[0] = '\0'; + + while (*name == '/') + name ++; + + if (!strstr(name, ".tar/") && !strstr(name, ".tar.gz/")) + scheme[0] = '\0'; } } else @@ -452,6 +500,8 @@ cat_ppd(const char *name, /* I - PPD name */ return (cat_static(name, request_id)); else if (!strcmp(scheme, "drv")) return (cat_drv(name, request_id)); + else if (!strcmp(scheme, "file")) + return (cat_tar(name, request_id)); else { /* @@ -540,144 +590,132 @@ cat_static(const char *name, /* I - PPD name */ int request_id) /* I - Request ID for response? */ { cups_file_t *fp; /* PPD file */ - const char *datadir; /* CUPS_DATADIR env var */ - char line[1024], /* Line/filename */ - message[2048]; /* status-message */ -#ifdef __APPLE__ - const char *printerDriver, /* Pointer to .printerDriver extension */ - *slash; /* Pointer to next slash */ -#endif /* __APPLE__ */ - - - if (name[0] == '/' || strstr(name, "../") || strstr(name, "/..")) - { - /* - * Bad name... - */ - - fprintf(stderr, "ERROR: [cups-driverd] Bad PPD name \"%s\"!\n", name); - - if (request_id) - { - snprintf(message, sizeof(message), "Bad PPD name \"%s\"!", name); + char filename[1024], /* PPD filename */ + line[1024]; /* Line buffer */ - cupsdSendIPPHeader(IPP_NOT_FOUND, request_id); - cupsdSendIPPGroup(IPP_TAG_OPERATION); - cupsdSendIPPString(IPP_TAG_CHARSET, "attributes-charset", "utf-8"); - cupsdSendIPPString(IPP_TAG_LANGUAGE, "attributes-natural-language", - "en-US"); - cupsdSendIPPString(IPP_TAG_TEXT, "status-message", message); - cupsdSendIPPTrailer(); - } + if ((fp = get_file(name, request_id, "model", filename, sizeof(filename), + NULL)) == NULL) return (1); + + if (request_id) + { + cupsdSendIPPHeader(IPP_OK, request_id); + cupsdSendIPPGroup(IPP_TAG_OPERATION); + cupsdSendIPPString(IPP_TAG_CHARSET, "attributes-charset", "utf-8"); + cupsdSendIPPString(IPP_TAG_LANGUAGE, "attributes-natural-language", + "en-US"); + cupsdSendIPPTrailer(); } /* - * Try opening the file... + * Now copy the file to stdout... */ -#ifdef __APPLE__ - if (!strncmp(name, "System/Library/Printers/PPDs/Contents/Resources/", 48) || - !strncmp(name, "Library/Printers/PPDs/Contents/Resources/", 41) || - (!strncmp(name, "System/Library/Printers/", 24) && - (printerDriver = - strstr(name + 24, - ".printerDriver/Contents/Resources/PPDs")) != NULL && - (slash = strchr(name + 24, '/')) != NULL && - slash > printerDriver) || - (!strncmp(name, "Library/Printers/", 17) && - (printerDriver = - strstr(name + 17, - ".printerDriver/Contents/Resources/PPDs")) != NULL && - (slash = strchr(name + 17, '/')) != NULL && - slash > printerDriver)) - { - /* - * Map ppd-name to Mac OS X standard locations... - */ + while (cupsFileGets(fp, line, sizeof(line))) + puts(line); - snprintf(line, sizeof(line), "/%s", name); - } - else + cupsFileClose(fp); -#elif defined(__linux) - if (!strncmp(name, "lsb/usr/", 8)) - { - /* - * Map ppd-name to LSB standard /usr/share/ppd location... - */ + return (0); +} - snprintf(line, sizeof(line), "/usr/share/ppd/%s", name + 8); - } - else if (!strncmp(name, "lsb/opt/", 8)) - { - /* - * Map ppd-name to LSB standard /opt/share/ppd location... - */ - snprintf(line, sizeof(line), "/opt/share/ppd/%s", name + 8); - } - else if (!strncmp(name, "lsb/local/", 10)) - { - /* - * Map ppd-name to LSB standard /usr/local/share/ppd location... - */ +/* + * 'cat_tar()' - Copy an archived PPD file to stdout. + */ - snprintf(line, sizeof(line), "/usr/local/share/ppd/%s", name + 10); - } - else +static int /* O - Exit code */ +cat_tar(const char *name, /* I - PPD name */ + int request_id) /* I - Request ID */ +{ + cups_file_t *fp; /* Archive file pointer */ + char filename[1024], /* Archive filename */ + *ppdname, /* PPD filename in archive */ + curname[256], /* Current name in archive */ + buffer[8192]; /* Copy buffer */ + struct stat curinfo; /* Current file info in archive */ + off_t total, /* Total bytes copied */ + next; /* Offset for next record in archive */ + ssize_t bytes; /* Bytes read */ -#endif /* __APPLE__ */ - { - if ((datadir = getenv("CUPS_DATADIR")) == NULL) - datadir = CUPS_DATADIR; - snprintf(line, sizeof(line), "%s/model/%s", datadir, name); - } + /* + * Open the archive file... + */ - if ((fp = cupsFileOpen(line, "r")) == NULL) + if ((fp = get_file(name, request_id, "model", filename, sizeof(filename), + &ppdname)) == NULL) + return (1); + + /* + * Scan the archive for the PPD... + */ + + while (read_tar(fp, curname, sizeof(curname), &curinfo)) { - fprintf(stderr, "ERROR: [cups-driverd] Unable to open \"%s\" - %s\n", - line, strerror(errno)); + next = cupsFileTell(fp) + ((curinfo.st_size + TAR_BLOCK - 1) & + ~(TAR_BLOCK - 1)); - if (request_id) + if (!strcmp(ppdname, curname)) { - snprintf(message, sizeof(message), "Unable to open \"%s\" - %s", - line, strerror(errno)); + if (request_id) + { + cupsdSendIPPHeader(IPP_OK, request_id); + cupsdSendIPPGroup(IPP_TAG_OPERATION); + cupsdSendIPPString(IPP_TAG_CHARSET, "attributes-charset", "utf-8"); + cupsdSendIPPString(IPP_TAG_LANGUAGE, "attributes-natural-language", + "en-US"); + cupsdSendIPPTrailer(); + } - cupsdSendIPPHeader(IPP_NOT_FOUND, request_id); - cupsdSendIPPGroup(IPP_TAG_OPERATION); - cupsdSendIPPString(IPP_TAG_CHARSET, "attributes-charset", "utf-8"); - cupsdSendIPPString(IPP_TAG_LANGUAGE, "attributes-natural-language", - "en-US"); - cupsdSendIPPString(IPP_TAG_TEXT, "status-message", message); - cupsdSendIPPTrailer(); + for (total = 0; total < curinfo.st_size; total += bytes) + { + if ((size_t)(bytes = (curinfo.st_size - total)) > sizeof(buffer)) + bytes = sizeof(buffer); + + if ((bytes = cupsFileRead(fp, buffer, bytes)) < 0) + { + if (errno == EINTR || errno == EAGAIN) + { + bytes = 0; + } + else + { + perror("ERROR: [cups-driverd] Read error"); + break; + } + } + else if (bytes > 0 && fwrite(buffer, bytes, 1, stdout) != 1) + break; + } + + cupsFileClose(fp); + return (0); } - return (1); + if (cupsFileTell(fp) != next) + cupsFileSeek(fp, next); } + cupsFileClose(fp); + + fprintf(stderr, "ERROR: PPD \"%s\" not found.\n", name); + if (request_id) { - cupsdSendIPPHeader(IPP_OK, request_id); + snprintf(buffer, sizeof(buffer), "PPD \"%s\" not found.", name); + + cupsdSendIPPHeader(IPP_NOT_FOUND, request_id); cupsdSendIPPGroup(IPP_TAG_OPERATION); cupsdSendIPPString(IPP_TAG_CHARSET, "attributes-charset", "utf-8"); cupsdSendIPPString(IPP_TAG_LANGUAGE, "attributes-natural-language", "en-US"); + cupsdSendIPPString(IPP_TAG_TEXT, "status-message", buffer); cupsdSendIPPTrailer(); } - /* - * Now copy the file to stdout... - */ - - while (cupsFileGets(fp, line, sizeof(line))) - puts(line); - - cupsFileClose(fp); - - return (0); + return (1); } @@ -763,9 +801,9 @@ compare_ppds(const ppd_info_t *p0, /* I - First PPD file */ */ static int /* O - Exit status */ -dump_ppds_dat(void) +dump_ppds_dat(const char *filename) /* I - Filename */ { - char filename[1024]; /* ppds.dat filename */ + char temp[1024]; /* ppds.dat filename */ ppd_info_t *ppd; /* Current PPD */ @@ -773,7 +811,12 @@ dump_ppds_dat(void) * See if we a PPD database file... */ - load_ppds_dat(filename, sizeof(filename), 0); + if (filename) + strlcpy(temp, filename, sizeof(temp)); + else + temp[0] = '\0'; + + load_ppds_dat(temp, sizeof(temp), 0); puts("mtime,size,model_number,type,filename,name,languages0,products0," "psversions0,make,make_and_model,device_id,scheme"); @@ -813,6 +856,173 @@ free_array(cups_array_t *a) /* I - Array to free */ /* + * 'get_file()' - Get the filename associated with a request. + */ + +static cups_file_t * /* O - File pointer or NULL */ +get_file(const char *name, /* I - Name */ + int request_id, /* I - Request ID */ + const char *subdir, /* I - Subdirectory for file */ + char *buffer, /* I - Filename buffer */ + size_t bufsize, /* I - Size of filename buffer */ + char **subfile) /* O - Sub-filename */ +{ + cups_file_t *fp; /* File pointer */ + const char *datadir; /* CUPS_DATADIR env var */ + char *bufptr, /* Pointer into filename buffer */ + message[2048]; /* status-message */ +#ifdef __APPLE__ + const char *printerDriver, /* Pointer to .printerDriver extension */ + *slash; /* Pointer to next slash */ +#endif /* __APPLE__ */ + + + if (subfile) + *subfile = NULL; + + while (*name == '/') + name ++; + + if (strstr(name, "../") || strstr(name, "/..")) + { + /* + * Bad name... + */ + + fprintf(stderr, "ERROR: [cups-driverd] Bad PPD name \"%s\".\n", name); + + if (request_id) + { + snprintf(message, sizeof(message), "Bad PPD name \"%s\".", name); + + cupsdSendIPPHeader(IPP_NOT_FOUND, request_id); + cupsdSendIPPGroup(IPP_TAG_OPERATION); + cupsdSendIPPString(IPP_TAG_CHARSET, "attributes-charset", "utf-8"); + cupsdSendIPPString(IPP_TAG_LANGUAGE, "attributes-natural-language", + "en-US"); + cupsdSendIPPString(IPP_TAG_TEXT, "status-message", message); + cupsdSendIPPTrailer(); + } + + return (NULL); + } + + /* + * Try opening the file... + */ + +#ifdef __APPLE__ + if (!strncmp(name, "System/Library/Printers/PPDs/Contents/Resources/", 48) || + !strncmp(name, "Library/Printers/PPDs/Contents/Resources/", 41) || + (!strncmp(name, "System/Library/Printers/", 24) && + (printerDriver = + strstr(name + 24, + ".printerDriver/Contents/Resources/PPDs")) != NULL && + (slash = strchr(name + 24, '/')) != NULL && + slash > printerDriver) || + (!strncmp(name, "Library/Printers/", 17) && + (printerDriver = + strstr(name + 17, + ".printerDriver/Contents/Resources/PPDs")) != NULL && + (slash = strchr(name + 17, '/')) != NULL && + slash > printerDriver)) + { + /* + * Map ppd-name to OS X standard locations... + */ + + snprintf(buffer, bufsize, "/%s", name); + } + else + +#elif defined(__linux) + if (!strncmp(name, "lsb/usr/", 8)) + { + /* + * Map ppd-name to LSB standard /usr/share/ppd location... + */ + + snprintf(buffer, bufsize, "/usr/share/ppd/%s", name + 8); + } + else if (!strncmp(name, "lsb/opt/", 8)) + { + /* + * Map ppd-name to LSB standard /opt/share/ppd location... + */ + + snprintf(buffer, bufsize, "/opt/share/ppd/%s", name + 8); + } + else if (!strncmp(name, "lsb/local/", 10)) + { + /* + * Map ppd-name to LSB standard /usr/local/share/ppd location... + */ + + snprintf(buffer, bufsize, "/usr/local/share/ppd/%s", name + 10); + } + else + +#endif /* __APPLE__ */ + { + if ((datadir = getenv("CUPS_DATADIR")) == NULL) + datadir = CUPS_DATADIR; + + snprintf(buffer, bufsize, "%s/%s/%s", datadir, subdir, name); + } + + /* + * Strip anything after ".drv/", ".drv.gz/", ".tar/", or ".tar.gz/"... + */ + + if (subfile) + { + if ((bufptr = strstr(buffer, ".drv/")) != NULL) + bufptr += 4; + else if ((bufptr = strstr(buffer, ".drv.gz/")) != NULL) + bufptr += 7; + else if ((bufptr = strstr(buffer, ".tar/")) != NULL) + bufptr += 4; + else if ((bufptr = strstr(buffer, ".tar.gz/")) != NULL) + bufptr += 7; + + if (bufptr) + { + *bufptr++ = '\0'; + *subfile = bufptr; + } + } + + /* + * Try opening the file... + */ + + if ((fp = cupsFileOpen(buffer, "r")) == NULL) + { + fprintf(stderr, "ERROR: [cups-driverd] Unable to open \"%s\" - %s\n", + buffer, strerror(errno)); + + if (request_id) + { + snprintf(message, sizeof(message), "Unable to open \"%s\" - %s", + buffer, strerror(errno)); + + cupsdSendIPPHeader(IPP_NOT_FOUND, request_id); + cupsdSendIPPGroup(IPP_TAG_OPERATION); + cupsdSendIPPString(IPP_TAG_CHARSET, "attributes-charset", "utf-8"); + cupsdSendIPPString(IPP_TAG_LANGUAGE, "attributes-natural-language", + "en-US"); + cupsdSendIPPString(IPP_TAG_TEXT, "status-message", message); + cupsdSendIPPTrailer(); + } + + return (NULL); + } + + return (fp); +} + + +/* * 'list_ppds()' - List PPD files. */ @@ -869,6 +1079,7 @@ list_ppds(int request_id, /* I - Request ID */ * See if we a PPD database file... */ + filename[0] = '\0'; load_ppds_dat(filename, sizeof(filename), 1); /* @@ -888,7 +1099,7 @@ list_ppds(int request_id, /* I - Request ID */ #ifdef __APPLE__ /* - * Load PPDs from standard Mac OS X locations... + * Load PPDs from standard OS X locations... */ load_ppds("/Library/Printers", @@ -1029,12 +1240,12 @@ list_ppds(int request_id, /* I - Request ID */ if (type_str) { for (type = 0; - type < (int)(sizeof(ppd_types) / sizeof(ppd_types[0])); + type < (int)(sizeof(PPDTypes) / sizeof(PPDTypes[0])); type ++) - if (!strcmp(type_str, ppd_types[type])) + if (!strcmp(type_str, PPDTypes[type])) break; - if (type >= (int)(sizeof(ppd_types) / sizeof(ppd_types[0]))) + if (type >= (int)(sizeof(PPDTypes) / sizeof(PPDTypes[0]))) { fprintf(stderr, "ERROR: [cups-driverd] Bad ppd-type=\"%s\" ignored!\n", type_str); @@ -1273,11 +1484,14 @@ list_ppds(int request_id, /* I - Request ID */ { sent_header = 1; - cupsdSendIPPHeader(IPP_OK, request_id); - cupsdSendIPPGroup(IPP_TAG_OPERATION); - cupsdSendIPPString(IPP_TAG_CHARSET, "attributes-charset", "utf-8"); - cupsdSendIPPString(IPP_TAG_LANGUAGE, "attributes-natural-language", - "en-US"); + if (request_id) + { + cupsdSendIPPHeader(IPP_OK, request_id); + cupsdSendIPPGroup(IPP_TAG_OPERATION); + cupsdSendIPPString(IPP_TAG_CHARSET, "attributes-charset", "utf-8"); + cupsdSendIPPString(IPP_TAG_LANGUAGE, "attributes-natural-language", + "en-US"); + } } fprintf(stderr, "DEBUG2: [cups-driverd] Sending %s (%s)...\n", @@ -1285,56 +1499,61 @@ list_ppds(int request_id, /* I - Request ID */ count --; - cupsdSendIPPGroup(IPP_TAG_PRINTER); + if (request_id) + { + cupsdSendIPPGroup(IPP_TAG_PRINTER); - if (send_name) - cupsdSendIPPString(IPP_TAG_NAME, "ppd-name", ppd->record.name); + if (send_name) + cupsdSendIPPString(IPP_TAG_NAME, "ppd-name", ppd->record.name); - if (send_natural_language) - { - cupsdSendIPPString(IPP_TAG_LANGUAGE, "ppd-natural-language", - ppd->record.languages[0]); + if (send_natural_language) + { + cupsdSendIPPString(IPP_TAG_LANGUAGE, "ppd-natural-language", + ppd->record.languages[0]); - for (i = 1; i < PPD_MAX_LANG && ppd->record.languages[i][0]; i ++) - cupsdSendIPPString(IPP_TAG_LANGUAGE, "", ppd->record.languages[i]); - } + for (i = 1; i < PPD_MAX_LANG && ppd->record.languages[i][0]; i ++) + cupsdSendIPPString(IPP_TAG_LANGUAGE, "", ppd->record.languages[i]); + } - if (send_make) - cupsdSendIPPString(IPP_TAG_TEXT, "ppd-make", ppd->record.make); + if (send_make) + cupsdSendIPPString(IPP_TAG_TEXT, "ppd-make", ppd->record.make); - if (send_make_and_model) - cupsdSendIPPString(IPP_TAG_TEXT, "ppd-make-and-model", - ppd->record.make_and_model); + if (send_make_and_model) + cupsdSendIPPString(IPP_TAG_TEXT, "ppd-make-and-model", + ppd->record.make_and_model); - if (send_device_id) - cupsdSendIPPString(IPP_TAG_TEXT, "ppd-device-id", - ppd->record.device_id); + if (send_device_id) + cupsdSendIPPString(IPP_TAG_TEXT, "ppd-device-id", + ppd->record.device_id); - if (send_product) - { - cupsdSendIPPString(IPP_TAG_TEXT, "ppd-product", - ppd->record.products[0]); + if (send_product) + { + cupsdSendIPPString(IPP_TAG_TEXT, "ppd-product", + ppd->record.products[0]); - for (i = 1; i < PPD_MAX_PROD && ppd->record.products[i][0]; i ++) - cupsdSendIPPString(IPP_TAG_TEXT, "", ppd->record.products[i]); - } + for (i = 1; i < PPD_MAX_PROD && ppd->record.products[i][0]; i ++) + cupsdSendIPPString(IPP_TAG_TEXT, "", ppd->record.products[i]); + } - if (send_psversion) - { - cupsdSendIPPString(IPP_TAG_TEXT, "ppd-psversion", - ppd->record.psversions[0]); + if (send_psversion) + { + cupsdSendIPPString(IPP_TAG_TEXT, "ppd-psversion", + ppd->record.psversions[0]); - for (i = 1; i < PPD_MAX_VERS && ppd->record.psversions[i][0]; i ++) - cupsdSendIPPString(IPP_TAG_TEXT, "", ppd->record.psversions[i]); - } + for (i = 1; i < PPD_MAX_VERS && ppd->record.psversions[i][0]; i ++) + cupsdSendIPPString(IPP_TAG_TEXT, "", ppd->record.psversions[i]); + } - if (send_type) - cupsdSendIPPString(IPP_TAG_KEYWORD, "ppd-type", - ppd_types[ppd->record.type]); + if (send_type) + cupsdSendIPPString(IPP_TAG_KEYWORD, "ppd-type", + PPDTypes[ppd->record.type]); - if (send_model_number) - cupsdSendIPPInteger(IPP_TAG_INTEGER, "ppd-model-number", - ppd->record.model_number); + if (send_model_number) + cupsdSendIPPInteger(IPP_TAG_INTEGER, "ppd-model-number", + ppd->record.model_number); + } + else + printf("%s (%s)\n", ppd->record.name, ppd->record.make_and_model); /* * If we have only requested the ppd-make attribute, then skip @@ -1358,7 +1577,7 @@ list_ppds(int request_id, /* I - Request ID */ } } - if (!sent_header) + if (!sent_header && request_id) { cupsdSendIPPHeader(IPP_NOT_FOUND, request_id); cupsdSendIPPGroup(IPP_TAG_OPERATION); @@ -1366,7 +1585,8 @@ list_ppds(int request_id, /* I - Request ID */ cupsdSendIPPString(IPP_TAG_LANGUAGE, "attributes-natural-language", "en-US"); } - cupsdSendIPPTrailer(); + if (request_id) + cupsdSendIPPTrailer(); return (0); } @@ -1687,12 +1907,12 @@ load_drivers(cups_array_t *include, /* I - Drivers to include */ *start++ = '\0'; for (type = 0; - type < (int)(sizeof(ppd_types) / sizeof(ppd_types[0])); + type < (int)(sizeof(PPDTypes) / sizeof(PPDTypes[0])); type ++) - if (!strcmp(type_str, ppd_types[type])) + if (!strcmp(type_str, PPDTypes[type])) break; - if (type >= (int)(sizeof(ppd_types) / sizeof(ppd_types[0]))) + if (type >= (int)(sizeof(PPDTypes) / sizeof(PPDTypes[0]))) { fprintf(stderr, "ERROR: [cups-driverd] Bad ppd-type \"%s\" ignored!\n", @@ -1745,24 +1965,21 @@ load_drivers(cups_array_t *include, /* I - Drivers to include */ /* - * 'load_ppds()' - Load PPD files recursively. + * 'load_ppd()' - Load a PPD file. */ -static int /* O - 1 on success, 0 on failure */ -load_ppds(const char *d, /* I - Actual directory */ - const char *p, /* I - Virtual path in name */ - int descend) /* I - Descend into directories? */ +static void +load_ppd(const char *filename, /* I - Real filename */ + const char *name, /* I - Virtual filename */ + const char *scheme, /* I - PPD scheme */ + struct stat *fileinfo, /* I - File information */ + ppd_info_t *ppd, /* I - Existing PPD file or NULL */ + cups_file_t *fp, /* I - File to read from */ + off_t end) /* I - End of file position or 0 */ { - struct stat dinfo, /* Directory information */ - *dinfoptr; /* Pointer to match */ int i; /* Looping var */ - cups_file_t *fp; /* Pointer to file */ - cups_dir_t *dir; /* Directory pointer */ - cups_dentry_t *dent; /* Directory entry */ - char filename[1024], /* Name of PPD or directory */ - line[256], /* Line from backend */ - *ptr, /* Pointer into name */ - name[128], /* Name of PPD file */ + char line[256], /* Line from file */ + *ptr, /* Pointer into line */ lang_version[64], /* PPD LanguageVersion */ lang_encoding[64], /* PPD LanguageEncoding */ country[64], /* Country code */ @@ -1780,8 +1997,6 @@ load_ppds(const char *d, /* I - Actual directory */ cups_array_t *products, /* Product array */ *psversions, /* PSVersion array */ *cups_languages; /* cupsLanguages array */ - ppd_info_t *ppd, /* New PPD file */ - key; /* Search key */ int new_ppd; /* Is this a new PPD? */ struct /* LanguageVersion translation table */ { @@ -1816,6 +2031,379 @@ load_ppds(const char *d, /* I - Actual directory */ /* + * Now read until we get the required fields... + */ + + cups_languages = cupsArrayNew(NULL, NULL); + products = cupsArrayNew(NULL, NULL); + psversions = cupsArrayNew(NULL, NULL); + + model_name[0] = '\0'; + nick_name[0] = '\0'; + manufacturer[0] = '\0'; + device_id[0] = '\0'; + lang_encoding[0] = '\0'; + strcpy(lang_version, "en"); + model_number = 0; + install_group = 0; + type = PPD_TYPE_POSTSCRIPT; + + while ((end == 0 || cupsFileTell(fp) < end) && + cupsFileGets(fp, line, sizeof(line))) + { + if (!strncmp(line, "*Manufacturer:", 14)) + sscanf(line, "%*[^\"]\"%255[^\"]", manufacturer); + else if (!strncmp(line, "*ModelName:", 11)) + sscanf(line, "%*[^\"]\"%127[^\"]", model_name); + else if (!strncmp(line, "*LanguageEncoding:", 18)) + sscanf(line, "%*[^:]:%63s", lang_encoding); + else if (!strncmp(line, "*LanguageVersion:", 17)) + sscanf(line, "%*[^:]:%63s", lang_version); + else if (!strncmp(line, "*NickName:", 10)) + sscanf(line, "%*[^\"]\"%255[^\"]", nick_name); + else if (!_cups_strncasecmp(line, "*1284DeviceID:", 14)) + { + sscanf(line, "%*[^\"]\"%255[^\"]", device_id); + + // Make sure device ID ends with a semicolon... + if (device_id[0] && device_id[strlen(device_id) - 1] != ';') + strlcat(device_id, ";", sizeof(device_id)); + } + else if (!strncmp(line, "*Product:", 9)) + { + if (sscanf(line, "%*[^\"]\"(%255[^\"]", product) == 1) + { + /* + * Make sure the value ends with a right parenthesis - can't stop at + * the first right paren since the product name may contain escaped + * parenthesis... + */ + + ptr = product + strlen(product) - 1; + if (ptr > product && *ptr == ')') + { + /* + * Yes, ends with a parenthesis, so remove it from the end and + * add the product to the list... + */ + + *ptr = '\0'; + cupsArrayAdd(products, strdup(product)); + } + } + } + else if (!strncmp(line, "*PSVersion:", 11)) + { + sscanf(line, "%*[^\"]\"%255[^\"]", psversion); + cupsArrayAdd(psversions, strdup(psversion)); + } + else if (!strncmp(line, "*cupsLanguages:", 15)) + { + char *start; /* Start of language */ + + + for (start = line + 15; *start && isspace(*start & 255); start ++); + + if (*start++ == '\"') + { + while (*start) + { + for (ptr = start + 1; + *ptr && *ptr != '\"' && !isspace(*ptr & 255); + ptr ++); + + if (*ptr) + { + *ptr++ = '\0'; + + while (isspace(*ptr & 255)) + *ptr++ = '\0'; + } + + cupsArrayAdd(cups_languages, strdup(start)); + start = ptr; + } + } + } + else if (!strncmp(line, "*cupsFax:", 9)) + { + for (ptr = line + 9; isspace(*ptr & 255); ptr ++); + + if (!_cups_strncasecmp(ptr, "true", 4)) + type = PPD_TYPE_FAX; + } + else if (!strncmp(line, "*cupsFilter:", 12) && type == PPD_TYPE_POSTSCRIPT) + { + if (strstr(line + 12, "application/vnd.cups-raster")) + type = PPD_TYPE_RASTER; + else if (strstr(line + 12, "application/vnd.cups-pdf")) + type = PPD_TYPE_PDF; + } + else if (!strncmp(line, "*cupsModelNumber:", 17)) + sscanf(line, "*cupsModelNumber:%d", &model_number); + else if (!strncmp(line, "*OpenGroup: Installable", 23)) + install_group = 1; + else if (!strncmp(line, "*CloseGroup:", 12)) + install_group = 0; + else if (!strncmp(line, "*OpenUI", 7)) + { + /* + * Stop early if we have a NickName or ModelName attributes + * before the first non-installable OpenUI... + */ + + if (!install_group && (model_name[0] || nick_name[0]) && + cupsArrayCount(products) > 0 && cupsArrayCount(psversions) > 0) + break; + } + } + + /* + * See if we got all of the required info... + */ + + if (nick_name[0]) + cupsCharsetToUTF8((cups_utf8_t *)make_model, nick_name, + sizeof(make_model), _ppdGetEncoding(lang_encoding)); + else + strcpy(make_model, model_name); + + while (isspace(make_model[0] & 255)) + _cups_strcpy(make_model, make_model + 1); + + if (!make_model[0] || cupsArrayCount(products) == 0 || + cupsArrayCount(psversions) == 0) + { + /* + * We don't have all the info needed, so skip this file... + */ + + if (!make_model[0]) + fprintf(stderr, "WARNING: Missing NickName and ModelName in %s!\n", + filename); + + if (cupsArrayCount(products) == 0) + fprintf(stderr, "WARNING: Missing Product in %s!\n", filename); + + if (cupsArrayCount(psversions) == 0) + fprintf(stderr, "WARNING: Missing PSVersion in %s!\n", filename); + + free_array(products); + free_array(psversions); + free_array(cups_languages); + + return; + } + + if (model_name[0]) + cupsArrayAdd(products, strdup(model_name)); + + /* + * Normalize the make and model string... + */ + + while (isspace(manufacturer[0] & 255)) + _cups_strcpy(manufacturer, manufacturer + 1); + + if (!_cups_strncasecmp(make_model, manufacturer, strlen(manufacturer))) + strlcpy(temp, make_model, sizeof(temp)); + else + snprintf(temp, sizeof(temp), "%s %s", manufacturer, make_model); + + _ppdNormalizeMakeAndModel(temp, make_model, sizeof(make_model)); + + /* + * See if we got a manufacturer... + */ + + if (!manufacturer[0] || !strcmp(manufacturer, "ESP")) + { + /* + * Nope, copy the first part of the make and model then... + */ + + strlcpy(manufacturer, make_model, sizeof(manufacturer)); + + /* + * Truncate at the first space, dash, or slash, or make the + * manufacturer "Other"... + */ + + for (ptr = manufacturer; *ptr; ptr ++) + if (*ptr == ' ' || *ptr == '-' || *ptr == '/') + break; + + if (*ptr && ptr > manufacturer) + *ptr = '\0'; + else + strcpy(manufacturer, "Other"); + } + else if (!_cups_strncasecmp(manufacturer, "LHAG", 4) || + !_cups_strncasecmp(manufacturer, "linotype", 8)) + strcpy(manufacturer, "LHAG"); + else if (!_cups_strncasecmp(manufacturer, "Hewlett", 7)) + strcpy(manufacturer, "HP"); + + /* + * Fix the lang_version as needed... + */ + + if ((ptr = strchr(lang_version, '-')) != NULL) + *ptr++ = '\0'; + else if ((ptr = strchr(lang_version, '_')) != NULL) + *ptr++ = '\0'; + + if (ptr) + { + /* + * Setup the country suffix... + */ + + country[0] = '_'; + _cups_strcpy(country + 1, ptr); + } + else + { + /* + * No country suffix... + */ + + country[0] = '\0'; + } + + for (i = 0; i < (int)(sizeof(languages) / sizeof(languages[0])); i ++) + if (!_cups_strcasecmp(languages[i].version, lang_version)) + break; + + if (i < (int)(sizeof(languages) / sizeof(languages[0]))) + { + /* + * Found a known language... + */ + + snprintf(lang_version, sizeof(lang_version), "%s%s", + languages[i].language, country); + } + else + { + /* + * Unknown language; use "xx"... + */ + + strcpy(lang_version, "xx"); + } + + /* + * Record the PPD file... + */ + + new_ppd = !ppd; + + if (new_ppd) + { + /* + * Add new PPD file... + */ + + fprintf(stderr, "DEBUG2: [cups-driverd] Adding ppd \"%s\"...\n", name); + + ppd = add_ppd(name, name, lang_version, manufacturer, make_model, + device_id, (char *)cupsArrayFirst(products), + (char *)cupsArrayFirst(psversions), + fileinfo->st_mtime, fileinfo->st_size, + model_number, type, scheme); + + if (!ppd) + return; + } + else + { + /* + * Update existing record... + */ + + fprintf(stderr, "DEBUG2: [cups-driverd] Updating ppd \"%s\"...\n", name); + + memset(ppd, 0, sizeof(ppd_info_t)); + + ppd->found = 1; + ppd->record.mtime = fileinfo->st_mtime; + ppd->record.size = fileinfo->st_size; + ppd->record.model_number = model_number; + ppd->record.type = type; + + strlcpy(ppd->record.filename, name, sizeof(ppd->record.filename)); + strlcpy(ppd->record.name, name, sizeof(ppd->record.name)); + strlcpy(ppd->record.languages[0], lang_version, + sizeof(ppd->record.languages[0])); + strlcpy(ppd->record.products[0], (char *)cupsArrayFirst(products), + sizeof(ppd->record.products[0])); + strlcpy(ppd->record.psversions[0], (char *)cupsArrayFirst(psversions), + sizeof(ppd->record.psversions[0])); + strlcpy(ppd->record.make, manufacturer, sizeof(ppd->record.make)); + strlcpy(ppd->record.make_and_model, make_model, + sizeof(ppd->record.make_and_model)); + strlcpy(ppd->record.device_id, device_id, sizeof(ppd->record.device_id)); + strlcpy(ppd->record.scheme, scheme, sizeof(ppd->record.scheme)); + } + + /* + * Add remaining products, versions, and languages... + */ + + for (i = 1; + i < PPD_MAX_PROD && (ptr = (char *)cupsArrayNext(products)) != NULL; + i ++) + strlcpy(ppd->record.products[i], ptr, + sizeof(ppd->record.products[0])); + + for (i = 1; + i < PPD_MAX_VERS && (ptr = (char *)cupsArrayNext(psversions)) != NULL; + i ++) + strlcpy(ppd->record.psversions[i], ptr, + sizeof(ppd->record.psversions[0])); + + for (i = 1, ptr = (char *)cupsArrayFirst(cups_languages); + i < PPD_MAX_LANG && ptr; + i ++, ptr = (char *)cupsArrayNext(cups_languages)) + strlcpy(ppd->record.languages[i], ptr, + sizeof(ppd->record.languages[0])); + + /* + * Free products, versions, and languages... + */ + + free_array(cups_languages); + free_array(products); + free_array(psversions); + + ChangedPPD = 1; +} + + +/* + * 'load_ppds()' - Load PPD files recursively. + */ + +static int /* O - 1 on success, 0 on failure */ +load_ppds(const char *d, /* I - Actual directory */ + const char *p, /* I - Virtual path in name */ + int descend) /* I - Descend into directories? */ +{ + struct stat dinfo, /* Directory information */ + *dinfoptr; /* Pointer to match */ + cups_file_t *fp; /* Pointer to file */ + cups_dir_t *dir; /* Directory pointer */ + cups_dentry_t *dent; /* Directory entry */ + char filename[1024], /* Name of PPD or directory */ + line[256], /* Line from file */ + *ptr, /* Pointer into name */ + name[128]; /* Name of PPD file */ + ppd_info_t *ppd, /* New PPD file */ + key; /* Search key */ + + + /* * See if we've loaded this directory before... */ @@ -1915,8 +2503,7 @@ load_ppds(const char *d, /* I - Actual directory */ continue; } - else if ((ptr = filename + strlen(filename) - 6) > filename && - !strcmp(ptr, ".plist")) + else if (strstr(filename, ".plist")) { /* * Skip plist files in the PPDs directory... @@ -1973,373 +2560,36 @@ load_ppds(const char *d, /* I - Actual directory */ line[0] = '\0'; cupsFileGets(fp, line, sizeof(line)); - if (strncmp(line, "*PPD-Adobe:", 11)) - { - /* - * Nope, treat it as a driver information file... - */ - - load_drv(filename, name, fp, dent->fileinfo.st_mtime, - dent->fileinfo.st_size); - continue; - } - - /* - * Now read until we get the NickName field... - */ - - cups_languages = cupsArrayNew(NULL, NULL); - products = cupsArrayNew(NULL, NULL); - psversions = cupsArrayNew(NULL, NULL); - - model_name[0] = '\0'; - nick_name[0] = '\0'; - manufacturer[0] = '\0'; - device_id[0] = '\0'; - lang_encoding[0] = '\0'; - strcpy(lang_version, "en"); - model_number = 0; - install_group = 0; - type = PPD_TYPE_POSTSCRIPT; - - while (cupsFileGets(fp, line, sizeof(line)) != NULL) - { - if (!strncmp(line, "*Manufacturer:", 14)) - sscanf(line, "%*[^\"]\"%255[^\"]", manufacturer); - else if (!strncmp(line, "*ModelName:", 11)) - sscanf(line, "%*[^\"]\"%127[^\"]", model_name); - else if (!strncmp(line, "*LanguageEncoding:", 18)) - sscanf(line, "%*[^:]:%63s", lang_encoding); - else if (!strncmp(line, "*LanguageVersion:", 17)) - sscanf(line, "%*[^:]:%63s", lang_version); - else if (!strncmp(line, "*NickName:", 10)) - sscanf(line, "%*[^\"]\"%255[^\"]", nick_name); - else if (!_cups_strncasecmp(line, "*1284DeviceID:", 14)) - { - sscanf(line, "%*[^\"]\"%255[^\"]", device_id); - - // Make sure device ID ends with a semicolon... - if (device_id[0] && device_id[strlen(device_id) - 1] != ';') - strlcat(device_id, ";", sizeof(device_id)); - } - else if (!strncmp(line, "*Product:", 9)) - { - if (sscanf(line, "%*[^\"]\"(%255[^\"]", product) == 1) - { - /* - * Make sure the value ends with a right parenthesis - can't stop at - * the first right paren since the product name may contain escaped - * parenthesis... - */ - - ptr = product + strlen(product) - 1; - if (ptr > product && *ptr == ')') - { - /* - * Yes, ends with a parenthesis, so remove it from the end and - * add the product to the list... - */ - - *ptr = '\0'; - cupsArrayAdd(products, strdup(product)); - } - } - } - else if (!strncmp(line, "*PSVersion:", 11)) - { - sscanf(line, "%*[^\"]\"%255[^\"]", psversion); - cupsArrayAdd(psversions, strdup(psversion)); - } - else if (!strncmp(line, "*cupsLanguages:", 15)) - { - char *start; /* Start of language */ - - - for (start = line + 15; *start && isspace(*start & 255); start ++); - - if (*start++ == '\"') - { - while (*start) - { - for (ptr = start + 1; - *ptr && *ptr != '\"' && !isspace(*ptr & 255); - ptr ++); - - if (*ptr) - { - *ptr++ = '\0'; - - while (isspace(*ptr & 255)) - *ptr++ = '\0'; - } - - cupsArrayAdd(cups_languages, strdup(start)); - start = ptr; - } - } - } - else if (!strncmp(line, "*cupsFax:", 9)) - { - for (ptr = line + 9; isspace(*ptr & 255); ptr ++); - - if (!_cups_strncasecmp(ptr, "true", 4)) - type = PPD_TYPE_FAX; - } - else if (!strncmp(line, "*cupsFilter:", 12) && type == PPD_TYPE_POSTSCRIPT) - { - if (strstr(line + 12, "application/vnd.cups-raster")) - type = PPD_TYPE_RASTER; - else if (strstr(line + 12, "application/vnd.cups-pdf")) - type = PPD_TYPE_PDF; - } - else if (!strncmp(line, "*cupsModelNumber:", 17)) - sscanf(line, "*cupsModelNumber:%d", &model_number); - else if (!strncmp(line, "*OpenGroup: Installable", 23)) - install_group = 1; - else if (!strncmp(line, "*CloseGroup:", 12)) - install_group = 0; - else if (!strncmp(line, "*OpenUI", 7)) - { - /* - * Stop early if we have a NickName or ModelName attributes - * before the first non-installable OpenUI... - */ - - if (!install_group && (model_name[0] || nick_name[0]) && - cupsArrayCount(products) > 0 && cupsArrayCount(psversions) > 0) - break; - } - } - - /* - * Close the file... - */ - - cupsFileClose(fp); - - /* - * See if we got all of the required info... - */ - - if (nick_name[0]) - cupsCharsetToUTF8((cups_utf8_t *)make_model, nick_name, - sizeof(make_model), _ppdGetEncoding(lang_encoding)); - else - strcpy(make_model, model_name); - - while (isspace(make_model[0] & 255)) - _cups_strcpy(make_model, make_model + 1); - - if (!make_model[0] || cupsArrayCount(products) == 0 || - cupsArrayCount(psversions) == 0) + if (!strncmp(line, "*PPD-Adobe:", 11)) { /* - * We don't have all the info needed, so skip this file... + * Yes, load it... */ - if (!make_model[0]) - fprintf(stderr, "WARNING: Missing NickName and ModelName in %s!\n", - filename); - - if (cupsArrayCount(products) == 0) - fprintf(stderr, "WARNING: Missing Product in %s!\n", filename); - - if (cupsArrayCount(psversions) == 0) - fprintf(stderr, "WARNING: Missing PSVersion in %s!\n", filename); - - free_array(products); - free_array(psversions); - free_array(cups_languages); - - continue; + load_ppd(filename, name, "file", &dent->fileinfo, ppd, fp, 0); } - - if (model_name[0]) - cupsArrayAdd(products, strdup(model_name)); - - /* - * Normalize the make and model string... - */ - - while (isspace(manufacturer[0] & 255)) - _cups_strcpy(manufacturer, manufacturer + 1); - - if (!_cups_strncasecmp(make_model, manufacturer, strlen(manufacturer))) - strlcpy(temp, make_model, sizeof(temp)); else - snprintf(temp, sizeof(temp), "%s %s", manufacturer, make_model); - - _ppdNormalizeMakeAndModel(temp, make_model, sizeof(make_model)); - - /* - * See if we got a manufacturer... - */ - - if (!manufacturer[0] || !strcmp(manufacturer, "ESP")) { /* - * Nope, copy the first part of the make and model then... - */ - - strlcpy(manufacturer, make_model, sizeof(manufacturer)); - - /* - * Truncate at the first space, dash, or slash, or make the - * manufacturer "Other"... + * Nope, treat it as a driver information file or archive... */ - for (ptr = manufacturer; *ptr; ptr ++) - if (*ptr == ' ' || *ptr == '-' || *ptr == '/') - break; + cupsFileRewind(fp); - if (*ptr && ptr > manufacturer) - *ptr = '\0'; + if ((ptr = strstr(filename, ".tar")) != NULL && + (!strcmp(ptr, ".tar") || !strcmp(ptr, ".tar.gz"))) + load_tar(filename, name, fp, dent->fileinfo.st_mtime, + dent->fileinfo.st_size); else - strcpy(manufacturer, "Other"); - } - else if (!_cups_strncasecmp(manufacturer, "LHAG", 4) || - !_cups_strncasecmp(manufacturer, "linotype", 8)) - strcpy(manufacturer, "LHAG"); - else if (!_cups_strncasecmp(manufacturer, "Hewlett", 7)) - strcpy(manufacturer, "HP"); - - /* - * Fix the lang_version as needed... - */ - - if ((ptr = strchr(lang_version, '-')) != NULL) - *ptr++ = '\0'; - else if ((ptr = strchr(lang_version, '_')) != NULL) - *ptr++ = '\0'; - - if (ptr) - { - /* - * Setup the country suffix... - */ - - country[0] = '_'; - _cups_strcpy(country + 1, ptr); - } - else - { - /* - * No country suffix... - */ - - country[0] = '\0'; - } - - for (i = 0; i < (int)(sizeof(languages) / sizeof(languages[0])); i ++) - if (!_cups_strcasecmp(languages[i].version, lang_version)) - break; - - if (i < (int)(sizeof(languages) / sizeof(languages[0]))) - { - /* - * Found a known language... - */ - - snprintf(lang_version, sizeof(lang_version), "%s%s", - languages[i].language, country); - } - else - { - /* - * Unknown language; use "xx"... - */ - - strcpy(lang_version, "xx"); - } - - /* - * Record the PPD file... - */ - - new_ppd = !ppd; - - if (new_ppd) - { - /* - * Add new PPD file... - */ - - fprintf(stderr, "DEBUG2: [cups-driverd] Adding ppd \"%s\"...\n", name); - - ppd = add_ppd(name, name, lang_version, manufacturer, make_model, - device_id, (char *)cupsArrayFirst(products), - (char *)cupsArrayFirst(psversions), - dent->fileinfo.st_mtime, dent->fileinfo.st_size, - model_number, type, "file"); - - if (!ppd) - { - cupsDirClose(dir); - return (0); - } - } - else - { - /* - * Update existing record... - */ - - fprintf(stderr, "DEBUG2: [cups-driverd] Updating ppd \"%s\"...\n", name); - - memset(ppd, 0, sizeof(ppd_info_t)); - - ppd->found = 1; - ppd->record.mtime = dent->fileinfo.st_mtime; - ppd->record.size = dent->fileinfo.st_size; - ppd->record.model_number = model_number; - ppd->record.type = type; - - strlcpy(ppd->record.filename, name, sizeof(ppd->record.filename)); - strlcpy(ppd->record.name, name, sizeof(ppd->record.name)); - strlcpy(ppd->record.languages[0], lang_version, - sizeof(ppd->record.languages[0])); - strlcpy(ppd->record.products[0], (char *)cupsArrayFirst(products), - sizeof(ppd->record.products[0])); - strlcpy(ppd->record.psversions[0], (char *)cupsArrayFirst(psversions), - sizeof(ppd->record.psversions[0])); - strlcpy(ppd->record.make, manufacturer, sizeof(ppd->record.make)); - strlcpy(ppd->record.make_and_model, make_model, - sizeof(ppd->record.make_and_model)); - strlcpy(ppd->record.device_id, device_id, sizeof(ppd->record.device_id)); - strlcpy(ppd->record.scheme, "file", sizeof(ppd->record.scheme)); + load_drv(filename, name, fp, dent->fileinfo.st_mtime, + dent->fileinfo.st_size); } /* - * Add remaining products, versions, and languages... - */ - - for (i = 1; - i < PPD_MAX_PROD && (ptr = (char *)cupsArrayNext(products)) != NULL; - i ++) - strlcpy(ppd->record.products[i], ptr, - sizeof(ppd->record.products[0])); - - for (i = 1; - i < PPD_MAX_VERS && (ptr = (char *)cupsArrayNext(psversions)) != NULL; - i ++) - strlcpy(ppd->record.psversions[i], ptr, - sizeof(ppd->record.psversions[0])); - - for (i = 1, ptr = (char *)cupsArrayFirst(cups_languages); - i < PPD_MAX_LANG && ptr; - i ++, ptr = (char *)cupsArrayNext(cups_languages)) - strlcpy(ppd->record.languages[i], ptr, - sizeof(ppd->record.languages[0])); - - /* - * Free products, versions, and languages... + * Close the file... */ - free_array(cups_languages); - free_array(products); - free_array(psversions); - - ChangedPPD = 1; + cupsFileClose(fp); } cupsDirClose(dir); @@ -2367,10 +2617,14 @@ load_ppds_dat(char *filename, /* I - Filename buffer */ PPDsByMakeModel = cupsArrayNew((cups_array_func_t)compare_ppds, NULL); ChangedPPD = 0; - if ((cups_cachedir = getenv("CUPS_CACHEDIR")) == NULL) - cups_cachedir = CUPS_CACHEDIR; + if (!filename[0]) + { + if ((cups_cachedir = getenv("CUPS_CACHEDIR")) == NULL) + cups_cachedir = CUPS_CACHEDIR; + + snprintf(filename, filesize, "%s/ppds.dat", cups_cachedir); + } - snprintf(filename, filesize, "%s/ppds.dat", cups_cachedir); if ((fp = cupsFileOpen(filename, "r")) != NULL) { /* @@ -2425,6 +2679,117 @@ load_ppds_dat(char *filename, /* I - Filename buffer */ /* + * 'load_tar()' - Load archived PPD files. + */ + +static int /* O - 1 on success, 0 on failure */ +load_tar(const char *filename, /* I - Actual filename */ + const char *name, /* I - Name to the rest of the world */ + cups_file_t *fp, /* I - File to read from */ + time_t mtime, /* I - Mod time of driver info file */ + off_t size) /* I - Size of driver info file */ +{ + char curname[256], /* Current archive file name */ + uri[1024]; /* Virtual file URI */ + const char *curext; /* Extension on file */ + struct stat curinfo; /* Current archive file information */ + off_t next; /* Position for next header */ + + + /* + * Add a dummy entry for the file... + */ + + (void)filename; + + add_ppd(name, name, "", "", "", "", "", "", mtime, size, 0, + PPD_TYPE_ARCHIVE, "file"); + ChangedPPD = 1; + + /* + * Scan for PPDs in the archive... + */ + + while (read_tar(fp, curname, sizeof(curname), &curinfo)) + { + next = cupsFileTell(fp) + ((curinfo.st_size + TAR_BLOCK - 1) & + ~(TAR_BLOCK - 1)); + + if ((curext = strrchr(curname, '.')) != NULL && + !_cups_strcasecmp(curext, ".ppd")) + { + httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "file", "", "", + 0, "/%s/%s", name, curname); + load_ppd(name, uri, "file", &curinfo, NULL, fp, next); + } + + if (cupsFileTell(fp) != next) + cupsFileSeek(fp, next); + } + + return (1); +} + + +/* + * 'read_tar()' - Read a file header from an archive. + * + * This function skips all directories and special files. + */ + +static int /* O - 1 if found, 0 on EOF */ +read_tar(cups_file_t *fp, /* I - Archive to read */ + char *name, /* I - Filename buffer */ + size_t namesize, /* I - Size of filename buffer */ + struct stat *info) /* O - File information */ +{ + tar_rec_t record; /* Record from file */ + + + while (cupsFileRead(fp, (char *)&record, sizeof(record)) == sizeof(record)) + { + /* + * Check for a valid tar header... + */ + + if (memcmp(record.header.magic, TAR_MAGIC, 6) || + memcmp(record.header.version, TAR_VERSION, 2)) + { + if (record.header.magic[0] || + memcmp(record.header.magic, record.header.magic + 1, 5)) + fputs("ERROR: [cups-driverd] Bad tar magic/version.\n", stderr); + break; + } + + /* + * Ignore non-files... + */ + + if (record.header.linkflag != TAR_OLDNORMAL && + record.header.linkflag != TAR_NORMAL) + continue; + + /* + * Grab size and name from tar header and return... + */ + + if (record.header.prefix[0]) + snprintf(name, namesize, "%s/%s", record.header.prefix, + record.header.pathname); + else + strlcpy(name, record.header.pathname, namesize); + + info->st_mtime = strtol(record.header.mtime, NULL, 8); + info->st_size = strtoll(record.header.size, NULL, 8); + + return (1); + } + + return (0); +} + + +/* * 'regex_device_id()' - Compile a regular expression based on the 1284 device * ID. */ @@ -2582,5 +2947,5 @@ regex_string(const char *s) /* I - String to compare */ /* - * End of "$Id: cups-driverd.cxx 10276 2012-02-13 22:48:22Z mike $". + * End of "$Id: cups-driverd.cxx 11173 2013-07-23 12:31:34Z msweet $". */ diff --git a/scheduler/cups-exec.c b/scheduler/cups-exec.c index 6918c7f..6d0d3d8 100644 --- a/scheduler/cups-exec.c +++ b/scheduler/cups-exec.c @@ -1,9 +1,9 @@ /* - * "$Id: cups-exec.c 9931 2011-08-29 20:12:39Z mike $" + * "$Id: cups-exec.c 11173 2013-07-23 12:31:34Z msweet $" * * Sandbox helper for CUPS. * - * Copyright 2007-2011 by Apple Inc. + * Copyright 2007-2012 by Apple Inc. * * These coded instructions, statements, and computer programs are the * property of Apple Inc. and are protected by Federal copyright @@ -31,6 +31,7 @@ # ifndef SANDBOX_NAMED_EXTERNAL # define SANDBOX_NAMED_EXTERNAL 0x0003 # endif /* !SANDBOX_NAMED_EXTERNAL */ +# pragma GCC diagnostic ignored "-Wdeprecated-declarations" #endif /* HAVE_SANDBOX_H */ @@ -104,5 +105,5 @@ main(int argc, /* I - Number of command-line args */ /* - * End of "$Id: cups-exec.c 9931 2011-08-29 20:12:39Z mike $". + * End of "$Id: cups-exec.c 11173 2013-07-23 12:31:34Z msweet $". */ diff --git a/scheduler/cups-lpd.c b/scheduler/cups-lpd.c index 7846ecf..bd6757b 100644 --- a/scheduler/cups-lpd.c +++ b/scheduler/cups-lpd.c @@ -1,9 +1,9 @@ /* - * "$Id: cups-lpd.c 10379 2012-03-23 22:16:22Z mike $" + * "$Id: cups-lpd.c 11173 2013-07-23 12:31:34Z msweet $" * * Line Printer Daemon interface for CUPS. * - * Copyright 2007-2011 by Apple Inc. + * Copyright 2007-2012 by Apple Inc. * Copyright 1997-2006 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -744,8 +744,7 @@ print_file(http_t *http, /* I - HTTP connection */ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format", NULL, format); - if (last) - ippAddBoolean(request, IPP_TAG_OPERATION, "last-document", 1); + ippAddBoolean(request, IPP_TAG_OPERATION, "last-document", last); /* * Do the request... @@ -1623,5 +1622,5 @@ smart_gets(char *s, /* I - Pointer to line buffer */ /* - * End of "$Id: cups-lpd.c 10379 2012-03-23 22:16:22Z mike $". + * End of "$Id: cups-lpd.c 11173 2013-07-23 12:31:34Z msweet $". */ diff --git a/scheduler/cups-polld.c b/scheduler/cups-polld.c deleted file mode 100644 index 65b2e68..0000000 --- a/scheduler/cups-polld.c +++ /dev/null @@ -1,470 +0,0 @@ -/* - * "$Id: cups-polld.c 10321 2012-03-02 18:26:30Z mike $" - * - * Polling daemon for CUPS. - * - * Copyright 2007-2012 by Apple Inc. - * Copyright 1997-2006 by Easy Software Products, all rights reserved. - * - * These coded instructions, statements, and computer programs are the - * property of Apple Inc. and are protected by Federal copyright - * law. Distribution and use rights are outlined in the file "LICENSE.txt" - * which should have been included with this file. If this file is - * file is missing or damaged, see the license at "http://www.cups.org/". - * - * Contents: - * - * main() - Open sockets and poll until we are killed... - * dequote() - Remote quotes from a string. - * poll_server() - Poll the server for the given set of printers or - * classes. - * sighup_handler() - Handle 'hangup' signals to restart polling. - */ - -/* - * Include necessary headers... - */ - -#include <cups/cups-private.h> -#include <signal.h> - - -/* - * Local globals... - */ - -static int restart_polling = 1; - - -/* - * Local functions... - */ - -static char *dequote(char *d, const char *s, int dlen); -static int poll_server(http_t *http, int sock, int port, int interval, - const char *prefix); -static void sighup_handler(int sig); - - -/* - * 'main()' - Open sockets and poll until we are killed... - */ - -int /* O - Exit status */ -main(int argc, /* I - Number of command-line args */ - char *argv[]) /* I - Command-line arguments */ -{ - http_t *http; /* HTTP connection */ - int interval; /* Polling interval */ - int sock; /* Browser sock */ - int port; /* Browser port */ - int val; /* Socket option value */ - int seconds, /* Seconds left from poll */ - remain; /* Total remaining time to sleep */ - char prefix[1024]; /* Prefix for log messages */ -#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET) - struct sigaction action; /* Actions for POSIX signals */ -#endif /* HAVE_SIGACTION && !HAVE_SIGSET */ - - - /* - * Catch hangup signals for when the network changes... - */ - -#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */ - sigset(SIGHUP, sighup_handler); -#elif defined(HAVE_SIGACTION) - memset(&action, 0, sizeof(action)); - - sigemptyset(&action.sa_mask); - sigaddset(&action.sa_mask, SIGHUP); - action.sa_handler = sighup_handler; - sigaction(SIGHUP, &action, NULL); -#else - signal(SIGHUP, sighup_handler); -#endif /* HAVE_SIGSET */ - - /* - * Don't buffer log messages... - */ - - setbuf(stderr, NULL); - - /* - * The command-line must contain the following: - * - * cups-polld server server-port interval port - */ - - if (argc != 5) - { - fputs("Usage: cups-polld server server-port interval port\n", stderr); - return (1); - } - - interval = atoi(argv[3]); - port = atoi(argv[4]); - - if (interval < 2) - interval = 2; - - snprintf(prefix, sizeof(prefix), "[cups-polld %s:%d]", argv[1], atoi(argv[2])); - - /* - * Open a broadcast socket... - */ - - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) - { - fprintf(stderr, "ERROR: %s Unable to open broadcast socket: %s\n", prefix, - strerror(errno)); - return (1); - } - - /* - * Set the "broadcast" flag... - */ - - val = 1; - if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &val, sizeof(val))) - { - fprintf(stderr, "ERROR: %s Unable to put socket in broadcast mode: %s\n", - prefix, strerror(errno)); - - close(sock); - return (1); - } - - /* - * Loop forever, asking for available printers and classes... - */ - - for (http = NULL; !ferror(stderr);) - { - /* - * Open a connection to the server... - */ - - if (restart_polling || !http) - { - restart_polling = 0; - httpClose(http); - - if ((http = httpConnectEncrypt(argv[1], atoi(argv[2]), - cupsEncryption())) == NULL) - { - fprintf(stderr, "ERROR: %s Unable to connect to %s on port %s.\n", - prefix, argv[1], argv[2]); - } - } - - /* - * Get the printers and classes... - */ - - remain = interval; - - if (http && (seconds = poll_server(http, sock, port, interval, prefix)) > 0) - remain -= seconds; - - /* - * Sleep for any remaining time... - */ - - if (remain > 0 && !restart_polling) - sleep(remain); - } - - return (1); -} - - -/* - * 'dequote()' - Remote quotes from a string. - */ - -static char * /* O - Dequoted string */ -dequote(char *d, /* I - Destination string */ - const char *s, /* I - Source string */ - int dlen) /* I - Destination length */ -{ - char *dptr; /* Pointer into destination */ - - - if (s) - { - for (dptr = d, dlen --; *s && dlen > 0; s ++) - if (*s != '\"') - { - *dptr++ = *s; - dlen --; - } - - *dptr = '\0'; - } - else - *d = '\0'; - - return (d); -} - - -/* - * 'poll_server()' - Poll the server for the given set of printers or classes. - */ - -static int /* O - Number of seconds or -1 on error */ -poll_server(http_t *http, /* I - HTTP connection */ - int sock, /* I - Broadcast sock */ - int port, /* I - Broadcast port */ - int interval, /* I - Polling interval */ - const char *prefix) /* I - Prefix for log messages */ -{ - int seconds; /* Number of seconds */ - int count, /* Current number of printers/classes */ - max_count; /* Maximum printers/classes per second */ - ipp_t *request, /* Request data */ - *response; /* Response data */ - ipp_attribute_t *attr; /* Current attribute */ - const char *uri; /* printer-uri */ - char info[1024], /* printer-info */ - job_sheets[1024],/* job-sheets-default */ - location[1024], /* printer-location */ - make_model[1024]; - /* printer-make-and-model */ - cups_ptype_t type; /* printer-type */ - ipp_pstate_t state; /* printer-state */ - int accepting; /* printer-is-accepting-jobs */ - struct sockaddr_in addr; /* Broadcast address */ - char packet[1540]; /* Data packet */ - static const char * const attrs[] = /* Requested attributes */ - { - "job-sheets-default", - "printer-info", - "printer-is-accepting-jobs", - "printer-location", - "printer-make-and-model", - "printer-name", - "printer-state", - "printer-type", - "printer-uri-supported" - }; - - - /* - * Broadcast to 127.0.0.1 (localhost) - */ - - memset(&addr, 0, sizeof(addr)); - addr.sin_addr.s_addr = htonl(0x7f000001); - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - - /* - * Build a CUPS_GET_PRINTERS request and pass along a list of the - * attributes we are interested in along with the types of printers - * (and classes) we want. - */ - - request = ippNewRequest(CUPS_GET_PRINTERS); - - ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, - "requested-attributes", sizeof(attrs) / sizeof(attrs[0]), - NULL, attrs); - - ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, - "printer-type", 0); - ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, - "printer-type-mask", - CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT | - CUPS_PRINTER_NOT_SHARED); - - /* - * Do the request and get back a response... - */ - - seconds = time(NULL); - response = cupsDoRequest(http, request, "/"); - - if (cupsLastError() > IPP_OK_CONFLICT) - { - fprintf(stderr, "ERROR: %s CUPS-Get-Printers failed: %s\n", prefix, - cupsLastErrorString()); - ippDelete(response); - restart_polling = 1; - return (-1); - } - - if (response) - { - /* - * Figure out how many printers/classes we have... - */ - - for (attr = ippFindAttribute(response, "printer-name", IPP_TAG_NAME), - max_count = 0; - attr != NULL; - attr = ippFindNextAttribute(response, "printer-name", IPP_TAG_NAME), - max_count ++); - - fprintf(stderr, "DEBUG: %s Found %d printers.\n", prefix, max_count); - - count = 0; - max_count = 2 * max_count / interval + 1; - - /* - * Loop through the printers or classes returned in the list... - */ - - for (attr = response->attrs; attr; attr = attr->next) - { - /* - * Skip leading attributes until we hit a printer... - */ - - while (attr && attr->group_tag != IPP_TAG_PRINTER) - attr = attr->next; - - if (!attr) - break; - - /* - * Pull the needed attributes from this printer... - */ - - uri = NULL; - info[0] = '\0'; - job_sheets[0] = '\0'; - location[0] = '\0'; - make_model[0] = '\0'; - type = CUPS_PRINTER_REMOTE; - accepting = 1; - state = IPP_PRINTER_IDLE; - - while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER) - { - if (!strcmp(attr->name, "job-sheets-default") && - (attr->value_tag == IPP_TAG_NAME || - attr->value_tag == IPP_TAG_KEYWORD)) - { - if (attr->num_values == 1) - snprintf(job_sheets, sizeof(job_sheets), " job-sheets=%s", - attr->values[0].string.text); - else - snprintf(job_sheets, sizeof(job_sheets), " job-sheets=%s,%s", - attr->values[0].string.text, - attr->values[1].string.text); - } - else if (!strcmp(attr->name, "printer-uri-supported") && - attr->value_tag == IPP_TAG_URI) - uri = attr->values[0].string.text; - else if (!strcmp(attr->name, "printer-info") && - attr->value_tag == IPP_TAG_TEXT) - dequote(info, attr->values[0].string.text, sizeof(info)); - else if (!strcmp(attr->name, "printer-is-accepting-jobs") && - attr->value_tag == IPP_TAG_BOOLEAN) - accepting = attr->values[0].boolean; - else if (!strcmp(attr->name, "printer-location") && - attr->value_tag == IPP_TAG_TEXT) - dequote(location, attr->values[0].string.text, sizeof(location)); - else if (!strcmp(attr->name, "printer-make-and-model") && - attr->value_tag == IPP_TAG_TEXT) - dequote(make_model, attr->values[0].string.text, sizeof(location)); - else if (!strcmp(attr->name, "printer-state") && - attr->value_tag == IPP_TAG_ENUM) - state = (ipp_pstate_t)attr->values[0].integer; - else if (!strcmp(attr->name, "printer-type") && - attr->value_tag == IPP_TAG_ENUM) - type = (cups_ptype_t)attr->values[0].integer; - - attr = attr->next; - } - - /* - * See if we have everything needed... - */ - - if (uri == NULL) - { - if (attr == NULL) - break; - else - continue; - } - - /* - * Send the printer information... - */ - - type |= CUPS_PRINTER_REMOTE; - - if (!accepting) - type |= CUPS_PRINTER_REJECTING; - - snprintf(packet, sizeof(packet), - "%x %x %s \"%s\" \"%s\" \"%s\" lease-duration=%d%s\n", - type, state, uri, location, info, make_model, interval * 2, - job_sheets); - - fprintf(stderr, "DEBUG2: %s Sending %s", prefix, packet); - - if (sendto(sock, packet, strlen(packet), 0, - (struct sockaddr *)&addr, sizeof(addr)) <= 0) - { - ippDelete(response); - perror("cups-polld"); - return (-1); - } - - /* - * Throttle the local broadcasts as needed so that we don't - * overwhelm the local server... - */ - - count ++; - if (count >= max_count) - { - /* - * Sleep for a second... - */ - - count = 0; - - sleep(1); - } - - if (!attr || restart_polling) - break; - } - - ippDelete(response); - } - - /* - * Return the number of seconds we used... - */ - - return (time(NULL) - seconds); -} - - -/* - * 'sighup_handler()' - Handle 'hangup' signals to restart polling. - */ - -static void -sighup_handler(int sig) /* I - Signal number */ -{ - (void)sig; - - restart_polling = 1; - -#if !defined(HAVE_SIGSET) && !defined(HAVE_SIGACTION) - signal(SIGHUP, sighup_handler); -#endif /* !HAVE_SIGSET && !HAVE_SIGACTION */ -} - - -/* - * End of "$Id: cups-polld.c 10321 2012-03-02 18:26:30Z mike $". - */ diff --git a/scheduler/cups.sh.in b/scheduler/cups.sh.in index 133bca6..ff72c1c 100644 --- a/scheduler/cups.sh.in +++ b/scheduler/cups.sh.in @@ -1,6 +1,6 @@ #!/bin/sh # -# "$Id: cups.sh.in 9949 2011-08-31 04:58:33Z mike $" +# "$Id: cups.sh.in 11173 2013-07-23 12:31:34Z msweet $" # # Startup/shutdown script for CUPS. # @@ -233,5 +233,5 @@ exit 0 # -# End of "$Id: cups.sh.in 9949 2011-08-31 04:58:33Z mike $". +# End of "$Id: cups.sh.in 11173 2013-07-23 12:31:34Z msweet $". # diff --git a/scheduler/cups.xml.in b/scheduler/cups.xml.in index ba614ce..b76ad02 100644 --- a/scheduler/cups.xml.in +++ b/scheduler/cups.xml.in @@ -1,7 +1,7 @@ <?xml version="1.0"?> <!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1"> <!-- - $Id: cups.xml.in 9197 2010-07-08 17:23:08Z mike $ + $Id: cups.xml.in 11173 2013-07-23 12:31:34Z msweet $ Service manifest for CUPS. diff --git a/scheduler/cupsd.h b/scheduler/cupsd.h index 55d5ccb..48ea1d7 100644 --- a/scheduler/cupsd.h +++ b/scheduler/cupsd.h @@ -1,9 +1,9 @@ /* - * "$Id: cupsd.h 9766 2011-05-11 22:17:34Z mike $" + * "$Id: cupsd.h 11173 2013-07-23 12:31:34Z msweet $" * * Main header file for the CUPS scheduler. * - * Copyright 2007-2011 by Apple Inc. + * Copyright 2007-2012 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -82,12 +82,10 @@ extern const char *cups_hstrerror(int); * Defaults... */ -#define DEFAULT_HISTORY 1 /* Preserve job history? */ -#define DEFAULT_FILES 0 /* Preserve job files? */ +#define DEFAULT_HISTORY INT_MAX /* Preserve job history? */ +#define DEFAULT_FILES 86400 /* Preserve job files? */ #define DEFAULT_TIMEOUT 300 /* Timeout during requests/updates */ #define DEFAULT_KEEPALIVE 30 /* Timeout between requests */ -#define DEFAULT_INTERVAL 30 /* Interval between browse updates */ -#define DEFAULT_CHARSET "utf-8" /* Default charset */ /* @@ -118,6 +116,7 @@ extern const char *cups_hstrerror(int); #include "printers.h" #include "classes.h" #include "job.h" +#include "colorman.h" #include "conf.h" #include "banners.h" #include "dirsvc.h" @@ -161,13 +160,6 @@ VAR int NeedReload VALUE(RELOAD_ALL), VAR void *DefaultProfile VALUE(0); /* Default security profile */ -#ifdef HAVE_GSSAPI -VAR int KerberosInitialized VALUE(0); - /* Has Kerberos been initialized? */ -VAR krb5_context KerberosContext VALUE(NULL); - /* Kerberos context for credentials */ -#endif /* HAVE_GSSAPI */ - #ifdef HAVE_LAUNCH_H VAR int Launchd VALUE(0); /* Running from launchd */ @@ -183,10 +175,7 @@ extern void cupsdInitEnv(void); extern int cupsdLoadEnv(char *envp[], int envmax); extern void cupsdSetEnv(const char *name, const char *value); extern void cupsdSetEnvf(const char *name, const char *value, ...) -#ifdef __GNUC__ -__attribute__ ((__format__ (__printf__, 2, 3))) -#endif /* __GNUC__ */ -; + __attribute__ ((__format__ (__printf__, 2, 3))); extern void cupsdUpdateEnv(void); /* file.c */ @@ -210,10 +199,7 @@ extern char *cupsdMakeUUID(const char *name, int number, extern void cupsdReleaseSignals(void); extern void cupsdSetString(char **s, const char *v); extern void cupsdSetStringf(char **s, const char *f, ...) -#ifdef __GNUC__ -__attribute__ ((__format__ (__printf__, 2, 3))) -#endif /* __GNUC__ */ -; + __attribute__ ((__format__ (__printf__, 2, 3))); /* process.c */ extern void *cupsdCreateProfile(int job_id); @@ -244,5 +230,5 @@ extern void cupsdStopServer(void); /* - * End of "$Id: cupsd.h 9766 2011-05-11 22:17:34Z mike $". + * End of "$Id: cupsd.h 11173 2013-07-23 12:31:34Z msweet $". */ diff --git a/scheduler/cupsfilter.c b/scheduler/cupsfilter.c index 9f21a52..4b471d5 100644 --- a/scheduler/cupsfilter.c +++ b/scheduler/cupsfilter.c @@ -1,9 +1,9 @@ /* - * "$Id: cupsfilter.c 9862 2011-08-03 02:44:09Z mike $" + * "$Id: cupsfilter.c 11173 2013-07-23 12:31:34Z msweet $" * * Filtering program for CUPS. * - * Copyright 2007-2011 by Apple Inc. + * Copyright 2007-2013 by Apple Inc. * Copyright 1997-2006 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -102,7 +102,7 @@ static int open_pipe(int *fds); static int read_cupsd_conf(const char *filename); static void set_string(char **s, const char *val); static void sighandler(int sig); -static void usage(const char *command, const char *opt); +static void usage(const char *opt) __attribute__((noreturn)); /* @@ -192,7 +192,7 @@ main(int argc, /* I - Number of command-line args */ if (i < argc && !infile) infile = argv[i]; else - usage(command, opt); + usage(opt); break; case 'a' : /* Specify option... */ @@ -200,7 +200,7 @@ main(int argc, /* I - Number of command-line args */ if (i < argc) num_options = cupsParseOptions(argv[i], num_options, &options); else - usage(command, opt); + usage(opt); break; case 'c' : /* Specify cupsd.conf file location... */ @@ -214,7 +214,7 @@ main(int argc, /* I - Number of command-line args */ strlcpy(cupsdconf, argv[i], sizeof(cupsdconf)); } else - usage(command, opt); + usage(opt); break; case 'd' : /* Specify the real printer name */ @@ -222,7 +222,7 @@ main(int argc, /* I - Number of command-line args */ if (i < argc) printer = argv[i]; else - usage(command, opt); + usage(opt); break; case 'D' : /* Delete input file after conversion */ @@ -238,7 +238,7 @@ main(int argc, /* I - Number of command-line args */ if (i < argc && !infile) infile = argv[i]; else - usage(command, opt); + usage(opt); break; case 'i' : /* Specify source MIME type... */ @@ -246,12 +246,12 @@ main(int argc, /* I - Number of command-line args */ if (i < argc) { if (sscanf(argv[i], "%15[^/]/%255s", super, type) != 2) - usage(command, opt); + usage(opt); srctype = argv[i]; } else - usage(command, opt); + usage(opt); break; case 'j' : /* Get job file or specify destination MIME type... */ @@ -264,7 +264,7 @@ main(int argc, /* I - Number of command-line args */ infile = TempFile; } else - usage(command, opt); + usage(opt); break; } @@ -274,12 +274,12 @@ main(int argc, /* I - Number of command-line args */ if (i < argc) { if (sscanf(argv[i], "%15[^/]/%255s", super, type) != 2) - usage(command, opt); + usage(opt); dsttype = argv[i]; } else - usage(command, opt); + usage(opt); break; case 'n' : /* Specify number of copies... */ @@ -288,7 +288,7 @@ main(int argc, /* I - Number of command-line args */ num_options = cupsAddOption("copies", argv[i], num_options, &options); else - usage(command, opt); + usage(opt); break; case 'o' : /* Specify option(s) or output filename */ @@ -298,7 +298,7 @@ main(int argc, /* I - Number of command-line args */ if (!strcmp(command, "convert")) { if (outfile) - usage(command, NULL); + usage(NULL); else outfile = argv[i]; } @@ -307,7 +307,7 @@ main(int argc, /* I - Number of command-line args */ &options); } else - usage(command, opt); + usage(opt); break; case 'p' : /* Specify PPD file... */ @@ -316,7 +316,7 @@ main(int argc, /* I - Number of command-line args */ if (i < argc) ppdfile = argv[i]; else - usage(command, opt); + usage(opt); break; case 't' : /* Specify title... */ @@ -325,7 +325,7 @@ main(int argc, /* I - Number of command-line args */ if (i < argc) title = argv[i]; else - usage(command, opt); + usage(opt); break; case 'u' : /* Delete PPD file after conversion */ @@ -337,11 +337,11 @@ main(int argc, /* I - Number of command-line args */ if (i < argc) user = argv[i]; else - usage(command, opt); + usage(opt); break; default : /* Something we don't understand... */ - usage(command, opt); + usage(opt); break; } } @@ -350,22 +350,17 @@ main(int argc, /* I - Number of command-line args */ if (strcmp(command, "convert")) infile = argv[i]; else - { - _cupsLangPuts(stderr, - _("convert: Use the -f option to specify a file to " - "convert.")); - usage(command, NULL); - } + usage(NULL); } else { _cupsLangPuts(stderr, _("cupsfilter: Only one filename can be specified.")); - usage(command, NULL); + usage(NULL); } if (!infile && !srctype) - usage(command, NULL); + usage(NULL); if (!title) { @@ -414,6 +409,7 @@ main(int argc, /* I - Number of command-line args */ if (srctype) { + /* sscanf return value already checked above */ sscanf(srctype, "%15[^/]/%255s", super, type); if ((src = mimeType(mime, super, type)) == NULL) { @@ -431,6 +427,7 @@ main(int argc, /* I - Number of command-line args */ return (1); } + /* sscanf return value already checked above */ sscanf(dsttype, "%15[^/]/%255s", super, type); if (!_cups_strcasecmp(super, "printer")) dst = printer_type; @@ -658,7 +655,7 @@ add_printer_filters( mime_type_t *printer_type; /* Printer filter type */ - if ((ppd = ppdOpenFile(ppdfile)) == NULL) + if ((ppd = _ppdOpenFile(ppdfile, _PPD_LOCALIZATION_NONE)) == NULL) { ppd_status_t status; /* PPD load status */ int linenum; /* Line number */ @@ -920,7 +917,7 @@ exec_filters(mime_type_t *srctype, /* I - Source type */ { int i; /* Looping var */ const char *argv[8], /* Command-line arguments */ - *envp[15], /* Environment variables */ + *envp[16], /* Environment variables */ *temp; /* Temporary string */ char *optstr, /* Filter options */ content_type[1024], /* CONTENT_TYPE */ @@ -1043,7 +1040,8 @@ exec_filters(mime_type_t *srctype, /* I - Source type */ envp[11] = printer_name; envp[12] = rip_max_cache; envp[13] = userenv; - envp[14] = NULL; + envp[14] = "CHARSET=utf-8"; + envp[15] = NULL; for (i = 0; argv[i]; i ++) fprintf(stderr, "DEBUG: argv[%d]=\"%s\"\n", i, argv[i]); @@ -1425,70 +1423,41 @@ sighandler(int s) /* I - Signal number */ */ static void -usage(const char *command, /* I - Command name */ - const char *opt) /* I - Incorrect option, if any */ +usage(const char *opt) /* I - Incorrect option, if any */ { if (opt) - _cupsLangPrintf(stderr, _("%s: Unknown option \"%c\"."), command, *opt); - - if (!strcmp(command, "cupsfilter")) - { - _cupsLangPuts(stdout, _("Usage: cupsfilter [ options ] filename")); - _cupsLangPuts(stdout, _("Options:")); - _cupsLangPuts(stdout, _(" -D Remove the input file " - "when finished.")); - _cupsLangPuts(stdout, _(" -P filename.ppd Set PPD file.")); - _cupsLangPuts(stdout, _(" -U username Set username for job.")); - _cupsLangPuts(stdout, _(" -c cupsd.conf Set cupsd.conf file to " - "use.")); - _cupsLangPuts(stdout, _(" -d printer Use the named " - "printer.")); - _cupsLangPuts(stdout, _(" -e Use every filter from " - "the PPD file.")); - _cupsLangPuts(stdout, _(" -i mime/type Set input MIME type " - "(otherwise auto-typed).")); - _cupsLangPuts(stdout, _(" -j job-id[,N] Filter file N from the " - "specified job (default is file 1).")); - _cupsLangPuts(stdout, _(" -m mime/type Set output MIME type " - "(otherwise application/pdf).")); - _cupsLangPuts(stdout, _(" -n copies Set number of copies.")); - _cupsLangPuts(stdout, _(" -o name=value Set option(s).")); - _cupsLangPuts(stdout, _(" -p filename.ppd Set PPD file.")); - _cupsLangPuts(stdout, _(" -t title Set title.")); - _cupsLangPuts(stdout, _(" -u Remove the PPD file " - "when finished.")); - } - else - { - _cupsLangPuts(stdout, _("Usage: convert [ options ]")); - _cupsLangPuts(stdout, _("Options:")); - _cupsLangPuts(stdout, _(" -D Remove the input file " - "when finished.")); - _cupsLangPuts(stdout, _(" -J title Set title.")); - _cupsLangPuts(stdout, _(" -P filename.ppd Set PPD file.")); - _cupsLangPuts(stdout, _(" -U username Set username for job.")); - _cupsLangPuts(stdout, _(" -a 'name=value ...' Set option(s).")); - _cupsLangPuts(stdout, _(" -c copies Set number of copies.")); - _cupsLangPuts(stdout, _(" -d printer Use the named " - "printer.")); - _cupsLangPuts(stdout, _(" -e Use every filter from " - "the PPD file.")); - _cupsLangPuts(stdout, _(" -f filename Set file to be " - "converted (otherwise stdin).")); - _cupsLangPuts(stdout, _(" -i mime/type Set input MIME type " - "(otherwise auto-typed).")); - _cupsLangPuts(stdout, _(" -j mime/type Set output MIME type " - "(otherwise application/pdf).")); - _cupsLangPuts(stdout, _(" -o filename Set file to be " - "generated (otherwise stdout).")); - _cupsLangPuts(stdout, _(" -u Remove the PPD file " - "when finished.")); - } + _cupsLangPrintf(stderr, _("%s: Unknown option \"%c\"."), "cupsfilter", + *opt); + + _cupsLangPuts(stdout, _("Usage: cupsfilter [ options ] filename")); + _cupsLangPuts(stdout, _("Options:")); + _cupsLangPuts(stdout, _(" -D Remove the input file " + "when finished.")); + _cupsLangPuts(stdout, _(" -P filename.ppd Set PPD file.")); + _cupsLangPuts(stdout, _(" -U username Specify username.")); + _cupsLangPuts(stdout, _(" -c cupsd.conf Set cupsd.conf file to " + "use.")); + _cupsLangPuts(stdout, _(" -d printer Use the named " + "printer.")); + _cupsLangPuts(stdout, _(" -e Use every filter from " + "the PPD file.")); + _cupsLangPuts(stdout, _(" -i mime/type Set input MIME type " + "(otherwise auto-typed).")); + _cupsLangPuts(stdout, _(" -j job-id[,N] Filter file N from the " + "specified job (default is file 1).")); + _cupsLangPuts(stdout, _(" -m mime/type Set output MIME type " + "(otherwise application/pdf).")); + _cupsLangPuts(stdout, _(" -n copies Set number of copies.")); + _cupsLangPuts(stdout, _(" -o name=value Set option(s).")); + _cupsLangPuts(stdout, _(" -p filename.ppd Set PPD file.")); + _cupsLangPuts(stdout, _(" -t title Set title.")); + _cupsLangPuts(stdout, _(" -u Remove the PPD file " + "when finished.")); exit(1); } /* - * End of "$Id: cupsfilter.c 9862 2011-08-03 02:44:09Z mike $". + * End of "$Id: cupsfilter.c 11173 2013-07-23 12:31:34Z msweet $". */ diff --git a/scheduler/dirsvc.c b/scheduler/dirsvc.c index 00e8807..bce0d64 100644 --- a/scheduler/dirsvc.c +++ b/scheduler/dirsvc.c @@ -1,9 +1,9 @@ /* - * "$Id: dirsvc.c 10243 2012-02-11 02:05:21Z mike $" + * "$Id: dirsvc.c 11173 2013-07-23 12:31:34Z msweet $" * * Directory services routines for the CUPS scheduler. * - * Copyright 2007-2011 by Apple Inc. + * Copyright 2007-2012 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -14,68 +14,33 @@ * * Contents: * - * cupsdDeregisterPrinter() - Stop sending broadcast information for a local - * printer and remove any pending references to - * remote printers. - * cupsdLoadRemoteCache() - Load the remote printer cache. - * cupsdRegisterPrinter() - Start sending broadcast information for a - * printer or update the broadcast contents. - * cupsdRestartPolling() - Restart polling servers as needed. - * cupsdSaveRemoteCache() - Save the remote printer cache. - * cupsdSendBrowseList() - Send new browsing information as necessary. - * ldap_rebind_proc() - Callback function for LDAP rebind - * ldap_connect() - Start new LDAP connection - * ldap_reconnect() - Reconnect to LDAP Server - * ldap_disconnect() - Disconnect from LDAP Server - * cupsdStartBrowsing() - Start sending and receiving broadcast - * information. - * cupsdStartPolling() - Start polling servers as needed. - * cupsdStopBrowsing() - Stop sending and receiving broadcast - * information. - * cupsdStopPolling() - Stop polling servers as needed. - * cupsdUpdateDNSSDName() - Update the computer name we use for - * browsing... - * cupsdUpdateLDAPBrowse() - Scan for new printers via LDAP... - * cupsdUpdateSLPBrowse() - Get browsing information via SLP. - * dequote() - Remote quotes from a string. - * dnssdAddAlias() - Add a DNS-SD alias name. - * dnssdBuildTxtRecord() - Build a TXT record from printer info. - * dnssdComparePrinters() - Compare the registered names of two printers. - * dnssdDeregisterPrinter() - Stop sending broadcast information for a - * printer. - * dnssdPackTxtRecord() - Pack an array of key/value pairs into the TXT - * record format. - * dnssdRegisterCallback() - DNSServiceRegister callback. - * dnssdRegisterPrinter() - Start sending broadcast information for a - * printer or update the broadcast contents. - * dnssdStop() - Stop all DNS-SD registrations. - * dnssdUpdate() - Handle DNS-SD queries. - * get_auth_info_required() - Get the auth-info-required value to advertise. - * get_hostconfig() - Get an /etc/hostconfig service setting. - * is_local_queue() - Determine whether the URI points at a local - * queue. - * process_browse_data() - Process new browse data. - * process_implicit_classes() - Create/update implicit classes as needed. - * send_cups_browse() - Send new browsing information using the CUPS - * protocol. - * ldap_search_rec() - LDAP Search with reconnect - * ldap_freeres() - Free LDAPMessage - * ldap_getval_char() - Get first LDAP value and convert to string - * send_ldap_ou() - Send LDAP ou registrations. - * send_ldap_browse() - Send LDAP printer registrations. - * ldap_dereg_printer() - Delete printer from directory - * ldap_dereg_ou() - Remove the organizational unit. - * send_slp_browse() - Register the specified printer with SLP. - * slp_attr_callback() - SLP attribute callback - * slp_dereg_printer() - SLPDereg() the specified printer - * slp_get_attr() - Get an attribute from an SLP registration. - * slp_reg_callback() - Empty SLPRegReport. - * slp_url_callback() - SLP service url callback - * update_cups_browse() - Update the browse lists using the CUPS - * protocol. - * update_lpd() - Update the LPD configuration as needed. - * update_polling() - Read status messages from the poll daemons. - * update_smb() - Update the SMB configuration as needed. + * cupsdDeregisterPrinter() - Stop sending broadcast information for a local + * printer and remove any pending references to + * remote printers. + * cupsdRegisterPrinter() - Start sending broadcast information for a + * printer or update the broadcast contents. + * cupsdStartBrowsing() - Start sending and receiving broadcast + * information. + * cupsdStopBrowsing() - Stop sending and receiving broadcast + * information. + * cupsdUpdateDNSSDName() - Update the computer name we use for + * browsing... + * dnssdAddAlias() - Add a DNS-SD alias name. + * dnssdBuildTxtRecord() - Build a TXT record from printer info. + * dnssdDeregisterInstance() - Deregister a DNS-SD service instance. + * dnssdDeregisterPrinter() - Deregister all services for a printer. + * dnssdErrorString() - Return an error string for an error code. + * dnssdRegisterCallback() - Free a TXT record. + * dnssdRegisterCallback() - DNSServiceRegister callback. + * dnssdRegisterInstance() - Register an instance of a printer service. + * dnssdRegisterPrinter() - Start sending broadcast information for a + * printer or update the broadcast contents. + * dnssdStop() - Stop all DNS-SD registrations. + * dnssdUpdate() - Handle DNS-SD queries. + * get_auth_info_required() - Get the auth-info-required value to advertise. + * get_hostconfig() - Get an /etc/hostconfig service setting. + * update_lpd() - Update the LPD configuration as needed. + * update_smb() - Update the SMB configuration as needed. */ /* @@ -85,153 +50,63 @@ #include "cupsd.h" #include <grp.h> -#ifdef HAVE_DNSSD -# include <dns_sd.h> -# ifdef __APPLE__ -# include <nameser.h> -# ifdef HAVE_COREFOUNDATION -# include <CoreFoundation/CoreFoundation.h> -# endif /* HAVE_COREFOUNDATION */ -# ifdef HAVE_SYSTEMCONFIGURATION -# include <SystemConfiguration/SystemConfiguration.h> -# endif /* HAVE_SYSTEMCONFIGURATION */ -# endif /* __APPLE__ */ -#endif /* HAVE_DNSSD */ +#if defined(HAVE_DNSSD) && defined(__APPLE__) +# include <nameser.h> +# include <CoreFoundation/CoreFoundation.h> +# include <SystemConfiguration/SystemConfiguration.h> +#endif /* HAVE_DNSSD && __APPLE__ */ /* * Local functions... */ -static char *dequote(char *d, const char *s, int dlen); -static char *get_auth_info_required(cupsd_printer_t *p, char *buffer, - size_t bufsize); +#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) +static char *get_auth_info_required(cupsd_printer_t *p, + char *buffer, size_t bufsize); +#endif /* HAVE_DNSSD || HAVE_AVAHI */ #ifdef __APPLE__ -static int get_hostconfig(const char *name); +static int get_hostconfig(const char *name); #endif /* __APPLE__ */ -static int is_local_queue(const char *uri, char *host, int hostlen, - char *resource, int resourcelen); -static void process_browse_data(const char *uri, const char *host, - const char *resource, cups_ptype_t type, - ipp_pstate_t state, const char *location, - const char *info, const char *make_model, - int num_attrs, cups_option_t *attrs); -static void process_implicit_classes(void); -static void send_cups_browse(cupsd_printer_t *p); -#ifdef HAVE_LDAP -static LDAP *ldap_connect(void); -static LDAP *ldap_reconnect(void); -static void ldap_disconnect(LDAP *ld); -static int ldap_search_rec(LDAP *ld, char *base, int scope, - char *filter, char *attrs[], - int attrsonly, LDAPMessage **res); -static int ldap_getval_firststring(LDAP *ld, LDAPMessage *entry, - char *attr, char *retval, - unsigned long maxsize); -static void ldap_freeres(LDAPMessage *entry); -static void send_ldap_ou(char *ou, char *basedn, char *descstring); -static void send_ldap_browse(cupsd_printer_t *p); -static void ldap_dereg_printer(cupsd_printer_t *p); -static void ldap_dereg_ou(char *ou, char *basedn); -# ifdef HAVE_LDAP_REBIND_PROC -# if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000) -static int ldap_rebind_proc(LDAP *RebindLDAPHandle, - LDAP_CONST char *refsp, - ber_tag_t request, - ber_int_t msgid, - void *params); -# else -static int ldap_rebind_proc(LDAP *RebindLDAPHandle, - char **dnp, - char **passwdp, - int *authmethodp, - int freeit, - void *arg); -# endif /* defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000) */ -# endif /* HAVE_LDAP_REBIND_PROC */ -#endif /* HAVE_LDAP */ -#ifdef HAVE_LIBSLP -static void send_slp_browse(cupsd_printer_t *p); -#endif /* HAVE_LIBSLP */ -static void update_cups_browse(void); -static void update_lpd(int onoff); -static void update_polling(void); -static void update_smb(int onoff); - - -#ifdef HAVE_DNSSD -# ifdef HAVE_COREFOUNDATION -static void dnssdAddAlias(const void *key, const void *value, - void *context); -# endif /* HAVE_COREFOUNDATION */ -static char *dnssdBuildTxtRecord(int *txt_len, cupsd_printer_t *p, - int for_lpd); -static int dnssdComparePrinters(cupsd_printer_t *a, cupsd_printer_t *b); -static void dnssdDeregisterPrinter(cupsd_printer_t *p); -static char *dnssdPackTxtRecord(int *txt_len, char *keyvalue[][2], - int count); -static void dnssdRegisterCallback(DNSServiceRef sdRef, - DNSServiceFlags flags, - DNSServiceErrorType errorCode, - const char *name, const char *regtype, - const char *domain, void *context); -static void dnssdRegisterPrinter(cupsd_printer_t *p); -static void dnssdStop(void); -static void dnssdUpdate(void); -#endif /* HAVE_DNSSD */ - -#ifdef HAVE_LDAP -static const char * const ldap_attrs[] =/* CUPS LDAP attributes */ - { - "printerDescription", - "printerLocation", - "printerMakeAndModel", - "printerType", - "printerURI", - NULL - }; -#endif /* HAVE_LDAP */ - -#ifdef HAVE_LIBSLP -/* - * SLP definitions... - */ - -/* - * SLP service name for CUPS... - */ - -# define SLP_CUPS_SRVTYPE "service:printer" -# define SLP_CUPS_SRVLEN 15 - +static void update_lpd(int onoff); +static void update_smb(int onoff); -/* - * Printer service URL structure - */ - -typedef struct _slpsrvurl_s /**** SLP URL list ****/ -{ - struct _slpsrvurl_s *next; /* Next URL in list */ - char url[HTTP_MAX_URI]; - /* URL */ -} slpsrvurl_t; - - -/* - * Local functions... - */ -static SLPBoolean slp_attr_callback(SLPHandle hslp, const char *attrlist, - SLPError errcode, void *cookie); -static void slp_dereg_printer(cupsd_printer_t *p); -static int slp_get_attr(const char *attrlist, const char *tag, - char **valbuf); -static void slp_reg_callback(SLPHandle hslp, SLPError errcode, - void *cookie); -static SLPBoolean slp_url_callback(SLPHandle hslp, const char *srvurl, - unsigned short lifetime, - SLPError errcode, void *cookie); -#endif /* HAVE_LIBSLP */ +#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) +# ifdef __APPLE__ +static void dnssdAddAlias(const void *key, const void *value, + void *context); +# endif /* __APPLE__ */ +static cupsd_txt_t dnssdBuildTxtRecord(cupsd_printer_t *p, int for_lpd); +static void dnssdDeregisterInstance(cupsd_srv_t *srv); +static void dnssdDeregisterPrinter(cupsd_printer_t *p, + int clear_name); +static const char *dnssdErrorString(int error); +static void dnssdFreeTxtRecord(cupsd_txt_t *txt); +# ifdef HAVE_DNSSD +static void dnssdRegisterCallback(DNSServiceRef sdRef, + DNSServiceFlags flags, + DNSServiceErrorType errorCode, + const char *name, + const char *regtype, + const char *domain, + void *context); +# else +static void dnssdRegisterCallback(AvahiEntryGroup *p, + AvahiEntryGroupState state, + void *context); +# endif /* HAVE_DNSSD */ +static int dnssdRegisterInstance(cupsd_srv_t *srv, + cupsd_printer_t *p, + char *name, const char *type, + const char *subtypes, int port, + cupsd_txt_t *txt, int commit); +static void dnssdRegisterPrinter(cupsd_printer_t *p); +static void dnssdStop(void); +# ifdef HAVE_DNSSD +static void dnssdUpdate(void); +# endif /* HAVE_DNSSD */ +#endif /* HAVE_DNSSD || HAVE_AVAHI */ /* @@ -254,430 +129,17 @@ cupsdDeregisterPrinter( removeit); if (!Browsing || !p->shared || - (p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT | - CUPS_PRINTER_SCANNER))) + (p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_SCANNER))) return; /* * Announce the deletion... */ - if ((BrowseLocalProtocols & BROWSE_CUPS) && BrowseSocket >= 0) - { - cups_ptype_t savedtype = p->type; /* Saved printer type */ - - p->type |= CUPS_PRINTER_DELETE; - - send_cups_browse(p); - - p->type = savedtype; - } - -#ifdef HAVE_LIBSLP - if (BrowseLocalProtocols & BROWSE_SLP) - slp_dereg_printer(p); -#endif /* HAVE_LIBSLP */ - -#ifdef HAVE_LDAP - if (BrowseLocalProtocols & BROWSE_LDAP) - ldap_dereg_printer(p); -#endif /* HAVE_LDAP */ - -#ifdef HAVE_DNSSD - if (removeit && (BrowseLocalProtocols & BROWSE_DNSSD) && DNSSDRef) - dnssdDeregisterPrinter(p); -#endif /* HAVE_DNSSD */ -} - - -/* - * 'cupsdLoadRemoteCache()' - Load the remote printer cache. - */ - -void -cupsdLoadRemoteCache(void) -{ - int i; /* Looping var */ - cups_file_t *fp; /* remote.cache file */ - int linenum; /* Current line number */ - char line[4096], /* Line from file */ - *value, /* Pointer to value */ - *valueptr, /* Pointer into value */ - scheme[32], /* Scheme portion of URI */ - username[64], /* Username portion of URI */ - host[HTTP_MAX_HOST], - /* Hostname portion of URI */ - resource[HTTP_MAX_URI]; - /* Resource portion of URI */ - int port; /* Port number */ - cupsd_printer_t *p; /* Current printer */ - time_t now; /* Current time */ - - - /* - * Don't load the cache if the remote protocols are disabled... - */ - - if (!Browsing) - { - cupsdLogMessage(CUPSD_LOG_DEBUG, - "cupsdLoadRemoteCache: Not loading remote cache."); - return; - } - - /* - * Open the remote.cache file... - */ - - snprintf(line, sizeof(line), "%s/remote.cache", CacheDir); - if ((fp = cupsdOpenConfFile(line)) == NULL) - return; - - /* - * Read printer configurations until we hit EOF... - */ - - linenum = 0; - p = NULL; - now = time(NULL); - - while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum)) - { - /* - * Decode the directive... - */ - - if (!_cups_strcasecmp(line, "<Printer") || - !_cups_strcasecmp(line, "<DefaultPrinter")) - { - /* - * <Printer name> or <DefaultPrinter name> - */ - - if (p == NULL && value) - { - /* - * Add the printer and a base file type... - */ - - cupsdLogMessage(CUPSD_LOG_DEBUG, - "cupsdLoadRemoteCache: Loading printer %s...", value); - - if ((p = cupsdFindDest(value)) != NULL) - { - if (p->type & CUPS_PRINTER_CLASS) - { - cupsdLogMessage(CUPSD_LOG_WARN, - "Cached remote printer \"%s\" conflicts with " - "existing class!", - value); - p = NULL; - continue; - } - } - else - p = cupsdAddPrinter(value); - - p->accepting = 1; - p->state = IPP_PRINTER_IDLE; - p->type |= CUPS_PRINTER_REMOTE | CUPS_PRINTER_DISCOVERED; - p->browse_time = now; - p->browse_expire = now + BrowseTimeout; - - /* - * Set the default printer as needed... - */ - - if (!_cups_strcasecmp(line, "<DefaultPrinter")) - DefaultPrinter = p; - } - else - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "Syntax error on line %d of remote.cache.", linenum); - break; - } - } - else if (!_cups_strcasecmp(line, "<Class") || - !_cups_strcasecmp(line, "<DefaultClass")) - { - /* - * <Class name> or <DefaultClass name> - */ - - if (p == NULL && value) - { - /* - * Add the printer and a base file type... - */ - - cupsdLogMessage(CUPSD_LOG_DEBUG, - "cupsdLoadRemoteCache: Loading class %s...", value); - - if ((p = cupsdFindDest(value)) != NULL) - p->type = CUPS_PRINTER_CLASS; - else - p = cupsdAddClass(value); - - p->accepting = 1; - p->state = IPP_PRINTER_IDLE; - p->type |= CUPS_PRINTER_REMOTE | CUPS_PRINTER_DISCOVERED; - p->browse_time = now; - p->browse_expire = now + BrowseTimeout; - - /* - * Set the default printer as needed... - */ - - if (!_cups_strcasecmp(line, "<DefaultClass")) - DefaultPrinter = p; - } - else - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "Syntax error on line %d of remote.cache.", linenum); - break; - } - } - else if (!_cups_strcasecmp(line, "</Printer>") || - !_cups_strcasecmp(line, "</Class>")) - { - if (p != NULL) - { - /* - * Close out the current printer... - */ - - cupsdSetPrinterAttrs(p); - - p = NULL; - } - else - cupsdLogMessage(CUPSD_LOG_ERROR, - "Syntax error on line %d of remote.cache.", linenum); - } - else if (!p) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "Syntax error on line %d of remote.cache.", linenum); - } - else if (!_cups_strcasecmp(line, "UUID")) - { - if (value && !strncmp(value, "urn:uuid:", 9)) - cupsdSetString(&(p->uuid), value); - else - cupsdLogMessage(CUPSD_LOG_ERROR, - "Bad UUID on line %d of remote.cache.", linenum); - } - else if (!_cups_strcasecmp(line, "Info")) - { - if (value) - cupsdSetString(&p->info, value); - } - else if (!_cups_strcasecmp(line, "MakeModel")) - { - if (value) - cupsdSetString(&p->make_model, value); - } - else if (!_cups_strcasecmp(line, "Location")) - { - if (value) - cupsdSetString(&p->location, value); - } - else if (!_cups_strcasecmp(line, "DeviceURI")) - { - if (value) - { - httpSeparateURI(HTTP_URI_CODING_ALL, value, scheme, sizeof(scheme), - username, sizeof(username), host, sizeof(host), &port, - resource, sizeof(resource)); - - cupsdSetString(&p->hostname, host); - cupsdSetString(&p->uri, value); - cupsdSetDeviceURI(p, value); - } - else - cupsdLogMessage(CUPSD_LOG_ERROR, - "Syntax error on line %d of remote.cache.", linenum); - } - else if (!_cups_strcasecmp(line, "Option") && value) - { - /* - * Option name value - */ - - for (valueptr = value; *valueptr && !isspace(*valueptr & 255); valueptr ++); - - if (!*valueptr) - cupsdLogMessage(CUPSD_LOG_ERROR, - "Syntax error on line %d of remote.cache.", linenum); - else - { - for (; *valueptr && isspace(*valueptr & 255); *valueptr++ = '\0'); - - p->num_options = cupsAddOption(value, valueptr, p->num_options, - &(p->options)); - } - } - else if (!_cups_strcasecmp(line, "Reason")) - { - if (value) - { - for (i = 0 ; i < p->num_reasons; i ++) - if (!strcmp(value, p->reasons[i])) - break; - - if (i >= p->num_reasons && - p->num_reasons < (int)(sizeof(p->reasons) / sizeof(p->reasons[0]))) - { - p->reasons[p->num_reasons] = _cupsStrAlloc(value); - p->num_reasons ++; - } - } - else - cupsdLogMessage(CUPSD_LOG_ERROR, - "Syntax error on line %d of remote.cache.", linenum); - } - else if (!_cups_strcasecmp(line, "State")) - { - /* - * Set the initial queue state... - */ - - if (value && !_cups_strcasecmp(value, "idle")) - p->state = IPP_PRINTER_IDLE; - else if (value && !_cups_strcasecmp(value, "stopped")) - { - p->state = IPP_PRINTER_STOPPED; - cupsdSetPrinterReasons(p, "+paused"); - } - else - cupsdLogMessage(CUPSD_LOG_ERROR, - "Syntax error on line %d of remote.cache.", linenum); - } - else if (!_cups_strcasecmp(line, "StateMessage")) - { - /* - * Set the initial queue state message... - */ - - if (value) - strlcpy(p->state_message, value, sizeof(p->state_message)); - } - else if (!_cups_strcasecmp(line, "Accepting")) - { - /* - * Set the initial accepting state... - */ - - if (value && - (!_cups_strcasecmp(value, "yes") || - !_cups_strcasecmp(value, "on") || - !_cups_strcasecmp(value, "true"))) - p->accepting = 1; - else if (value && - (!_cups_strcasecmp(value, "no") || - !_cups_strcasecmp(value, "off") || - !_cups_strcasecmp(value, "false"))) - p->accepting = 0; - else - cupsdLogMessage(CUPSD_LOG_ERROR, - "Syntax error on line %d of remote.cache.", linenum); - } - else if (!_cups_strcasecmp(line, "Type")) - { - if (value) - p->type = atoi(value); - else - cupsdLogMessage(CUPSD_LOG_ERROR, - "Syntax error on line %d of remote.cache.", linenum); - } - else if (!_cups_strcasecmp(line, "BrowseTime")) - { - if (value) - { - time_t t = atoi(value); - - if (t > p->browse_expire) - p->browse_expire = t; - } - else - cupsdLogMessage(CUPSD_LOG_ERROR, - "Syntax error on line %d of remote.cache.", linenum); - } - else if (!_cups_strcasecmp(line, "JobSheets")) - { - /* - * Set the initial job sheets... - */ - - if (value) - { - for (valueptr = value; *valueptr && !isspace(*valueptr & 255); valueptr ++); - - if (*valueptr) - *valueptr++ = '\0'; - - cupsdSetString(&p->job_sheets[0], value); - - while (isspace(*valueptr & 255)) - valueptr ++; - - if (*valueptr) - { - for (value = valueptr; *valueptr && !isspace(*valueptr & 255); valueptr ++); - - if (*valueptr) - *valueptr = '\0'; - - cupsdSetString(&p->job_sheets[1], value); - } - } - else - cupsdLogMessage(CUPSD_LOG_ERROR, - "Syntax error on line %d of remote.cache.", linenum); - } - else if (!_cups_strcasecmp(line, "AllowUser")) - { - if (value) - { - p->deny_users = 0; - cupsdAddString(&(p->users), value); - } - else - cupsdLogMessage(CUPSD_LOG_ERROR, - "Syntax error on line %d of remote.cache.", linenum); - } - else if (!_cups_strcasecmp(line, "DenyUser")) - { - if (value) - { - p->deny_users = 1; - cupsdAddString(&(p->users), value); - } - else - cupsdLogMessage(CUPSD_LOG_ERROR, - "Syntax error on line %d of remote.cache.", linenum); - } - else - { - /* - * Something else we don't understand... - */ - - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unknown configuration directive %s on line %d of remote.cache.", - line, linenum); - } - } - - cupsFileClose(fp); - - /* - * Do auto-classing if needed... - */ - - process_implicit_classes(); +#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) + if (removeit && (BrowseLocalProtocols & BROWSE_DNSSD) && DNSSDMaster) + dnssdDeregisterPrinter(p, 1); +#endif /* HAVE_DNSSD || HAVE_AVAHI */ } @@ -693,730 +155,14 @@ cupsdRegisterPrinter(cupsd_printer_t *p)/* I - Printer */ p->name); if (!Browsing || !BrowseLocalProtocols || - (p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT | - CUPS_PRINTER_SCANNER))) + (p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_SCANNER))) return; -#ifdef HAVE_LIBSLP -/* if (BrowseLocalProtocols & BROWSE_SLP) - slpRegisterPrinter(p); */ -#endif /* HAVE_LIBSLP */ - -#ifdef HAVE_DNSSD - if ((BrowseLocalProtocols & BROWSE_DNSSD) && DNSSDRef) +#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) + if ((BrowseLocalProtocols & BROWSE_DNSSD) && DNSSDMaster) dnssdRegisterPrinter(p); -#endif /* HAVE_DNSSD */ -} - - -/* - * 'cupsdRestartPolling()' - Restart polling servers as needed. - */ - -void -cupsdRestartPolling(void) -{ - int i; /* Looping var */ - cupsd_dirsvc_poll_t *pollp; /* Current polling server */ - - - for (i = 0, pollp = Polled; i < NumPolled; i ++, pollp ++) - if (pollp->pid) - kill(pollp->pid, SIGHUP); -} - - -/* - * 'cupsdSaveRemoteCache()' - Save the remote printer cache. - */ - -void -cupsdSaveRemoteCache(void) -{ - int i; /* Looping var */ - cups_file_t *fp; /* remote.cache file */ - char filename[1024], /* remote.cache filename */ - temp[1024], /* Temporary string */ - value[2048], /* Value string */ - *name; /* Current user name */ - cupsd_printer_t *printer; /* Current printer class */ - time_t curtime; /* Current time */ - struct tm *curdate; /* Current date */ - cups_option_t *option; /* Current option */ - - - /* - * Create the remote.cache file... - */ - - snprintf(filename, sizeof(filename), "%s/remote.cache", CacheDir); - - if ((fp = cupsdCreateConfFile(filename, ConfigFilePerm)) == NULL) - return; - - cupsdLogMessage(CUPSD_LOG_DEBUG, "Saving remote.cache..."); - - /* - * Write a small header to the file... - */ - - curtime = time(NULL); - curdate = localtime(&curtime); - strftime(temp, sizeof(temp) - 1, "%Y-%m-%d %H:%M", curdate); - - cupsFilePuts(fp, "# Remote cache file for " CUPS_SVERSION "\n"); - cupsFilePrintf(fp, "# Written by cupsd on %s\n", temp); - - /* - * Write each local printer known to the system... - */ - - for (printer = (cupsd_printer_t *)cupsArrayFirst(Printers); - printer; - printer = (cupsd_printer_t *)cupsArrayNext(Printers)) - { - /* - * Skip local destinations... - */ - - if (!(printer->type & CUPS_PRINTER_DISCOVERED)) - continue; - - /* - * Write printers as needed... - */ - - if (printer == DefaultPrinter) - cupsFilePuts(fp, "<Default"); - else - cupsFilePutChar(fp, '<'); - - if (printer->type & CUPS_PRINTER_CLASS) - cupsFilePrintf(fp, "Class %s>\n", printer->name); - else - cupsFilePrintf(fp, "Printer %s>\n", printer->name); - - cupsFilePrintf(fp, "BrowseTime %d\n", (int)printer->browse_expire); - - cupsFilePrintf(fp, "UUID %s\n", printer->uuid); - - if (printer->info) - cupsFilePutConf(fp, "Info", printer->info); - - if (printer->location) - cupsFilePutConf(fp, "Location", printer->location); - - if (printer->make_model) - cupsFilePutConf(fp, "MakeModel", printer->make_model); - - cupsFilePutConf(fp, "DeviceURI", printer->device_uri); - - if (printer->state == IPP_PRINTER_STOPPED) - cupsFilePuts(fp, "State Stopped\n"); - else - cupsFilePuts(fp, "State Idle\n"); - - for (i = 0; i < printer->num_reasons; i ++) - cupsFilePutConf(fp, "Reason", printer->reasons[i]); - - cupsFilePrintf(fp, "Type %d\n", printer->type); - - if (printer->accepting) - cupsFilePuts(fp, "Accepting Yes\n"); - else - cupsFilePuts(fp, "Accepting No\n"); - - snprintf(value, sizeof(value), "%s %s", printer->job_sheets[0], - printer->job_sheets[1]); - cupsFilePutConf(fp, "JobSheets", value); - - for (name = (char *)cupsArrayFirst(printer->users); - name; - name = (char *)cupsArrayNext(printer->users)) - cupsFilePutConf(fp, printer->deny_users ? "DenyUser" : "AllowUser", name); - - for (i = printer->num_options, option = printer->options; - i > 0; - i --, option ++) - { - snprintf(value, sizeof(value), "%s %s", option->name, option->value); - cupsFilePutConf(fp, "Option", value); - } - - if (printer->type & CUPS_PRINTER_CLASS) - cupsFilePuts(fp, "</Class>\n"); - else - cupsFilePuts(fp, "</Printer>\n"); - } - - cupsdCloseCreatedConfFile(fp, filename); -} - - -/* - * 'cupsdSendBrowseList()' - Send new browsing information as necessary. - */ - -void -cupsdSendBrowseList(void) -{ - int count; /* Number of dests to update */ - cupsd_printer_t *p; /* Current printer */ - time_t ut, /* Minimum update time */ - to; /* Timeout time */ - - - if (!Browsing || !Printers) - return; - - /* - * Compute the update and timeout times... - */ - - to = time(NULL); - ut = to - BrowseInterval; - - /* - * Figure out how many printers need an update... - */ - - if (BrowseInterval > 0 && BrowseLocalProtocols) - { - int max_count; /* Maximum number to update */ - - - /* - * Throttle the number of printers we'll be updating this time - * around based on the number of queues that need updating and - * the maximum number of queues to update each second... - */ - - max_count = 2 * cupsArrayCount(Printers) / BrowseInterval + 1; - - for (count = 0, p = (cupsd_printer_t *)cupsArrayFirst(Printers); - count < max_count && p != NULL; - p = (cupsd_printer_t *)cupsArrayNext(Printers)) - if (!(p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT | - CUPS_PRINTER_SCANNER)) && - p->shared && p->browse_time < ut) - count ++; - - /* - * Loop through all of the printers and send local updates as needed... - */ - - if (BrowseNext) - p = (cupsd_printer_t *)cupsArrayFind(Printers, BrowseNext); - else - p = (cupsd_printer_t *)cupsArrayFirst(Printers); - - for (; - count > 0; - p = (cupsd_printer_t *)cupsArrayNext(Printers)) - { - /* - * Check for wraparound... - */ - - if (!p) - p = (cupsd_printer_t *)cupsArrayFirst(Printers); - - if (!p) - break; - else if ((p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT | - CUPS_PRINTER_SCANNER)) || - !p->shared) - continue; - else if (p->browse_time < ut) - { - /* - * Need to send an update... - */ - - count --; - - p->browse_time = time(NULL); - - if ((BrowseLocalProtocols & BROWSE_CUPS) && BrowseSocket >= 0) - send_cups_browse(p); - -#ifdef HAVE_LIBSLP - if (BrowseLocalProtocols & BROWSE_SLP) - send_slp_browse(p); -#endif /* HAVE_LIBSLP */ - -#ifdef HAVE_LDAP - if (BrowseLocalProtocols & BROWSE_LDAP) - send_ldap_browse(p); -#endif /* HAVE_LDAP */ - } - } - - /* - * Save where we left off so that all printers get updated... - */ - - BrowseNext = p; - } - - /* - * Loop through all of the printers and timeout old printers as needed... - */ - - for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); - p; - p = (cupsd_printer_t *)cupsArrayNext(Printers)) - { - /* - * If this is a remote queue, see if it needs to be timed out... - */ - - if ((p->type & CUPS_PRINTER_DISCOVERED) && - !(p->type & CUPS_PRINTER_IMPLICIT) && - p->browse_expire < to) - { - cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, p, NULL, - "%s \'%s\' deleted by directory services (timeout).", - (p->type & CUPS_PRINTER_CLASS) ? "Class" : "Printer", - p->name); - - cupsdLogMessage(CUPSD_LOG_DEBUG, - "Remote destination \"%s\" has timed out; " - "deleting it...", - p->name); - - cupsArraySave(Printers); - cupsdDeletePrinter(p, 1); - cupsArrayRestore(Printers); - cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE); - } - } -} - - -#ifdef HAVE_LDAP_REBIND_PROC -# if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000) -/* - * 'ldap_rebind_proc()' - Callback function for LDAP rebind - */ - -static int /* O - Result code */ -ldap_rebind_proc( - LDAP *RebindLDAPHandle, /* I - LDAP handle */ - LDAP_CONST char *refsp, /* I - ??? */ - ber_tag_t request, /* I - ??? */ - ber_int_t msgid, /* I - ??? */ - void *params) /* I - ??? */ -{ - int rc; /* Result code */ -# if LDAP_API_VERSION > 3000 - struct berval bval; /* Bind value */ -# endif /* LDAP_API_VERSION > 3000 */ - - - (void)request; - (void)msgid; - (void)params; - - /* - * Bind to new LDAP server... - */ - - cupsdLogMessage(CUPSD_LOG_DEBUG2, "ldap_rebind_proc: Rebind to %s", refsp); - -# if LDAP_API_VERSION > 3000 - bval.bv_val = BrowseLDAPPassword; - bval.bv_len = (BrowseLDAPPassword == NULL) ? 0 : strlen(BrowseLDAPPassword); - - rc = ldap_sasl_bind_s(RebindLDAPHandle, BrowseLDAPBindDN, LDAP_SASL_SIMPLE, - &bval, NULL, NULL, NULL); -# else - rc = ldap_bind_s(RebindLDAPHandle, BrowseLDAPBindDN, BrowseLDAPPassword, - LDAP_AUTH_SIMPLE); -# endif /* LDAP_API_VERSION > 3000 */ - - return (rc); -} - - -# else /* defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000) */ -/* - * 'ldap_rebind_proc()' - Callback function for LDAP rebind - */ - -static int /* O - Result code */ -ldap_rebind_proc( - LDAP *RebindLDAPHandle, /* I - LDAP handle */ - char **dnp, /* I - ??? */ - char **passwdp, /* I - ??? */ - int *authmethodp, /* I - ??? */ - int freeit, /* I - ??? */ - void *arg) /* I - ??? */ -{ - switch (freeit) - { - case 1: - /* - * Free current values... - */ - - cupsdLogMessage(CUPSD_LOG_DEBUG2, "ldap_rebind_proc: Free values..."); - - if (dnp && *dnp) - free(*dnp); - - if (passwdp && *passwdp) - free(*passwdp); - break; - - case 0: - /* - * Return credentials for LDAP referal... - */ - - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "ldap_rebind_proc: Return necessary values..."); - - *dnp = strdup(BrowseLDAPBindDN); - *passwdp = strdup(BrowseLDAPPassword); - *authmethodp = LDAP_AUTH_SIMPLE; - break; - - default: - /* - * Should never happen... - */ - - cupsdLogMessage(CUPSD_LOG_ERROR, - "LDAP rebind has been called with wrong freeit value!"); - break; - } - - return (LDAP_SUCCESS); -} -# endif /* defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000) */ -#endif /* HAVE_LDAP_REBIND_PROC */ - - -#ifdef HAVE_LDAP -/* - * 'ldap_connect()' - Start new LDAP connection - */ - -static LDAP * /* O - LDAP handle */ -ldap_connect(void) -{ - int rc; /* LDAP API status */ - int version = 3; /* LDAP version */ - struct berval bv = {0, ""}; /* SASL bind value */ - LDAP *TempBrowseLDAPHandle=NULL; - /* Temporary LDAP Handle */ -# if defined(HAVE_LDAP_SSL) && defined (HAVE_MOZILLA_LDAP) - int ldap_ssl = 0; /* LDAP SSL indicator */ - int ssl_err = 0; /* LDAP SSL error value */ -# endif /* defined(HAVE_LDAP_SSL) && defined (HAVE_MOZILLA_LDAP) */ - - -# ifdef HAVE_OPENLDAP -# ifdef HAVE_LDAP_SSL - /* - * Set the certificate file to use for encrypted LDAP sessions... - */ - - if (BrowseLDAPCACertFile) - { - cupsdLogMessage(CUPSD_LOG_DEBUG, - "ldap_connect: Setting CA certificate file \"%s\"", - BrowseLDAPCACertFile); - - if ((rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE, - (void *)BrowseLDAPCACertFile)) != LDAP_SUCCESS) - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to set CA certificate file for LDAP " - "connections: %d - %s", rc, ldap_err2string(rc)); - } -# endif /* HAVE_LDAP_SSL */ - - /* - * Initialize OPENLDAP connection... - * LDAP stuff currently only supports ldapi EXTERNAL SASL binds... - */ - - if (!BrowseLDAPServer || !_cups_strcasecmp(BrowseLDAPServer, "localhost")) - rc = ldap_initialize(&TempBrowseLDAPHandle, "ldapi:///"); - else - rc = ldap_initialize(&TempBrowseLDAPHandle, BrowseLDAPServer); - -# else /* HAVE_OPENLDAP */ - - int ldap_port = 0; /* LDAP port */ - char ldap_protocol[11], /* LDAP protocol */ - ldap_host[255]; /* LDAP host */ - - /* - * Split LDAP URI into its components... - */ - - if (!BrowseLDAPServer) - { - cupsdLogMessage(CUPSD_LOG_ERROR, "BrowseLDAPServer not configured!"); - cupsdLogMessage(CUPSD_LOG_ERROR, "Disabling LDAP browsing!"); - BrowseLocalProtocols &= ~BROWSE_LDAP; - BrowseRemoteProtocols &= ~BROWSE_LDAP; - return (NULL); - } - - sscanf(BrowseLDAPServer, "%10[^:]://%254[^:/]:%d", ldap_protocol, ldap_host, - &ldap_port); - - if (!strcmp(ldap_protocol, "ldap")) - ldap_ssl = 0; - else if (!strcmp(ldap_protocol, "ldaps")) - ldap_ssl = 1; - else - { - cupsdLogMessage(CUPSD_LOG_ERROR, "Unrecognized LDAP protocol (%s)!", - ldap_protocol); - cupsdLogMessage(CUPSD_LOG_ERROR, "Disabling LDAP browsing!"); - BrowseLocalProtocols &= ~BROWSE_LDAP; - BrowseRemoteProtocols &= ~BROWSE_LDAP; - return (NULL); - } - - if (ldap_port == 0) - { - if (ldap_ssl) - ldap_port = LDAPS_PORT; - else - ldap_port = LDAP_PORT; - } - - cupsdLogMessage(CUPSD_LOG_DEBUG, "ldap_connect: PROT:%s HOST:%s PORT:%d", - ldap_protocol, ldap_host, ldap_port); - - /* - * Initialize LDAP connection... - */ - - if (!ldap_ssl) - { - if ((TempBrowseLDAPHandle = ldap_init(ldap_host, ldap_port)) == NULL) - rc = LDAP_OPERATIONS_ERROR; - else - rc = LDAP_SUCCESS; - -# ifdef HAVE_LDAP_SSL - } - else - { - /* - * Initialize SSL LDAP connection... - */ - - if (BrowseLDAPCACertFile) - { - rc = ldapssl_client_init(BrowseLDAPCACertFile, (void *)NULL); - if (rc != LDAP_SUCCESS) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "Failed to initialize LDAP SSL client!"); - rc = LDAP_OPERATIONS_ERROR; - } - else - { - if ((TempBrowseLDAPHandle = ldapssl_init(ldap_host, ldap_port, - 1)) == NULL) - rc = LDAP_OPERATIONS_ERROR; - else - rc = LDAP_SUCCESS; - } - } - else - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "LDAP SSL certificate file/database not configured!"); - rc = LDAP_OPERATIONS_ERROR; - } - -# else /* HAVE_LDAP_SSL */ - - /* - * Return error, because client libraries doesn't support SSL - */ - - cupsdLogMessage(CUPSD_LOG_ERROR, - "LDAP client libraries do not support SSL"); - rc = LDAP_OPERATIONS_ERROR; - -# endif /* HAVE_LDAP_SSL */ - } -# endif /* HAVE_OPENLDAP */ - - /* - * Check return code from LDAP initialize... - */ - - if (rc != LDAP_SUCCESS) - { - cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to initialize LDAP!"); - - if (rc == LDAP_SERVER_DOWN || rc == LDAP_CONNECT_ERROR) - cupsdLogMessage(CUPSD_LOG_ERROR, "Temporarily disabling LDAP browsing..."); - else - { - cupsdLogMessage(CUPSD_LOG_ERROR, "Disabling LDAP browsing!"); - - BrowseLocalProtocols &= ~BROWSE_LDAP; - BrowseRemoteProtocols &= ~BROWSE_LDAP; - } - - ldap_disconnect(TempBrowseLDAPHandle); - - return (NULL); - } - - /* - * Upgrade LDAP version... - */ - - if (ldap_set_option(TempBrowseLDAPHandle, LDAP_OPT_PROTOCOL_VERSION, - (const void *)&version) != LDAP_SUCCESS) - { - cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to set LDAP protocol version %d!", - version); - cupsdLogMessage(CUPSD_LOG_ERROR, "Disabling LDAP browsing!"); - - BrowseLocalProtocols &= ~BROWSE_LDAP; - BrowseRemoteProtocols &= ~BROWSE_LDAP; - ldap_disconnect(TempBrowseLDAPHandle); - - return (NULL); - } - - /* - * Register LDAP rebind procedure... - */ - -# ifdef HAVE_LDAP_REBIND_PROC -# if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000) - - rc = ldap_set_rebind_proc(TempBrowseLDAPHandle, &ldap_rebind_proc, - (void *)NULL); - if (rc != LDAP_SUCCESS) - cupsdLogMessage(CUPSD_LOG_ERROR, - "Setting LDAP rebind function failed with status %d: %s", - rc, ldap_err2string(rc)); - -# else - - ldap_set_rebind_proc(TempBrowseLDAPHandle, &ldap_rebind_proc, (void *)NULL); - -# endif /* defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000) */ -# endif /* HAVE_LDAP_REBIND_PROC */ - - /* - * Start LDAP bind... - */ - -# if LDAP_API_VERSION > 3000 - struct berval bval; - bval.bv_val = BrowseLDAPPassword; - bval.bv_len = (BrowseLDAPPassword == NULL) ? 0 : strlen(BrowseLDAPPassword); - - if (!BrowseLDAPServer || !_cups_strcasecmp(BrowseLDAPServer, "localhost")) - rc = ldap_sasl_bind_s(TempBrowseLDAPHandle, NULL, "EXTERNAL", &bv, NULL, - NULL, NULL); - else - rc = ldap_sasl_bind_s(TempBrowseLDAPHandle, BrowseLDAPBindDN, LDAP_SASL_SIMPLE, &bval, NULL, NULL, NULL); - -# else - rc = ldap_bind_s(TempBrowseLDAPHandle, BrowseLDAPBindDN, - BrowseLDAPPassword, LDAP_AUTH_SIMPLE); -# endif /* LDAP_API_VERSION > 3000 */ - - if (rc != LDAP_SUCCESS) - { - cupsdLogMessage(CUPSD_LOG_ERROR, "LDAP bind failed with error %d: %s", - rc, ldap_err2string(rc)); - -# if defined(HAVE_LDAP_SSL) && defined (HAVE_MOZILLA_LDAP) - if (ldap_ssl && (rc == LDAP_SERVER_DOWN || rc == LDAP_CONNECT_ERROR)) - { - ssl_err = PORT_GetError(); - if (ssl_err != 0) - cupsdLogMessage(CUPSD_LOG_ERROR, "LDAP SSL error %d: %s", ssl_err, - ldapssl_err2string(ssl_err)); - } -# endif /* defined(HAVE_LDAP_SSL) && defined (HAVE_MOZILLA_LDAP) */ - - ldap_disconnect(TempBrowseLDAPHandle); - - return (NULL); - } - - cupsdLogMessage(CUPSD_LOG_INFO, "LDAP connection established"); - - return (TempBrowseLDAPHandle); -} - - -/* - * 'ldap_reconnect()' - Reconnect to LDAP Server - */ - -static LDAP * /* O - New LDAP handle */ -ldap_reconnect(void) -{ - LDAP *TempBrowseLDAPHandle = NULL; /* Temp Handle to LDAP server */ - - - /* - * Get a new LDAP Handle and replace the global Handle - * if the new connection was successful. - */ - - cupsdLogMessage(CUPSD_LOG_INFO, "Try LDAP reconnect..."); - - TempBrowseLDAPHandle = ldap_connect(); - - if (TempBrowseLDAPHandle != NULL) - { - if (BrowseLDAPHandle != NULL) - ldap_disconnect(BrowseLDAPHandle); - - BrowseLDAPHandle = TempBrowseLDAPHandle; - } - - return (BrowseLDAPHandle); -} - - -/* - * 'ldap_disconnect()' - Disconnect from LDAP Server - */ - -static void -ldap_disconnect(LDAP *ld) /* I - LDAP handle */ -{ - int rc; /* Return code */ - - - /* - * Close LDAP handle... - */ - -# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 - rc = ldap_unbind_ext_s(ld, NULL, NULL); -# else - rc = ldap_unbind_s(ld); -# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */ - - if (rc != LDAP_SUCCESS) - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unbind from LDAP server failed with status %d: %s", - rc, ldap_err2string(rc)); +#endif /* HAVE_DNSSD || HAVE_AVAHI */ } -#endif /* HAVE_LDAP */ /* @@ -1426,134 +172,24 @@ ldap_disconnect(LDAP *ld) /* I - LDAP handle */ void cupsdStartBrowsing(void) { - int val; /* Socket option value */ - struct sockaddr_in addr; /* Broadcast address */ cupsd_printer_t *p; /* Current printer */ - BrowseNext = NULL; - - if (!Browsing || !(BrowseLocalProtocols | BrowseRemoteProtocols)) + if (!Browsing || !BrowseLocalProtocols) return; - if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_CUPS) +#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) + if (BrowseLocalProtocols & BROWSE_DNSSD) { - if (BrowseSocket < 0) - { - /* - * Create the broadcast socket... - */ - - if ((BrowseSocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to create broadcast socket - %s.", - strerror(errno)); - BrowseLocalProtocols &= ~BROWSE_CUPS; - BrowseRemoteProtocols &= ~BROWSE_CUPS; - - if (FatalErrors & CUPSD_FATAL_BROWSE) - cupsdEndProcess(getpid(), 0); - } - } - - if (BrowseSocket >= 0) - { - /* - * Bind the socket to browse port... - */ - - memset(&addr, 0, sizeof(addr)); - addr.sin_addr.s_addr = htonl(INADDR_ANY); - addr.sin_family = AF_INET; - addr.sin_port = htons(BrowsePort); - - if (bind(BrowseSocket, (struct sockaddr *)&addr, sizeof(addr))) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to bind broadcast socket - %s.", - strerror(errno)); - -#ifdef WIN32 - closesocket(BrowseSocket); -#else - close(BrowseSocket); -#endif /* WIN32 */ - - BrowseSocket = -1; - BrowseLocalProtocols &= ~BROWSE_CUPS; - BrowseRemoteProtocols &= ~BROWSE_CUPS; - - if (FatalErrors & CUPSD_FATAL_BROWSE) - cupsdEndProcess(getpid(), 0); - } - } - - if (BrowseSocket >= 0) - { - /* - * Set the "broadcast" flag... - */ - - val = 1; - if (setsockopt(BrowseSocket, SOL_SOCKET, SO_BROADCAST, &val, sizeof(val))) - { - cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to set broadcast mode - %s.", - strerror(errno)); - -#ifdef WIN32 - closesocket(BrowseSocket); -#else - close(BrowseSocket); -#endif /* WIN32 */ - - BrowseSocket = -1; - BrowseLocalProtocols &= ~BROWSE_CUPS; - BrowseRemoteProtocols &= ~BROWSE_CUPS; - - if (FatalErrors & CUPSD_FATAL_BROWSE) - cupsdEndProcess(getpid(), 0); - } - } - - if (BrowseSocket >= 0) - { - /* - * Close the socket on exec... - */ - - fcntl(BrowseSocket, F_SETFD, fcntl(BrowseSocket, F_GETFD) | FD_CLOEXEC); - - /* - * Finally, add the socket to the input selection set as needed... - */ - - if (BrowseRemoteProtocols & BROWSE_CUPS) - { - /* - * We only listen if we want remote printers... - */ - - cupsdAddSelect(BrowseSocket, (cupsd_selfunc_t)update_cups_browse, - NULL, NULL); - } - } - } - else - BrowseSocket = -1; - -#ifdef HAVE_DNSSD - if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_DNSSD) - { - DNSServiceErrorType error; /* Error from service creation */ cupsd_listener_t *lis; /* Current listening socket */ - +# ifdef HAVE_DNSSD + DNSServiceErrorType error; /* Error from service creation */ /* * First create a "master" connection for all registrations... */ - if ((error = DNSServiceCreateConnection(&DNSSDRef)) + if ((error = DNSServiceCreateConnection(&DNSSDMaster)) != kDNSServiceErr_NoError) { cupsdLogMessage(CUPSD_LOG_ERROR, @@ -1568,100 +204,71 @@ cupsdStartBrowsing(void) * Add the master connection to the select list... */ - int fd = DNSServiceRefSockFD(DNSSDRef); + int fd = DNSServiceRefSockFD(DNSSDMaster); fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC); cupsdAddSelect(fd, (cupsd_selfunc_t)dnssdUpdate, NULL, NULL); + } - /* - * Then get the port we use for registrations. If we are not listening - * on any non-local ports, there is no sense sharing local printers via - * Bonjour... - */ - - DNSSDPort = 0; - - for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners); - lis; - lis = (cupsd_listener_t *)cupsArrayNext(Listeners)) - { - if (httpAddrLocalhost(&(lis->address))) - continue; +# else /* HAVE_AVAHI */ + if ((DNSSDMaster = avahi_threaded_poll_new()) == NULL) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create DNS-SD thread."); - DNSSDPort = _httpAddrPort(&(lis->address)); - break; - } + if (FatalErrors & CUPSD_FATAL_BROWSE) + cupsdEndProcess(getpid(), 0); + } + else + { + int error; /* Error code, if any */ - /* - * Create an array to track the printers we share... - */ + DNSSDClient = avahi_client_new(avahi_threaded_poll_get(DNSSDMaster), 0, + NULL, NULL, &error); - if (BrowseRemoteProtocols & BROWSE_DNSSD) - DNSSDPrinters = cupsArrayNew((cups_array_func_t)dnssdComparePrinters, - NULL); + if (DNSSDClient == NULL) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to communicate with avahi-daemon: %s", + dnssdErrorString(error)); - /* - * Set the computer name and register the web interface... - */ + if (FatalErrors & CUPSD_FATAL_BROWSE) + cupsdEndProcess(getpid(), 0); - cupsdUpdateDNSSDName(); + avahi_threaded_poll_free(DNSSDMaster); + DNSSDMaster = NULL; + } + else + avahi_threaded_poll_start(DNSSDMaster); } - } -#endif /* HAVE_DNSSD */ +# endif /* HAVE_DNSSD */ -#ifdef HAVE_LIBSLP - if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_SLP) - { /* - * Open SLP handle... + * Then get the port we use for registrations. If we are not listening + * on any non-local ports, there is no sense sharing local printers via + * Bonjour... */ - if (SLPOpen("en", SLP_FALSE, &BrowseSLPHandle) != SLP_OK) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to open an SLP handle; disabling SLP browsing!"); - BrowseLocalProtocols &= ~BROWSE_SLP; - BrowseRemoteProtocols &= ~BROWSE_SLP; - BrowseSLPHandle = NULL; + DNSSDPort = 0; - if (FatalErrors & CUPSD_FATAL_BROWSE) - cupsdEndProcess(getpid(), 0); - } - - BrowseSLPRefresh = 0; - } - else - BrowseSLPHandle = NULL; -#endif /* HAVE_LIBSLP */ - -#ifdef HAVE_LDAP - if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_LDAP) - { - if (!BrowseLDAPDN) + for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners); + lis; + lis = (cupsd_listener_t *)cupsArrayNext(Listeners)) { - cupsdLogMessage(CUPSD_LOG_ERROR, - "Need to set BrowseLDAPDN to use LDAP browsing!"); - BrowseLocalProtocols &= ~BROWSE_LDAP; - BrowseRemoteProtocols &= ~BROWSE_LDAP; + if (httpAddrLocalhost(&(lis->address))) + continue; - if (FatalErrors & CUPSD_FATAL_BROWSE) - cupsdEndProcess(getpid(), 0); + DNSSDPort = _httpAddrPort(&(lis->address)); + break; } - else - { - /* - * Open LDAP handle... - */ - if ((BrowseLDAPHandle = ldap_connect()) == NULL && - (FatalErrors & CUPSD_FATAL_BROWSE)) - cupsdEndProcess(getpid(), 0); - } + /* + * Set the computer name and register the web interface... + */ - BrowseLDAPRefresh = 0; + cupsdUpdateDNSSDName(); } -#endif /* HAVE_LDAP */ +#endif /* HAVE_DNSSD || HAVE_AVAHI */ /* * Enable LPD and SMB printer sharing as needed through external programs... @@ -1680,116 +287,12 @@ cupsdStartBrowsing(void) for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); p; p = (cupsd_printer_t *)cupsArrayNext(Printers)) - if (!(p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT | - CUPS_PRINTER_SCANNER))) + if (!(p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_SCANNER))) cupsdRegisterPrinter(p); } /* - * 'cupsdStartPolling()' - Start polling servers as needed. - */ - -void -cupsdStartPolling(void) -{ - int i; /* Looping var */ - cupsd_dirsvc_poll_t *pollp; /* Current polling server */ - char polld[1024]; /* Poll daemon path */ - char sport[255]; /* Server port */ - char bport[255]; /* Browser port */ - char interval[255]; /* Poll interval */ - int statusfds[2]; /* Status pipe */ - char *argv[6]; /* Arguments */ - char *envp[100]; /* Environment */ - - - /* - * Don't do anything if we aren't polling... - */ - - if (NumPolled == 0 || BrowseSocket < 0) - { - PollPipe = -1; - PollStatusBuffer = NULL; - return; - } - - /* - * Setup string arguments for polld, port and interval options. - */ - - snprintf(polld, sizeof(polld), "%s/daemon/cups-polld", ServerBin); - - sprintf(bport, "%d", BrowsePort); - - if (BrowseInterval) - sprintf(interval, "%d", BrowseInterval); - else - strcpy(interval, "30"); - - argv[0] = "cups-polld"; - argv[2] = sport; - argv[3] = interval; - argv[4] = bport; - argv[5] = NULL; - - cupsdLoadEnv(envp, (int)(sizeof(envp) / sizeof(envp[0]))); - - /* - * Create a pipe that receives the status messages from each - * polling daemon... - */ - - if (cupsdOpenPipe(statusfds)) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to create polling status pipes - %s.", - strerror(errno)); - PollPipe = -1; - PollStatusBuffer = NULL; - return; - } - - PollPipe = statusfds[0]; - PollStatusBuffer = cupsdStatBufNew(PollPipe, "[Poll]"); - - /* - * Run each polling daemon, redirecting stderr to the polling pipe... - */ - - for (i = 0, pollp = Polled; i < NumPolled; i ++, pollp ++) - { - sprintf(sport, "%d", pollp->port); - - argv[1] = pollp->hostname; - - if (cupsdStartProcess(polld, argv, envp, -1, -1, statusfds[1], -1, -1, - 0, DefaultProfile, NULL, &(pollp->pid)) < 0) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "cupsdStartPolling: Unable to fork polling daemon - %s", - strerror(errno)); - pollp->pid = 0; - break; - } - else - cupsdLogMessage(CUPSD_LOG_DEBUG, - "cupsdStartPolling: Started polling daemon for %s:%d, pid = %d", - pollp->hostname, pollp->port, pollp->pid); - } - - close(statusfds[1]); - - /* - * Finally, add the pipe to the input selection set... - */ - - cupsdAddSelect(PollPipe, (cupsd_selfunc_t)update_polling, NULL, NULL); -} - - -/* * 'cupsdStopBrowsing()' - Stop sending and receiving broadcast information. */ @@ -1799,7 +302,7 @@ cupsdStopBrowsing(void) cupsd_printer_t *p; /* Current printer */ - if (!Browsing || !(BrowseLocalProtocols | BrowseRemoteProtocols)) + if (!Browsing || !BrowseLocalProtocols) return; /* @@ -1809,58 +312,17 @@ cupsdStopBrowsing(void) for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); p; p = (cupsd_printer_t *)cupsArrayNext(Printers)) - if (!(p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT | - CUPS_PRINTER_SCANNER))) + if (!(p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_SCANNER))) cupsdDeregisterPrinter(p, 1); /* * Shut down browsing sockets... */ - if (((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_CUPS) && - BrowseSocket >= 0) - { - /* - * Close the socket and remove it from the input selection set. - */ - -#ifdef WIN32 - closesocket(BrowseSocket); -#else - close(BrowseSocket); -#endif /* WIN32 */ - - cupsdRemoveSelect(BrowseSocket); - BrowseSocket = -1; - } - -#ifdef HAVE_DNSSD - if ((BrowseLocalProtocols & BROWSE_DNSSD) && DNSSDRef) +#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) + if ((BrowseLocalProtocols & BROWSE_DNSSD) && DNSSDMaster) dnssdStop(); -#endif /* HAVE_DNSSD */ - -#ifdef HAVE_LIBSLP - if (((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_SLP) && - BrowseSLPHandle) - { - /* - * Close SLP handle... - */ - - SLPClose(BrowseSLPHandle); - BrowseSLPHandle = NULL; - } -#endif /* HAVE_LIBSLP */ - -#ifdef HAVE_LDAP - if (((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_LDAP) && - BrowseLDAPHandle) - { - ldap_dereg_ou(ServerName, BrowseLDAPDN); - ldap_disconnect(BrowseLDAPHandle); - BrowseLDAPHandle = NULL; - } -#endif /* HAVE_OPENLDAP */ +#endif /* HAVE_DNSSD || HAVE_AVAHI */ /* * Disable LPD and SMB printer sharing as needed through external programs... @@ -1874,35 +336,7 @@ cupsdStopBrowsing(void) } -/* - * 'cupsdStopPolling()' - Stop polling servers as needed. - */ - -void -cupsdStopPolling(void) -{ - int i; /* Looping var */ - cupsd_dirsvc_poll_t *pollp; /* Current polling server */ - - - if (PollPipe >= 0) - { - cupsdStatBufDelete(PollStatusBuffer); - close(PollPipe); - - cupsdRemoveSelect(PollPipe); - - PollPipe = -1; - PollStatusBuffer = NULL; - } - - for (i = 0, pollp = Polled; i < NumPolled; i ++, pollp ++) - if (pollp->pid) - cupsdEndProcess(pollp->pid, 0); -} - - -#ifdef HAVE_DNSSD +#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) /* * 'cupsdUpdateDNSSDName()' - Update the computer name we use for browsing... */ @@ -1910,15 +344,14 @@ cupsdStopPolling(void) void cupsdUpdateDNSSDName(void) { - DNSServiceErrorType error; /* Error from service creation */ char webif[1024]; /* Web interface share name */ -# ifdef HAVE_SYSTEMCONFIGURATION +# ifdef __APPLE__ SCDynamicStoreRef sc; /* Context for dynamic store */ CFDictionaryRef btmm; /* Back-to-My-Mac domains */ CFStringEncoding nameEncoding; /* Encoding of computer name */ CFStringRef nameRef; /* Host name CFString */ char nameBuffer[1024]; /* C-string buffer */ -# endif /* HAVE_SYSTEMCONFIGURATION */ +# endif /* __APPLE__ */ /* @@ -1926,7 +359,6 @@ cupsdUpdateDNSSDName(void) * enabled... */ - if (!DNSSDPort) return; @@ -1934,7 +366,7 @@ cupsdUpdateDNSSDName(void) * Get the computer name as a c-string... */ -# ifdef HAVE_SYSTEMCONFIGURATION +# ifdef __APPLE__ sc = SCDynamicStoreCreate(kCFAllocatorDefault, CFSTR("cupsd"), NULL, NULL); if (sc) @@ -2025,282 +457,52 @@ cupsdUpdateDNSSDName(void) CFRelease(sc); } else -# endif /* HAVE_SYSTEMCONFIGURATION */ +# endif /* __APPLE__ */ +# ifdef HAVE_AVAHI + if (DNSSDClient) { - cupsdSetString(&DNSSDComputerName, ServerName); - cupsdSetString(&DNSSDHostName, ServerName); - } + const char *host_name = avahi_client_get_host_name(DNSSDClient); + const char *host_fqdn = avahi_client_get_host_name_fqdn(DNSSDClient); - /* - * Then (re)register the web interface if enabled... - */ + cupsdSetString(&DNSSDComputerName, host_name ? host_name : ServerName); - if (BrowseWebIF) - { - if (DNSSDComputerName) - snprintf(webif, sizeof(webif), "CUPS @ %s", DNSSDComputerName); + if (host_fqdn) + cupsdSetString(&DNSSDHostName, host_fqdn); + else if (strchr(ServerName, '.')) + cupsdSetString(&DNSSDHostName, ServerName); else - strlcpy(webif, "CUPS Web Interface", sizeof(webif)); - - if (WebIFRef) - DNSServiceRefDeallocate(WebIFRef); - - WebIFRef = DNSSDRef; - if ((error = DNSServiceRegister(&WebIFRef, - kDNSServiceFlagsShareConnection, - 0, webif, "_http._tcp", NULL, - NULL, htons(DNSSDPort), 7, - "\006path=/", dnssdRegisterCallback, - NULL)) != kDNSServiceErr_NoError) - cupsdLogMessage(CUPSD_LOG_ERROR, - "DNS-SD web interface registration failed: %d", error); - } -} -#endif /* HAVE_DNSSD */ - - -#ifdef HAVE_LDAP -/* - * 'cupsdUpdateLDAPBrowse()' - Scan for new printers via LDAP... - */ - -void -cupsdUpdateLDAPBrowse(void) -{ - char uri[HTTP_MAX_URI], /* Printer URI */ - host[HTTP_MAX_URI], /* Hostname */ - resource[HTTP_MAX_URI], /* Resource path */ - location[1024], /* Printer location */ - info[1024], /* Printer information */ - make_model[1024], /* Printer make and model */ - type_num[30]; /* Printer type number */ - int type; /* Printer type */ - int rc; /* LDAP status */ - int limit; /* Size limit */ - LDAPMessage *res, /* LDAP search results */ - *e; /* Current entry from search */ - - cupsdLogMessage(CUPSD_LOG_DEBUG2, "UpdateLDAPBrowse: %s", ServerName); - - BrowseLDAPRefresh = time(NULL) + BrowseInterval; - - /* - * Reconnect if LDAP Handle is invalid... - */ - - if (! BrowseLDAPHandle) - { - ldap_reconnect(); - return; + cupsdSetStringf(&DNSSDHostName, "%s.local", ServerName); } - - /* - * Search for cups printers in LDAP directory... - */ - - rc = ldap_search_rec(BrowseLDAPHandle, BrowseLDAPDN, LDAP_SCOPE_SUBTREE, - "(objectclass=cupsPrinter)", (char **)ldap_attrs, 0, &res); - - /* - * If ldap search was successfull then exit function - * and temporary disable LDAP updates... - */ - - if (rc != LDAP_SUCCESS) - { - if (BrowseLDAPUpdate && ((rc == LDAP_SERVER_DOWN) || (rc == LDAP_CONNECT_ERROR))) - { - BrowseLDAPUpdate = FALSE; - cupsdLogMessage(CUPSD_LOG_INFO, - "LDAP update temporary disabled"); - } - return; - } - - /* - * If LDAP updates were disabled, we will reenable them... - */ - - if (! BrowseLDAPUpdate) - { - BrowseLDAPUpdate = TRUE; - cupsdLogMessage(CUPSD_LOG_INFO, - "LDAP update enabled"); - } - - /* - * Count LDAP entries and return if no entry exist... - */ - - limit = ldap_count_entries(BrowseLDAPHandle, res); - cupsdLogMessage(CUPSD_LOG_DEBUG2, "LDAP search returned %d entries", limit); - if (limit < 1) - { - ldap_freeres(res); - return; - } - - /* - * Loop through the available printers... - */ - - for (e = ldap_first_entry(BrowseLDAPHandle, res); - e; - e = ldap_next_entry(BrowseLDAPHandle, e)) + else +# endif /* HAVE_AVAHI */ { - /* - * Get the required values from this entry... - */ - - if (ldap_getval_firststring(BrowseLDAPHandle, e, - "printerDescription", info, sizeof(info)) == -1) - continue; - - if (ldap_getval_firststring(BrowseLDAPHandle, e, - "printerLocation", location, sizeof(location)) == -1) - continue; - - if (ldap_getval_firststring(BrowseLDAPHandle, e, - "printerMakeAndModel", make_model, sizeof(make_model)) == -1) - continue; - - if (ldap_getval_firststring(BrowseLDAPHandle, e, - "printerType", type_num, sizeof(type_num)) == -1) - continue; - - type = atoi(type_num); - - if (ldap_getval_firststring(BrowseLDAPHandle, e, - "printerURI", uri, sizeof(uri)) == -1) - continue; - - /* - * Process the entry as browse data... - */ - - if (!is_local_queue(uri, host, sizeof(host), resource, sizeof(resource))) - process_browse_data(uri, host, resource, type, IPP_PRINTER_IDLE, - location, info, make_model, 0, NULL); + cupsdSetString(&DNSSDComputerName, ServerName); + if (strchr(ServerName, '.')) + cupsdSetString(&DNSSDHostName, ServerName); + else + cupsdSetStringf(&DNSSDHostName, "%s.local", ServerName); } - ldap_freeres(res); -} -#endif /* HAVE_LDAP */ - - -#ifdef HAVE_LIBSLP -/* - * 'cupsdUpdateSLPBrowse()' - Get browsing information via SLP. - */ - -void -cupsdUpdateSLPBrowse(void) -{ - slpsrvurl_t *s, /* Temporary list of service URLs */ - *next; /* Next service in list */ - cupsd_printer_t p; /* Printer information */ - const char *uri; /* Pointer to printer URI */ - char host[HTTP_MAX_URI], /* Host portion of URI */ - resource[HTTP_MAX_URI]; /* Resource portion of URI */ - - - /* - * Reset the refresh time... - */ - - BrowseSLPRefresh = time(NULL) + BrowseInterval; - /* - * Poll for remote printers using SLP... - */ - - s = NULL; - - SLPFindSrvs(BrowseSLPHandle, SLP_CUPS_SRVTYPE, "", "", - slp_url_callback, &s); - - /* - * Loop through the list of available printers... + * Then (re)register the web interface if enabled... */ - for (; s; s = next) - { - /* - * Save the "next" pointer... - */ - - next = s->next; - - /* - * Load a cupsd_printer_t structure with the SLP service attributes... - */ - - SLPFindAttrs(BrowseSLPHandle, s->url, "", "", slp_attr_callback, &p); - - /* - * Process this printer entry... - */ - - uri = s->url + SLP_CUPS_SRVLEN + 1; - - if (!strncmp(uri, "http://", 7) || !strncmp(uri, "ipp://", 6)) - { - /* - * Pull the URI apart to see if this is a local or remote printer... - */ - - if (!is_local_queue(uri, host, sizeof(host), resource, sizeof(resource))) - process_browse_data(uri, host, resource, p.type, IPP_PRINTER_IDLE, - p.location, p.info, p.make_model, 0, NULL); - } - - /* - * Free this listing... - */ - - cupsdClearString(&p.info); - cupsdClearString(&p.location); - cupsdClearString(&p.make_model); - - free(s); - } -} -#endif /* HAVE_LIBSLP */ - - -/* - * 'dequote()' - Remote quotes from a string. - */ - -static char * /* O - Dequoted string */ -dequote(char *d, /* I - Destination string */ - const char *s, /* I - Source string */ - int dlen) /* I - Destination length */ -{ - char *dptr; /* Pointer into destination */ - - - if (s) + if (BrowseWebIF) { - for (dptr = d, dlen --; *s && dlen > 0; s ++) - if (*s != '\"') - { - *dptr++ = *s; - dlen --; - } + if (DNSSDComputerName) + snprintf(webif, sizeof(webif), "CUPS @ %s", DNSSDComputerName); + else + strlcpy(webif, "CUPS", sizeof(webif)); - *dptr = '\0'; + dnssdDeregisterInstance(&WebIFSrv); + dnssdRegisterInstance(&WebIFSrv, NULL, webif, "_http._tcp", "_printer", + DNSSDPort, NULL, 1); } - else - *d = '\0'; - - return (d); } -#ifdef HAVE_DNSSD -# ifdef HAVE_COREFOUNDATION +# ifdef __APPLE__ /* * 'dnssdAddAlias()' - Add a DNS-SD alias name. */ @@ -2338,20 +540,20 @@ dnssdAddAlias(const void *key, /* I - Key */ cupsdLogMessage(CUPSD_LOG_ERROR, "Bad Back to My Mac domain in dynamic store!"); } -# endif /* HAVE_COREFOUNDATION */ +# endif /* __APPLE__ */ /* * 'dnssdBuildTxtRecord()' - Build a TXT record from printer info. */ -static char * /* O - TXT record */ +static cupsd_txt_t /* O - TXT record */ dnssdBuildTxtRecord( - int *txt_len, /* O - TXT record length */ cupsd_printer_t *p, /* I - Printer information */ int for_lpd) /* I - 1 = LPD, 0 = IPP */ { - int i; /* Looping var */ + int i, /* Looping var */ + count; /* Count of key/value pairs */ char admin_hostname[256], /* .local hostname for admin page */ adminurl_str[256], /* URL for the admin page */ type_str[32], /* Type to string buffer */ @@ -2359,249 +561,370 @@ dnssdBuildTxtRecord( rp_str[1024], /* Queue name string buffer */ air_str[1024], /* auth-info-required string buffer */ *keyvalue[32][2]; /* Table of key/value pairs */ + cupsd_txt_t txt; /* TXT record */ /* * Load up the key value pairs... */ - i = 0; - - keyvalue[i ][0] = "txtvers"; - keyvalue[i++][1] = "1"; + count = 0; - keyvalue[i ][0] = "qtotal"; - keyvalue[i++][1] = "1"; - - keyvalue[i ][0] = "rp"; - keyvalue[i++][1] = rp_str; - if (for_lpd) - strlcpy(rp_str, p->name, sizeof(rp_str)); - else - snprintf(rp_str, sizeof(rp_str), "%s/%s", - (p->type & CUPS_PRINTER_CLASS) ? "classes" : "printers", p->name); + if (!for_lpd || (BrowseLocalProtocols & BROWSE_LPD)) + { + keyvalue[count ][0] = "txtvers"; + keyvalue[count++][1] = "1"; - keyvalue[i ][0] = "ty"; - keyvalue[i++][1] = p->make_model ? p->make_model : "Unknown"; + keyvalue[count ][0] = "qtotal"; + keyvalue[count++][1] = "1"; - snprintf(admin_hostname, sizeof(admin_hostname), "%s.local.", DNSSDHostName); - httpAssembleURIf(HTTP_URI_CODING_ALL, adminurl_str, sizeof(adminurl_str), - "http", NULL, admin_hostname, DNSSDPort, "/%s/%s", - (p->type & CUPS_PRINTER_CLASS) ? "classes" : "printers", - p->name); - keyvalue[i ][0] = "adminurl"; - keyvalue[i++][1] = adminurl_str; + keyvalue[count ][0] = "rp"; + keyvalue[count++][1] = rp_str; + if (for_lpd) + strlcpy(rp_str, p->name, sizeof(rp_str)); + else + snprintf(rp_str, sizeof(rp_str), "%s/%s", + (p->type & CUPS_PRINTER_CLASS) ? "classes" : "printers", + p->name); - keyvalue[i ][0] = "note"; - keyvalue[i++][1] = p->location ? p->location : ""; + keyvalue[count ][0] = "ty"; + keyvalue[count++][1] = p->make_model ? p->make_model : "Unknown"; - keyvalue[i ][0] = "priority"; - keyvalue[i++][1] = for_lpd ? "100" : "0"; + if (strstr(DNSSDHostName, ".local")) + strlcpy(admin_hostname, DNSSDHostName, sizeof(admin_hostname)); + else + snprintf(admin_hostname, sizeof(admin_hostname), "%s.local.", + DNSSDHostName); + httpAssembleURIf(HTTP_URI_CODING_ALL, adminurl_str, sizeof(adminurl_str), +# ifdef HAVE_SSL + "https", +# else + "http", +# endif /* HAVE_SSL */ + NULL, admin_hostname, DNSSDPort, "/%s/%s", + (p->type & CUPS_PRINTER_CLASS) ? "classes" : "printers", + p->name); + keyvalue[count ][0] = "adminurl"; + keyvalue[count++][1] = adminurl_str; - keyvalue[i ][0] = "product"; - keyvalue[i++][1] = p->pc && p->pc->product ? p->pc->product : "Unknown"; + if (p->location) + { + keyvalue[count ][0] = "note"; + keyvalue[count++][1] = p->location; + } - keyvalue[i ][0] = "pdl"; - keyvalue[i++][1] = p->pdl ? p->pdl : "application/postscript"; + keyvalue[count ][0] = "priority"; + keyvalue[count++][1] = for_lpd ? "100" : "0"; - if (get_auth_info_required(p, air_str, sizeof(air_str))) - { - keyvalue[i ][0] = "air"; - keyvalue[i++][1] = air_str; - } + keyvalue[count ][0] = "product"; + keyvalue[count++][1] = p->pc && p->pc->product ? p->pc->product : "Unknown"; - keyvalue[i ][0] = "UUID"; - keyvalue[i++][1] = p->uuid + 9; + keyvalue[count ][0] = "pdl"; + keyvalue[count++][1] = p->pdl ? p->pdl : "application/postscript"; -#ifdef HAVE_SSL - keyvalue[i ][0] = "TLS"; - keyvalue[i++][1] = "1.2"; -#endif /* HAVE_SSL */ + if (get_auth_info_required(p, air_str, sizeof(air_str))) + { + keyvalue[count ][0] = "air"; + keyvalue[count++][1] = air_str; + } - keyvalue[i ][0] = "Transparent"; - keyvalue[i++][1] = "F"; + keyvalue[count ][0] = "UUID"; + keyvalue[count++][1] = p->uuid + 9; - keyvalue[i ][0] = "Binary"; - keyvalue[i++][1] = "F"; + #ifdef HAVE_SSL + keyvalue[count ][0] = "TLS"; + keyvalue[count++][1] = "1.2"; + #endif /* HAVE_SSL */ - keyvalue[i ][0] = "Fax"; - keyvalue[i++][1] = (p->type & CUPS_PRINTER_FAX) ? "T" : "F"; + if (p->type & CUPS_PRINTER_FAX) + { + keyvalue[count ][0] = "Fax"; + keyvalue[count++][1] = (p->type & CUPS_PRINTER_FAX) ? "T" : "F"; + } - keyvalue[i ][0] = "Color"; - keyvalue[i++][1] = (p->type & CUPS_PRINTER_COLOR) ? "T" : "F"; + if (p->type & CUPS_PRINTER_COLOR) + { + keyvalue[count ][0] = "Color"; + keyvalue[count++][1] = (p->type & CUPS_PRINTER_COLOR) ? "T" : "F"; + } - keyvalue[i ][0] = "Duplex"; - keyvalue[i++][1] = (p->type & CUPS_PRINTER_DUPLEX) ? "T" : "F"; + if (p->type & CUPS_PRINTER_DUPLEX) + { + keyvalue[count ][0] = "Duplex"; + keyvalue[count++][1] = (p->type & CUPS_PRINTER_DUPLEX) ? "T" : "F"; + } - keyvalue[i ][0] = "Staple"; - keyvalue[i++][1] = (p->type & CUPS_PRINTER_STAPLE) ? "T" : "F"; + if (p->type & CUPS_PRINTER_STAPLE) + { + keyvalue[count ][0] = "Staple"; + keyvalue[count++][1] = (p->type & CUPS_PRINTER_STAPLE) ? "T" : "F"; + } - keyvalue[i ][0] = "Copies"; - keyvalue[i++][1] = (p->type & CUPS_PRINTER_COPIES) ? "T" : "F"; + if (p->type & CUPS_PRINTER_COPIES) + { + keyvalue[count ][0] = "Copies"; + keyvalue[count++][1] = (p->type & CUPS_PRINTER_COPIES) ? "T" : "F"; + } - keyvalue[i ][0] = "Collate"; - keyvalue[i++][1] = (p->type & CUPS_PRINTER_COLLATE) ? "T" : "F"; + if (p->type & CUPS_PRINTER_COLLATE) + { + keyvalue[count ][0] = "Collate"; + keyvalue[count++][1] = (p->type & CUPS_PRINTER_COLLATE) ? "T" : "F"; + } - keyvalue[i ][0] = "Punch"; - keyvalue[i++][1] = (p->type & CUPS_PRINTER_PUNCH) ? "T" : "F"; + if (p->type & CUPS_PRINTER_PUNCH) + { + keyvalue[count ][0] = "Punch"; + keyvalue[count++][1] = (p->type & CUPS_PRINTER_PUNCH) ? "T" : "F"; + } - keyvalue[i ][0] = "Bind"; - keyvalue[i++][1] = (p->type & CUPS_PRINTER_BIND) ? "T" : "F"; + if (p->type & CUPS_PRINTER_BIND) + { + keyvalue[count ][0] = "Bind"; + keyvalue[count++][1] = (p->type & CUPS_PRINTER_BIND) ? "T" : "F"; + } - keyvalue[i ][0] = "Sort"; - keyvalue[i++][1] = (p->type & CUPS_PRINTER_SORT) ? "T" : "F"; + if (p->type & CUPS_PRINTER_SORT) + { + keyvalue[count ][0] = "Sort"; + keyvalue[count++][1] = (p->type & CUPS_PRINTER_SORT) ? "T" : "F"; + } - keyvalue[i ][0] = "Scan"; - keyvalue[i++][1] = (p->type & CUPS_PRINTER_MFP) ? "T" : "F"; + if (p->type & CUPS_PRINTER_MFP) + { + keyvalue[count ][0] = "Scan"; + keyvalue[count++][1] = (p->type & CUPS_PRINTER_MFP) ? "T" : "F"; + } - snprintf(type_str, sizeof(type_str), "0x%X", p->type | CUPS_PRINTER_REMOTE); - snprintf(state_str, sizeof(state_str), "%d", p->state); + snprintf(type_str, sizeof(type_str), "0x%X", p->type | CUPS_PRINTER_REMOTE); + snprintf(state_str, sizeof(state_str), "%d", p->state); - keyvalue[i ][0] = "printer-state"; - keyvalue[i++][1] = state_str; + keyvalue[count ][0] = "printer-state"; + keyvalue[count++][1] = state_str; - keyvalue[i ][0] = "printer-type"; - keyvalue[i++][1] = type_str; + keyvalue[count ][0] = "printer-type"; + keyvalue[count++][1] = type_str; + } /* * Then pack them into a proper txt record... */ - return (dnssdPackTxtRecord(txt_len, keyvalue, i)); -} +# ifdef HAVE_DNSSD + TXTRecordCreate(&txt, 0, NULL); + for (i = 0; i < count; i ++) + { + size_t len = strlen(keyvalue[i][1]); -/* - * 'dnssdComparePrinters()' - Compare the registered names of two printers. - */ + if (len < 256) + TXTRecordSetValue(&txt, keyvalue[i][0], (uint8_t)len, keyvalue[i][1]); + } -static int /* O - Result of comparison */ -dnssdComparePrinters(cupsd_printer_t *a,/* I - First printer */ - cupsd_printer_t *b)/* I - Second printer */ -{ - return (_cups_strcasecmp(a->reg_name, b->reg_name)); +# else + for (i = 0, txt = NULL; i < count; i ++) + txt = avahi_string_list_add_printf(txt, "%s=%s", keyvalue[i][0], + keyvalue[i][1]); +# endif /* HAVE_DNSSD */ + + return (txt); } /* - * 'dnssdDeregisterPrinter()' - Stop sending broadcast information for a - * printer. + * 'dnssdDeregisterInstance()' - Deregister a DNS-SD service instance. */ static void -dnssdDeregisterPrinter( - cupsd_printer_t *p) /* I - Printer */ +dnssdDeregisterInstance( + cupsd_srv_t *srv) /* I - Service */ { - cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdDeregisterPrinter(%s)", p->name); + if (!srv || !*srv) + return; - /* - * Closing the socket deregisters the service - */ +# ifdef HAVE_DNSSD + DNSServiceRefDeallocate(*srv); - if (p->ipp_ref) - { - DNSServiceRefDeallocate(p->ipp_ref); - p->ipp_ref = NULL; - } +# else /* HAVE_AVAHI */ + avahi_threaded_poll_lock(DNSSDMaster); + avahi_entry_group_free(*srv); + avahi_threaded_poll_unlock(DNSSDMaster); +# endif /* HAVE_DNSSD */ - if (p->ipp_txt) - { - /* - * p->ipp_txt is malloc'd, not _cupsStrAlloc'd... - */ + *srv = NULL; +} - free(p->ipp_txt); - p->ipp_txt = NULL; - } - if (p->printer_ref) - { - DNSServiceRefDeallocate(p->printer_ref); - p->printer_ref = NULL; - } +/* + * 'dnssdDeregisterPrinter()' - Deregister all services for a printer. + */ - if (p->printer_txt) +static void +dnssdDeregisterPrinter( + cupsd_printer_t *p, /* I - Printer */ + int clear_name) /* I - Clear the name? */ + +{ + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "dnssdDeregisterPrinter(p=%p(%s), clear_name=%d)", p, p->name, + clear_name); + + if (p->ipp_srv) { - /* - * p->printer_txt is malloc'd, not _cupsStrAlloc'd... - */ + dnssdDeregisterInstance(&p->ipp_srv); - free(p->printer_txt); - p->printer_txt = NULL; +# ifdef HAVE_DNSSD +# ifdef HAVE_SSL + dnssdDeregisterInstance(&p->ipps_srv); +# endif /* HAVE_SSL */ + dnssdDeregisterInstance(&p->printer_srv); +# endif /* HAVE_DNSSD */ } /* - * Remove the printer from the array of DNS-SD printers, then clear the + * Remove the printer from the array of DNS-SD printers but keep the * registered name... */ cupsArrayRemove(DNSSDPrinters, p); - cupsdClearString(&p->reg_name); + + /* + * Optionally clear the service name... + */ + + if (clear_name) + cupsdClearString(&p->reg_name); } /* - * 'dnssdPackTxtRecord()' - Pack an array of key/value pairs into the - * TXT record format. + * 'dnssdErrorString()' - Return an error string for an error code. */ -static char * /* O - TXT record */ -dnssdPackTxtRecord(int *txt_len, /* O - TXT record length */ - char *keyvalue[][2], /* I - Table of key value pairs */ - int count) /* I - Items in table */ +static const char * /* O - Error message */ +dnssdErrorString(int error) /* I - Error number */ { - int i; /* Looping var */ - int length; /* Length of TXT record */ - int length2; /* Length of value */ - char *txtRecord; /* TXT record buffer */ - char *cursor; /* Looping pointer */ +# ifdef HAVE_DNSSD + switch (error) + { + case kDNSServiceErr_NoError : + return ("OK."); + default : + case kDNSServiceErr_Unknown : + return ("Unknown error."); - /* - * Calculate the buffer size - */ + case kDNSServiceErr_NoSuchName : + return ("Service not found."); - if (count <= 0) - return (NULL); + case kDNSServiceErr_NoMemory : + return ("Out of memory."); - for (length = i = 0; i < count; i++) - length += 1 + strlen(keyvalue[i][0]) + - (keyvalue[i][1] ? 1 + strlen(keyvalue[i][1]) : 0); + case kDNSServiceErr_BadParam : + return ("Bad parameter."); - /* - * Allocate and fill it - */ + case kDNSServiceErr_BadReference : + return ("Bad service reference."); - txtRecord = malloc(length); - if (txtRecord) - { - *txt_len = length; + case kDNSServiceErr_BadState : + return ("Bad state."); - for (cursor = txtRecord, i = 0; i < count; i++) - { - /* - * Drop in the p-string style length byte followed by the data - */ + case kDNSServiceErr_BadFlags : + return ("Bad flags."); - length = strlen(keyvalue[i][0]); - length2 = keyvalue[i][1] ? 1 + strlen(keyvalue[i][1]) : 0; + case kDNSServiceErr_Unsupported : + return ("Unsupported."); - *cursor++ = (unsigned char)(length + length2); + case kDNSServiceErr_NotInitialized : + return ("Not initialized."); - memcpy(cursor, keyvalue[i][0], length); - cursor += length; + case kDNSServiceErr_AlreadyRegistered : + return ("Already registered."); - if (length2) - { - length2 --; - *cursor++ = '='; - memcpy(cursor, keyvalue[i][1], length2); - cursor += length2; - } - } + case kDNSServiceErr_NameConflict : + return ("Name conflict."); + + case kDNSServiceErr_Invalid : + return ("Invalid name."); + + case kDNSServiceErr_Firewall : + return ("Firewall prevents registration."); + + case kDNSServiceErr_Incompatible : + return ("Client library incompatible."); + + case kDNSServiceErr_BadInterfaceIndex : + return ("Bad interface index."); + + case kDNSServiceErr_Refused : + return ("Server prevents registration."); + + case kDNSServiceErr_NoSuchRecord : + return ("Record not found."); + + case kDNSServiceErr_NoAuth : + return ("Authentication required."); + + case kDNSServiceErr_NoSuchKey : + return ("Encryption key not found."); + + case kDNSServiceErr_NATTraversal : + return ("Unable to traverse NAT boundary."); + + case kDNSServiceErr_DoubleNAT : + return ("Unable to traverse double-NAT boundary."); + + case kDNSServiceErr_BadTime : + return ("Bad system time."); + + case kDNSServiceErr_BadSig : + return ("Bad signature."); + + case kDNSServiceErr_BadKey : + return ("Bad encryption key."); + + case kDNSServiceErr_Transient : + return ("Transient error occurred - please try again."); + + case kDNSServiceErr_ServiceNotRunning : + return ("Server not running."); + + case kDNSServiceErr_NATPortMappingUnsupported : + return ("NAT doesn't support NAT-PMP or UPnP."); + + case kDNSServiceErr_NATPortMappingDisabled : + return ("NAT supports NAT-PNP or UPnP but it is disabled."); + + case kDNSServiceErr_NoRouter : + return ("No Internet/default router configured."); + + case kDNSServiceErr_PollingMode : + return ("Service polling mode error."); + + case kDNSServiceErr_Timeout : + return ("Service timeout."); } - return (txtRecord); +# else /* HAVE_AVAHI */ + return (avahi_strerror(error)); +# endif /* HAVE_DNSSD */ +} + + +/* + * 'dnssdRegisterCallback()' - Free a TXT record. + */ + +static void +dnssdFreeTxtRecord(cupsd_txt_t *txt) /* I - TXT record */ +{ +# ifdef HAVE_DNSSD + TXTRecordDeallocate(txt); + +# else /* HAVE_AVAHI */ + avahi_string_list_free(*txt); + *txt = NULL; +# endif /* HAVE_DNSSD */ } @@ -2609,6 +932,7 @@ dnssdPackTxtRecord(int *txt_len, /* O - TXT record length */ * 'dnssdRegisterCallback()' - DNSServiceRegister callback. */ +# ifdef HAVE_DNSSD static void dnssdRegisterCallback( DNSServiceRef sdRef, /* I - DNS Service reference */ @@ -2617,7 +941,7 @@ dnssdRegisterCallback( const char *name, /* I - Service name */ const char *regtype, /* I - Service type */ const char *domain, /* I - Domain. ".local" for now */ - void *context) /* I - User-defined context */ + void *context) /* I - Printer */ { cupsd_printer_t *p = (cupsd_printer_t *)context; /* Current printer */ @@ -2650,245 +974,330 @@ dnssdRegisterCallback( } } +# else /* HAVE_AVAHI */ +static void +dnssdRegisterCallback( + AvahiEntryGroup *srv, /* I - Service */ + AvahiEntryGroupState state, /* I - Registration state */ + void *context) /* I - Printer */ +{ + cupsd_printer_t *p = (cupsd_printer_t *)context; + /* Current printer */ + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "dnssdRegisterCallback(srv=%p, state=%d, context=%p) " + "for %s (%s)", srv, state, context, + p ? p->name : "Web Interface", + p ? (p->reg_name ? p->reg_name : "(null)") : "NA"); + + /* TODO: Handle collisions with avahi_alternate_service_name(p->reg_name)? */ +} +# endif /* HAVE_DNSSD */ + /* - * 'dnssdRegisterPrinter()' - Start sending broadcast information for a printer - * or update the broadcast contents. + * 'dnssdRegisterInstance()' - Register an instance of a printer service. */ -static void -dnssdRegisterPrinter(cupsd_printer_t *p)/* I - Printer */ +static int /* O - 1 on success, 0 on failure */ +dnssdRegisterInstance( + cupsd_srv_t *srv, /* O - Service */ + cupsd_printer_t *p, /* I - Printer */ + char *name, /* I - DNS-SD service name */ + const char *type, /* I - DNS-SD service type */ + const char *subtypes, /* I - Subtypes to register or NULL */ + int port, /* I - Port number or 0 */ + cupsd_txt_t *txt, /* I - TXT record */ + int commit) /* I - Commit registration? */ { - DNSServiceErrorType se; /* dnssd errors */ - char *ipp_txt, /* IPP TXT record buffer */ - *printer_txt, /* LPD TXT record buffer */ - name[1024], /* Service name */ - *nameptr; /* Pointer into name */ - int ipp_len, /* IPP TXT record length */ - printer_len, /* LPD TXT record length */ - printer_port; /* LPD port number */ - const char *regtype; /* Registration type */ + char temp[256], /* Temporary string */ + *ptr; /* Pointer into string */ + int error; /* Any error */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdRegisterPrinter(%s) %s", p->name, - !p->ipp_ref ? "new" : "update"); + cupsdLogMessage(CUPSD_LOG_DEBUG, + "Registering \"%s\" with DNS-SD type \"%s\".", name, type); - /* - * If per-printer sharing was just disabled make sure we're not - * registered before returning. - */ + if (p && !srv) + { + /* + * Assign the correct pointer for "srv"... + */ - if (!p->shared) +# ifdef HAVE_DNSSD + if (!strcmp(type, "_printer._tcp")) + srv = &p->printer_srv; /* Target LPD service */ +# ifdef HAVE_SSL + else if (!strcmp(type, "_ipps._tcp")) + srv = &p->ipps_srv; /* Target IPPS service */ +# endif /* HAVE_SSL */ + else + srv = &p->ipp_srv; /* Target IPP service */ + +# else /* HAVE_AVAHI */ + srv = &p->ipp_srv; /* Target service group */ +# endif /* HAVE_DNSSD */ + } + +# ifdef HAVE_DNSSD + (void)commit; + +# else /* HAVE_AVAHI */ + avahi_threaded_poll_lock(DNSSDMaster); + + if (!*srv) + *srv = avahi_entry_group_new(DNSSDClient, dnssdRegisterCallback, NULL); + if (!*srv) { - dnssdDeregisterPrinter(p); - return; + avahi_threaded_poll_unlock(DNSSDMaster); + + cupsdLogMessage(CUPSD_LOG_WARN, "DNS-SD registration of \"%s\" failed: %s", + name, dnssdErrorString(avahi_client_errno(DNSSDClient))); + return (0); } +# endif /* HAVE_DNSSD */ /* - * The registered name takes the form of "<printer-info> @ <computer name>"... + * Make sure the name is <= 63 octets, and when we truncate be sure to + * properly truncate any UTF-8 characters... */ - if (p->info && strlen(p->info) > 0) + ptr = name + strlen(name); + while ((ptr - name) > 63) { - if (DNSSDComputerName) - snprintf(name, sizeof(name), "%s @ %s", p->info, DNSSDComputerName); - else - strlcpy(name, p->info, sizeof(name)); + do + { + ptr --; + } + while (ptr > name && (*ptr & 0xc0) == 0x80); + + if (ptr > name) + *ptr = '\0'; } - else if (DNSSDComputerName) - snprintf(name, sizeof(name), "%s @ %s", p->name, DNSSDComputerName); - else - strlcpy(name, p->name, sizeof(name)); /* - * If an existing printer was renamed, unregister it and start over... + * Register the service... */ - if (p->reg_name && strcmp(p->reg_name, name)) - dnssdDeregisterPrinter(p); +# ifdef HAVE_DNSSD + if (subtypes) + snprintf(temp, sizeof(temp), "%s,%s", type, subtypes); + else + strlcpy(temp, type, sizeof(temp)); - if (!p->reg_name) + *srv = DNSSDMaster; + error = DNSServiceRegister(srv, kDNSServiceFlagsShareConnection, + 0, name, temp, NULL, NULL, htons(port), + txt ? TXTRecordGetLength(txt) : 0, + txt ? TXTRecordGetBytesPtr(txt) : NULL, + dnssdRegisterCallback, p); + +# else /* HAVE_AVAHI */ + if (txt) { - cupsdSetString(&p->reg_name, name); - cupsArrayAdd(DNSSDPrinters, p); + AvahiStringList *temptxt; + for (temptxt = *txt; temptxt; temptxt = temptxt->next) + cupsdLogMessage(CUPSD_LOG_DEBUG, "DNS_SD \"%s\" %s", name, temptxt->text); } - /* - * Register IPP and (optionally) LPD... - */ - - ipp_len = 0; /* anti-compiler-warning-code */ - ipp_txt = dnssdBuildTxtRecord(&ipp_len, p, 0); + error = avahi_entry_group_add_service_strlst(*srv, AVAHI_IF_UNSPEC, + AVAHI_PROTO_UNSPEC, 0, name, + type, NULL, NULL, port, + txt ? *txt : NULL); + if (error) + cupsdLogMessage(CUPSD_LOG_DEBUG, "DNS-SD service add for \"%s\" failed.", + name); - if (p->ipp_ref && - (ipp_len != p->ipp_len || memcmp(ipp_txt, p->ipp_txt, ipp_len))) + if (!error && subtypes) { /* - * Update the existing registration... + * Register all of the subtypes... */ - /* A TTL of 0 means use record's original value (Radar 3176248) */ - if ((se = DNSServiceUpdateRecord(p->ipp_ref, NULL, 0, ipp_len, ipp_txt, - 0)) == kDNSServiceErr_NoError) - { - if (p->ipp_txt) - free(p->ipp_txt); + char *start, /* Start of subtype */ + subtype[256]; /* Subtype string */ - p->ipp_txt = ipp_txt; - p->ipp_len = ipp_len; - ipp_txt = NULL; - } - else + strlcpy(temp, subtypes, sizeof(temp)); + + for (start = temp; *start; start = ptr) { /* - * Failed to update record, lets close this reference and move on... + * Skip leading whitespace... */ - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to update IPP DNS-SD record for %s - %d", p->name, - se); + while (*start && isspace(*start & 255)) + start ++; - DNSServiceRefDeallocate(p->ipp_ref); - p->ipp_ref = NULL; + /* + * Grab everything up to the next comma or the end of the string... + */ + + for (ptr = start; *ptr && *ptr != ','; ptr ++); + + if (*ptr) + *ptr++ = '\0'; + + if (!*start) + break; + + /* + * Register the subtype... + */ + + snprintf(subtype, sizeof(subtype), "%s._sub.%s", start, type); + + error = avahi_entry_group_add_service_subtype(*srv, AVAHI_IF_UNSPEC, + AVAHI_PROTO_UNSPEC, 0, + name, type, NULL, subtype); + if (error) + { + cupsdLogMessage(CUPSD_LOG_DEBUG, + "DNS-SD subtype %s registration for \"%s\" failed." , + subtype, name); + break; + } } } - if (!p->ipp_ref) + if (!error && commit) { - /* - * Initial registration. Use the _fax-ipp regtype for fax queues... - */ + if ((error = avahi_entry_group_commit(*srv)) != 0) + cupsdLogMessage(CUPSD_LOG_DEBUG, "DNS-SD commit of \"%s\" failed.", + name); + } - regtype = (p->type & CUPS_PRINTER_FAX) ? "_fax-ipp._tcp" : DNSSDRegType; + avahi_threaded_poll_unlock(DNSSDMaster); +# endif /* HAVE_DNSSD */ - cupsdLogMessage(CUPSD_LOG_DEBUG, - "Registering DNS-SD printer %s with name \"%s\" and " - "type \"%s\"", p->name, name, regtype); + if (error) + { + cupsdLogMessage(CUPSD_LOG_WARN, "DNS-SD registration of \"%s\" failed: %s", + name, dnssdErrorString(error)); + cupsdLogMessage(CUPSD_LOG_DEBUG, "DNS-SD type: %s", type); + if (subtypes) + cupsdLogMessage(CUPSD_LOG_DEBUG, "DNS-SD sub-types: %s", subtypes); + } - /* - * Register the queue, dropping characters as needed until we succeed... - */ + return (!error); +} - nameptr = name + strlen(name); - do - { - p->ipp_ref = DNSSDRef; - if ((se = DNSServiceRegister(&p->ipp_ref, kDNSServiceFlagsShareConnection, - 0, name, regtype, NULL, NULL, - htons(DNSSDPort), ipp_len, ipp_txt, - dnssdRegisterCallback, - p)) == kDNSServiceErr_BadParam) - { - /* - * Name is too long, drop trailing characters, taking into account - * UTF-8 encoding... - */ +/* + * 'dnssdRegisterPrinter()' - Start sending broadcast information for a printer + * or update the broadcast contents. + */ - nameptr --; +static void +dnssdRegisterPrinter(cupsd_printer_t *p)/* I - Printer */ +{ + char name[256]; /* Service name */ + int printer_port; /* LPD port number */ + int status; /* Registration status */ + cupsd_txt_t ipp_txt, /* IPP(S) TXT record */ + printer_txt; /* LPD TXT record */ - while (nameptr > name && (*nameptr & 0xc0) == 0x80) - nameptr --; + cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdRegisterPrinter(%s) %s", p->name, + !p->ipp_srv ? "new" : "update"); - if (nameptr > name) - *nameptr = '\0'; - } - } - while (se == kDNSServiceErr_BadParam && nameptr > name); + /* + * Remove the current registrations if we have them and then return if + * per-printer sharing was just disabled... + */ + + dnssdDeregisterPrinter(p, 0); + + if (!p->shared) + return; - if (se == kDNSServiceErr_NoError) + /* + * Set the registered name as needed; the registered name takes the form of + * "<printer-info> @ <computer name>"... + */ + + if (!p->reg_name) + { + if (p->info && strlen(p->info) > 0) { - p->ipp_txt = ipp_txt; - p->ipp_len = ipp_len; - ipp_txt = NULL; + if (DNSSDComputerName) + snprintf(name, sizeof(name), "%s @ %s", p->info, DNSSDComputerName); + else + strlcpy(name, p->info, sizeof(name)); } + else if (DNSSDComputerName) + snprintf(name, sizeof(name), "%s @ %s", p->name, DNSSDComputerName); else - cupsdLogMessage(CUPSD_LOG_WARN, - "DNS-SD IPP registration of \"%s\" failed: %d", - p->name, se); + strlcpy(name, p->name, sizeof(name)); } + else + strlcpy(name, p->reg_name, sizeof(name)); + + /* + * Register IPP and LPD... + * + * We always must register the "_printer" service type in order to reserve + * our name, but use port number 0 if we haven't actually configured cups-lpd + * to share via LPD... + */ - if (ipp_txt) - free(ipp_txt); + ipp_txt = dnssdBuildTxtRecord(p, 0); + printer_txt = dnssdBuildTxtRecord(p, 1); if (BrowseLocalProtocols & BROWSE_LPD) - { - printer_len = 0; /* anti-compiler-warning-code */ printer_port = 515; - printer_txt = dnssdBuildTxtRecord(&printer_len, p, 1); - } else - { - printer_len = 0; printer_port = 0; - printer_txt = NULL; - } - if (p->printer_ref && - (printer_len != p->printer_len || - memcmp(printer_txt, p->printer_txt, printer_len))) + status = dnssdRegisterInstance(NULL, p, name, "_printer._tcp", NULL, + printer_port, &printer_txt, 0); + +# ifdef HAVE_SSL + if (status) + dnssdRegisterInstance(NULL, p, name, "_ipps._tcp", DNSSDSubTypes, + DNSSDPort, &ipp_txt, 0); +# endif /* HAVE_SSL */ + + if (status) { /* - * Update the existing registration... + * Use the "_fax-ipp" service type for fax queues, otherwise use "_ipp"... */ - /* A TTL of 0 means use record's original value (Radar 3176248) */ - if ((se = DNSServiceUpdateRecord(p->printer_ref, NULL, 0, printer_len, - printer_txt, - 0)) == kDNSServiceErr_NoError) - { - if (p->printer_txt) - free(p->printer_txt); - - p->printer_txt = printer_txt; - p->printer_len = printer_len; - printer_txt = NULL; - } + if (p->type & CUPS_PRINTER_FAX) + status = dnssdRegisterInstance(NULL, p, name, "_fax-ipp._tcp", + DNSSDSubTypes, DNSSDPort, &ipp_txt, 1); else - { - /* - * Failed to update record, lets close this reference and move on... - */ - - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to update LPD DNS-SD record for %s - %d", - p->name, se); - - DNSServiceRefDeallocate(p->printer_ref); - p->printer_ref = NULL; - } + status = dnssdRegisterInstance(NULL, p, name, "_ipp._tcp", DNSSDSubTypes, + DNSSDPort, &ipp_txt, 1); } - if (!p->printer_ref) + dnssdFreeTxtRecord(&ipp_txt); + dnssdFreeTxtRecord(&printer_txt); + + if (status) { /* - * Initial registration... + * Save the registered name and add the printer to the array of DNS-SD + * printers... */ - cupsdLogMessage(CUPSD_LOG_DEBUG, - "Registering DNS-SD printer %s with name \"%s\" and " - "type \"_printer._tcp\"", p->name, name); - - p->printer_ref = DNSSDRef; - if ((se = DNSServiceRegister(&p->printer_ref, - kDNSServiceFlagsShareConnection, - 0, name, "_printer._tcp", NULL, NULL, - htons(printer_port), printer_len, printer_txt, - dnssdRegisterCallback, - p)) == kDNSServiceErr_NoError) - { - p->printer_txt = printer_txt; - p->printer_len = printer_len; - printer_txt = NULL; - } - else - cupsdLogMessage(CUPSD_LOG_WARN, - "DNS-SD LPD registration of \"%s\" failed: %d", - p->name, se); + cupsdSetString(&p->reg_name, name); + cupsArrayAdd(DNSSDPrinters, p); } + else + { + /* + * Registration failed for this printer... + */ - if (printer_txt) - free(printer_txt); + dnssdDeregisterInstance(&p->ipp_srv); + +# ifdef HAVE_DNSSD +# ifdef HAVE_SSL + dnssdDeregisterInstance(&p->ipps_srv); +# endif /* HAVE_SSL */ + dnssdDeregisterInstance(&p->printer_srv); +# endif /* HAVE_DNSSD */ + } } @@ -2909,28 +1318,27 @@ dnssdStop(void) for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); p; p = (cupsd_printer_t *)cupsArrayNext(Printers)) - dnssdDeregisterPrinter(p); + dnssdDeregisterPrinter(p, 1); /* * Shutdown the rest of the service refs... */ - if (WebIFRef) - { - DNSServiceRefDeallocate(WebIFRef); - WebIFRef = NULL; - } + dnssdDeregisterInstance(&WebIFSrv); - if (RemoteRef) - { - DNSServiceRefDeallocate(RemoteRef); - RemoteRef = NULL; - } +# ifdef HAVE_DNSSD + cupsdRemoveSelect(DNSServiceRefSockFD(DNSSDMaster)); - cupsdRemoveSelect(DNSServiceRefSockFD(DNSSDRef)); + DNSServiceRefDeallocate(DNSSDMaster); + DNSSDMaster = NULL; - DNSServiceRefDeallocate(DNSSDRef); - DNSSDRef = NULL; +# else /* HAVE_AVAHI */ + avahi_client_free(DNSSDClient); + DNSSDClient = NULL; + + avahi_threaded_poll_free(DNSSDMaster); + DNSSDMaster = NULL; +# endif /* HAVE_DNSSD */ cupsArrayDelete(DNSSDPrinters); DNSSDPrinters = NULL; @@ -2939,6 +1347,7 @@ dnssdStop(void) } +# ifdef HAVE_DNSSD /* * 'dnssdUpdate()' - Handle DNS-SD queries. */ @@ -2949,7 +1358,7 @@ dnssdUpdate(void) DNSServiceErrorType sdErr; /* Service discovery error */ - if ((sdErr = DNSServiceProcessResult(DNSSDRef)) != kDNSServiceErr_NoError) + if ((sdErr = DNSServiceProcessResult(DNSSDMaster)) != kDNSServiceErr_NoError) { cupsdLogMessage(CUPSD_LOG_ERROR, "DNS Service Discovery registration error %d!", @@ -2957,7 +1366,7 @@ dnssdUpdate(void) dnssdStop(); } } -#endif /* HAVE_DNSSD */ +# endif /* HAVE_DNSSD */ /* @@ -3016,7 +1425,7 @@ get_auth_info_required( int auth_type; /* Authentication type */ if ((auth_type = auth->type) == CUPSD_AUTH_DEFAULT) - auth_type = DefaultAuthType; + auth_type = cupsdDefaultAuthType(); switch (auth_type) { @@ -3037,6 +1446,7 @@ get_auth_info_required( return ("none"); } +#endif /* HAVE_DNSSD || HAVE_AVAHI */ #ifdef __APPLE__ @@ -3092,2295 +1502,6 @@ get_hostconfig(const char *name) /* I - Name of service */ /* - * 'is_local_queue()' - Determine whether the URI points at a local queue. - */ - -static int /* O - 1 = local, 0 = remote, -1 = bad URI */ -is_local_queue(const char *uri, /* I - Printer URI */ - char *host, /* O - Host string */ - int hostlen, /* I - Length of host buffer */ - char *resource, /* O - Resource string */ - int resourcelen) /* I - Length of resource buffer */ -{ - char scheme[32], /* Scheme portion of URI */ - username[HTTP_MAX_URI]; /* Username portion of URI */ - int port; /* Port portion of URI */ - cupsd_netif_t *iface; /* Network interface */ - - - /* - * Pull the URI apart to see if this is a local or remote printer... - */ - - if (httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme), - username, sizeof(username), host, hostlen, &port, - resource, resourcelen) < HTTP_URI_OK) - return (-1); - - DEBUG_printf(("host=\"%s\", ServerName=\"%s\"\n", host, ServerName)); - - /* - * Check for local server addresses... - */ - - if (!_cups_strcasecmp(host, ServerName) && port == LocalPort) - return (1); - - cupsdNetIFUpdate(); - - for (iface = (cupsd_netif_t *)cupsArrayFirst(NetIFList); - iface; - iface = (cupsd_netif_t *)cupsArrayNext(NetIFList)) - if (!_cups_strcasecmp(host, iface->hostname) && port == iface->port) - return (1); - - /* - * If we get here, the printer is remote... - */ - - return (0); -} - - -/* - * 'process_browse_data()' - Process new browse data. - */ - -static void -process_browse_data( - const char *uri, /* I - URI of printer/class */ - const char *host, /* I - Hostname */ - const char *resource, /* I - Resource path */ - cups_ptype_t type, /* I - Printer type */ - ipp_pstate_t state, /* I - Printer state */ - const char *location, /* I - Printer location */ - const char *info, /* I - Printer information */ - const char *make_model, /* I - Printer make and model */ - int num_attrs, /* I - Number of attributes */ - cups_option_t *attrs) /* I - Attributes */ -{ - int i; /* Looping var */ - int update; /* Update printer attributes? */ - char finaluri[HTTP_MAX_URI], /* Final URI for printer */ - name[IPP_MAX_NAME], /* Name of printer */ - newname[IPP_MAX_NAME], /* New name of printer */ - *hptr, /* Pointer into hostname */ - *sptr; /* Pointer into ServerName */ - const char *shortname; /* Short queue name (queue) */ - char local_make_model[IPP_MAX_NAME]; - /* Local make and model */ - cupsd_printer_t *p; /* Printer information */ - const char *ipp_options, /* ipp-options value */ - *lease_duration, /* lease-duration value */ - *uuid; /* uuid value */ - int is_class; /* Is this queue a class? */ - - - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "process_browse_data(uri=\"%s\", host=\"%s\", " - "resource=\"%s\", type=%x, state=%d, location=\"%s\", " - "info=\"%s\", make_model=\"%s\", num_attrs=%d, attrs=%p)", - uri, host, resource, type, state, - location ? location : "(nil)", info ? info : "(nil)", - make_model ? make_model : "(nil)", num_attrs, attrs); - - /* - * Determine if the URI contains any illegal characters in it... - */ - - if (strncmp(uri, "ipp://", 6) || !host[0] || - (strncmp(resource, "/printers/", 10) && - strncmp(resource, "/classes/", 9))) - { - cupsdLogMessage(CUPSD_LOG_ERROR, "Bad printer URI in browse data: %s", uri); - return; - } - - if (strchr(resource, '?') || - (!strncmp(resource, "/printers/", 10) && strchr(resource + 10, '/')) || - (!strncmp(resource, "/classes/", 9) && strchr(resource + 9, '/'))) - { - cupsdLogMessage(CUPSD_LOG_ERROR, "Bad resource in browse data: %s", - resource); - return; - } - - /* - * OK, this isn't a local printer; add any remote options... - */ - - ipp_options = cupsGetOption("ipp-options", num_attrs, attrs); - - if (BrowseRemoteOptions) - { - if (BrowseRemoteOptions[0] == '?') - { - /* - * Override server-supplied options... - */ - - snprintf(finaluri, sizeof(finaluri), "%s%s", uri, BrowseRemoteOptions); - } - else if (ipp_options) - { - /* - * Combine the server and local options... - */ - - snprintf(finaluri, sizeof(finaluri), "%s?%s+%s", uri, ipp_options, - BrowseRemoteOptions); - } - else - { - /* - * Just use the local options... - */ - - snprintf(finaluri, sizeof(finaluri), "%s?%s", uri, BrowseRemoteOptions); - } - - uri = finaluri; - } - else if (ipp_options) - { - /* - * Just use the server-supplied options... - */ - - snprintf(finaluri, sizeof(finaluri), "%s?%s", uri, ipp_options); - uri = finaluri; - } - - /* - * See if we already have it listed in the Printers list, and add it if not... - */ - - type |= CUPS_PRINTER_REMOTE | CUPS_PRINTER_DISCOVERED; - type &= ~CUPS_PRINTER_IMPLICIT; - update = 0; - hptr = strchr(host, '.'); - sptr = strchr(ServerName, '.'); - is_class = type & CUPS_PRINTER_CLASS; - uuid = cupsGetOption("uuid", num_attrs, attrs); - - if (!ServerNameIsIP && sptr != NULL && hptr != NULL) - { - /* - * Strip the common domain name components... - */ - - while (hptr != NULL) - { - if (!_cups_strcasecmp(hptr, sptr)) - { - *hptr = '\0'; - break; - } - else - hptr = strchr(hptr + 1, '.'); - } - } - - if (is_class) - { - /* - * Remote destination is a class... - */ - - if (!strncmp(resource, "/classes/", 9)) - snprintf(name, sizeof(name), "%s@%s", resource + 9, host); - else - return; - - shortname = resource + 9; - } - else - { - /* - * Remote destination is a printer... - */ - - if (!strncmp(resource, "/printers/", 10)) - snprintf(name, sizeof(name), "%s@%s", resource + 10, host); - else - return; - - shortname = resource + 10; - } - - if (hptr && !*hptr) - *hptr = '.'; /* Resource FQDN */ - - if ((p = cupsdFindDest(name)) == NULL && BrowseShortNames) - { - /* - * Long name doesn't exist, try short name... - */ - - cupsdLogMessage(CUPSD_LOG_DEBUG, "process_browse_data: %s not found...", - name); - - if ((p = cupsdFindDest(shortname)) == NULL) - { - /* - * Short name doesn't exist, use it for this shared queue. - */ - - cupsdLogMessage(CUPSD_LOG_DEBUG2, "process_browse_data: %s not found...", - shortname); - strlcpy(name, shortname, sizeof(name)); - } - else - { - /* - * Short name exists... - */ - - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "process_browse_data: %s found, type=%x, hostname=%s...", - shortname, p->type, p->hostname ? p->hostname : "(nil)"); - - if (p->type & CUPS_PRINTER_IMPLICIT) - p = NULL; /* Don't replace implicit classes */ - else if (p->hostname && _cups_strcasecmp(p->hostname, host)) - { - /* - * Short name exists but is for a different host. If this is a remote - * queue, rename it and use the long name... - */ - - if (p->type & CUPS_PRINTER_REMOTE) - { - cupsdLogMessage(CUPSD_LOG_DEBUG, - "Renamed remote %s \"%s\" to \"%s@%s\"...", - is_class ? "class" : "printer", p->name, p->name, - p->hostname); - cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, p, NULL, - "%s \'%s\' deleted by directory services.", - is_class ? "Class" : "Printer", p->name); - - snprintf(newname, sizeof(newname), "%s@%s", p->name, p->hostname); - cupsdRenamePrinter(p, newname); - - cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL, - "%s \'%s\' added by directory services.", - is_class ? "Class" : "Printer", p->name); - } - - /* - * Force creation with long name... - */ - - p = NULL; - } - } - } - else if (p) - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "process_browse_data: %s found, type=%x, hostname=%s...", - name, p->type, p->hostname ? p->hostname : "(nil)"); - - if (!p) - { - /* - * Queue doesn't exist; add it... - */ - - if (is_class) - p = cupsdAddClass(name); - else - p = cupsdAddPrinter(name); - - if (!p) - return; - - cupsdClearString(&(p->hostname)); - - cupsdLogMessage(CUPSD_LOG_DEBUG, "Added remote %s \"%s\"...", - is_class ? "class" : "printer", name); - - cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL, - "%s \'%s\' added by directory services.", - is_class ? "Class" : "Printer", name); - - /* - * Force the URI to point to the real server... - */ - - p->type = type & ~CUPS_PRINTER_REJECTING; - p->accepting = 1; - - cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP); - } - - if (!p->hostname) - { - /* - * Hostname not set, so this must be a cached remote printer - * that was created for a pending print job... - */ - - cupsdSetString(&p->hostname, host); - cupsdSetString(&p->uri, uri); - cupsdSetString(&p->device_uri, uri); - update = 1; - - cupsdMarkDirty(CUPSD_DIRTY_REMOTE); - } - - /* - * Update the state... - */ - - p->state = state; - p->browse_time = time(NULL); - - if ((lease_duration = cupsGetOption("lease-duration", num_attrs, - attrs)) != NULL) - { - /* - * Grab the lease-duration for the browse data; anything less then 1 - * second or more than 1 week gets the default BrowseTimeout... - */ - - i = atoi(lease_duration); - if (i < 1 || i > 604800) - i = BrowseTimeout; - - p->browse_expire = p->browse_time + i; - } - else - p->browse_expire = p->browse_time + BrowseTimeout; - - if (type & CUPS_PRINTER_REJECTING) - { - type &= ~CUPS_PRINTER_REJECTING; - - if (p->accepting) - { - update = 1; - p->accepting = 0; - } - } - else if (!p->accepting) - { - update = 1; - p->accepting = 1; - } - - if (p->type != type) - { - p->type = type; - update = 1; - } - - if (uuid && strcmp(p->uuid, uuid)) - { - cupsdSetString(&p->uuid, uuid); - update = 1; - } - - if (location && (!p->location || strcmp(p->location, location))) - { - cupsdSetString(&p->location, location); - update = 1; - } - - if (info && (!p->info || strcmp(p->info, info))) - { - cupsdSetString(&p->info, info); - update = 1; - - cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE); - } - - if (!make_model || !make_model[0]) - { - if (is_class) - snprintf(local_make_model, sizeof(local_make_model), - "Remote Class on %s", host); - else - snprintf(local_make_model, sizeof(local_make_model), - "Remote Printer on %s", host); - } - else - snprintf(local_make_model, sizeof(local_make_model), - "%s on %s", make_model, host); - - if (!p->make_model || strcmp(p->make_model, local_make_model)) - { - cupsdSetString(&p->make_model, local_make_model); - update = 1; - } - - if (p->num_options) - { - if (!update && !(type & CUPS_PRINTER_DELETE)) - { - /* - * See if we need to update the attributes... - */ - - if (p->num_options != num_attrs) - update = 1; - else - { - for (i = 0; i < num_attrs; i ++) - if (strcmp(attrs[i].name, p->options[i].name) || - (!attrs[i].value != !p->options[i].value) || - (attrs[i].value && strcmp(attrs[i].value, p->options[i].value))) - { - update = 1; - break; - } - } - } - - /* - * Free the old options... - */ - - cupsFreeOptions(p->num_options, p->options); - } - - p->num_options = num_attrs; - p->options = attrs; - - if (type & CUPS_PRINTER_DELETE) - { - cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, p, NULL, - "%s \'%s\' deleted by directory services.", - is_class ? "Class" : "Printer", p->name); - - cupsdExpireSubscriptions(p, NULL); - - cupsdDeletePrinter(p, 1); - cupsdUpdateImplicitClasses(); - cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE); - } - else if (update) - { - cupsdSetPrinterAttrs(p); - cupsdUpdateImplicitClasses(); - } - - /* - * See if we have a default printer... If not, make the first network - * default printer the default. - */ - - if (DefaultPrinter == NULL && Printers != NULL && UseNetworkDefault) - { - /* - * Find the first network default printer and use it... - */ - - for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); - p; - p = (cupsd_printer_t *)cupsArrayNext(Printers)) - if (p->type & CUPS_PRINTER_DEFAULT) - { - DefaultPrinter = p; - cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE); - break; - } - } - - /* - * Do auto-classing if needed... - */ - - process_implicit_classes(); -} - - -/* - * 'process_implicit_classes()' - Create/update implicit classes as needed. - */ - -static void -process_implicit_classes(void) -{ - int i; /* Looping var */ - int update; /* Update printer attributes? */ - char name[IPP_MAX_NAME], /* Name of printer */ - *hptr; /* Pointer into hostname */ - cupsd_printer_t *p, /* Printer information */ - *pclass, /* Printer class */ - *first; /* First printer in class */ - int offset, /* Offset of name */ - len; /* Length of name */ - - - if (!ImplicitClasses || !Printers) - return; - - /* - * Loop through all available printers and create classes as needed... - */ - - for (p = (cupsd_printer_t *)cupsArrayFirst(Printers), len = 0, offset = 0, - update = 0, pclass = NULL, first = NULL; - p != NULL; - p = (cupsd_printer_t *)cupsArrayNext(Printers)) - { - /* - * Skip implicit classes... - */ - - if (p->type & CUPS_PRINTER_IMPLICIT) - { - len = 0; - continue; - } - - /* - * If len == 0, get the length of this printer name up to the "@" - * sign (if any). - */ - - cupsArraySave(Printers); - - if (len > 0 && - !_cups_strncasecmp(p->name, name + offset, len) && - (p->name[len] == '\0' || p->name[len] == '@')) - { - /* - * We have more than one printer with the same name; see if - * we have a class, and if this printer is a member... - */ - - if (pclass && _cups_strcasecmp(pclass->name, name)) - { - if (update) - cupsdSetPrinterAttrs(pclass); - - update = 0; - pclass = NULL; - } - - if (!pclass && (pclass = cupsdFindDest(name)) == NULL) - { - /* - * Need to add the class... - */ - - pclass = cupsdAddPrinter(name); - cupsArrayAdd(ImplicitPrinters, pclass); - - pclass->type |= CUPS_PRINTER_IMPLICIT; - pclass->accepting = 1; - pclass->state = IPP_PRINTER_IDLE; - - cupsdSetString(&pclass->location, p->location); - cupsdSetString(&pclass->info, p->info); - - cupsdSetString(&pclass->job_sheets[0], p->job_sheets[0]); - cupsdSetString(&pclass->job_sheets[1], p->job_sheets[1]); - - update = 1; - - cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE); - - cupsdLogMessage(CUPSD_LOG_DEBUG, "Added implicit class \"%s\"...", - name); - cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL, - "Implicit class \'%s\' added by directory services.", - name); - } - - if (first != NULL) - { - for (i = 0; i < pclass->num_printers; i ++) - if (pclass->printers[i] == first) - break; - - if (i >= pclass->num_printers) - { - first->in_implicit_class = 1; - cupsdAddPrinterToClass(pclass, first); - } - - first = NULL; - } - - for (i = 0; i < pclass->num_printers; i ++) - if (pclass->printers[i] == p) - break; - - if (i >= pclass->num_printers) - { - p->in_implicit_class = 1; - cupsdAddPrinterToClass(pclass, p); - update = 1; - } - } - else - { - /* - * First time around; just get name length and mark it as first - * in the list... - */ - - if ((hptr = strchr(p->name, '@')) != NULL) - len = hptr - p->name; - else - len = strlen(p->name); - - if (len >= sizeof(name)) - { - /* - * If the printer name length somehow is greater than we normally allow, - * skip this printer... - */ - - len = 0; - cupsArrayRestore(Printers); - continue; - } - - strncpy(name, p->name, len); - name[len] = '\0'; - offset = 0; - - if ((first = (hptr ? cupsdFindDest(name) : p)) != NULL && - !(first->type & CUPS_PRINTER_IMPLICIT)) - { - /* - * Can't use same name as a local printer; add "Any" to the - * front of the name, unless we have explicitly disabled - * the "ImplicitAnyClasses"... - */ - - if (ImplicitAnyClasses && len < (sizeof(name) - 4)) - { - /* - * Add "Any" to the class name... - */ - - strcpy(name, "Any"); - strncpy(name + 3, p->name, len); - name[len + 3] = '\0'; - offset = 3; - } - else - { - /* - * Don't create an implicit class if we have a local printer - * with the same name... - */ - - len = 0; - cupsArrayRestore(Printers); - continue; - } - } - - first = p; - } - - cupsArrayRestore(Printers); - } - - /* - * Update the last printer class as needed... - */ - - if (pclass && update) - cupsdSetPrinterAttrs(pclass); -} - - -/* - * 'send_cups_browse()' - Send new browsing information using the CUPS - * protocol. - */ - -static void -send_cups_browse(cupsd_printer_t *p) /* I - Printer to send */ -{ - int i; /* Looping var */ - cups_ptype_t type; /* Printer type */ - cupsd_dirsvc_addr_t *b; /* Browse address */ - int bytes; /* Length of packet */ - char packet[1453], /* Browse data packet */ - uri[1024], /* Printer URI */ - location[1024], /* printer-location */ - info[1024], /* printer-info */ - make_model[1024], - /* printer-make-and-model */ - air[1024]; /* auth-info-required */ - cupsd_netif_t *iface; /* Network interface */ - - - /* - * Figure out the printer type value... - */ - - type = p->type | CUPS_PRINTER_REMOTE; - - if (!p->accepting) - type |= CUPS_PRINTER_REJECTING; - - if (p == DefaultPrinter) - type |= CUPS_PRINTER_DEFAULT; - - /* - * Remove quotes from printer-info, printer-location, and - * printer-make-and-model attributes... - */ - - dequote(location, p->location, sizeof(location)); - dequote(info, p->info, sizeof(info)); - - if (p->make_model) - dequote(make_model, p->make_model, sizeof(make_model)); - else if (p->type & CUPS_PRINTER_CLASS) - { - if (p->num_printers > 0 && p->printers[0]->make_model) - strlcpy(make_model, p->printers[0]->make_model, sizeof(make_model)); - else - strlcpy(make_model, "Local Printer Class", sizeof(make_model)); - } - else if (p->raw) - strlcpy(make_model, "Local Raw Printer", sizeof(make_model)); - else - strlcpy(make_model, "Local System V Printer", sizeof(make_model)); - - if (get_auth_info_required(p, packet, sizeof(packet))) - snprintf(air, sizeof(air), " auth-info-required=%s", packet); - else - air[0] = '\0'; - - /* - * Send a packet to each browse address... - */ - - for (i = NumBrowsers, b = Browsers; i > 0; i --, b ++) - if (b->iface[0]) - { - /* - * Send the browse packet to one or more interfaces... - */ - - if (!strcmp(b->iface, "*")) - { - /* - * Send to all local interfaces... - */ - - cupsdNetIFUpdate(); - - for (iface = (cupsd_netif_t *)cupsArrayFirst(NetIFList); - iface; - iface = (cupsd_netif_t *)cupsArrayNext(NetIFList)) - { - /* - * Only send to local, IPv4 interfaces... - */ - - if (!iface->is_local || !iface->port || - iface->address.addr.sa_family != AF_INET) - continue; - - httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, - iface->hostname, iface->port, - (p->type & CUPS_PRINTER_CLASS) ? "/classes/%s" : - "/printers/%s", - p->name); - snprintf(packet, sizeof(packet), - "%x %x %s \"%s\" \"%s\" \"%s\" %s%s uuid=%s\n", - type, p->state, uri, location, info, make_model, - p->browse_attrs ? p->browse_attrs : "", air, p->uuid); - - bytes = strlen(packet); - - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "cupsdSendBrowseList: (%d bytes to \"%s\") %s", bytes, - iface->name, packet); - - iface->broadcast.ipv4.sin_port = htons(BrowsePort); - - sendto(BrowseSocket, packet, bytes, 0, - (struct sockaddr *)&(iface->broadcast), - httpAddrLength(&(iface->broadcast))); - } - } - else if ((iface = cupsdNetIFFind(b->iface)) != NULL) - { - /* - * Send to the named interface using the IPv4 address... - */ - - while (iface) - if (strcmp(b->iface, iface->name)) - { - iface = NULL; - break; - } - else if (iface->address.addr.sa_family == AF_INET && iface->port) - break; - else - iface = (cupsd_netif_t *)cupsArrayNext(NetIFList); - - if (iface) - { - httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, - iface->hostname, iface->port, - (p->type & CUPS_PRINTER_CLASS) ? "/classes/%s" : - "/printers/%s", - p->name); - snprintf(packet, sizeof(packet), - "%x %x %s \"%s\" \"%s\" \"%s\" %s%s uuid=%s\n", - type, p->state, uri, location, info, make_model, - p->browse_attrs ? p->browse_attrs : "", air, p->uuid); - - bytes = strlen(packet); - - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "cupsdSendBrowseList: (%d bytes to \"%s\") %s", bytes, - iface->name, packet); - - iface->broadcast.ipv4.sin_port = htons(BrowsePort); - - sendto(BrowseSocket, packet, bytes, 0, - (struct sockaddr *)&(iface->broadcast), - httpAddrLength(&(iface->broadcast))); - } - } - } - else - { - /* - * Send the browse packet to the indicated address using - * the default server name... - */ - - snprintf(packet, sizeof(packet), - "%x %x %s \"%s\" \"%s\" \"%s\" %s%s uuid=%s\n", - type, p->state, p->uri, location, info, make_model, - p->browse_attrs ? p->browse_attrs : "", air, p->uuid); - - bytes = strlen(packet); - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "cupsdSendBrowseList: (%d bytes) %s", bytes, packet); - - if (sendto(BrowseSocket, packet, bytes, 0, - (struct sockaddr *)&(b->to), - httpAddrLength(&(b->to))) <= 0) - { - /* - * Unable to send browse packet, so remove this address from the - * list... - */ - - cupsdLogMessage(CUPSD_LOG_ERROR, - "cupsdSendBrowseList: sendto failed for browser " - "%d - %s.", - (int)(b - Browsers + 1), strerror(errno)); - - if (i > 1) - memmove(b, b + 1, (i - 1) * sizeof(cupsd_dirsvc_addr_t)); - - b --; - NumBrowsers --; - } - } -} - - -#ifdef HAVE_LDAP -/* - * 'ldap_search_rec()' - LDAP Search with reconnect - */ - -static int /* O - Return code */ -ldap_search_rec(LDAP *ld, /* I - LDAP handler */ - char *base, /* I - Base dn */ - int scope, /* I - LDAP search scope */ - char *filter, /* I - Filter string */ - char *attrs[], /* I - Requested attributes */ - int attrsonly, /* I - Return only attributes? */ - LDAPMessage **res) /* I - LDAP handler */ -{ - int rc; /* Return code */ - LDAP *ldr; /* LDAP handler after reconnect */ - - -# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 - rc = ldap_search_ext_s(ld, base, scope, filter, attrs, attrsonly, NULL, NULL, - NULL, LDAP_NO_LIMIT, res); -# else - rc = ldap_search_s(ld, base, scope, filter, attrs, attrsonly, res); -# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */ - - /* - * If we have a connection problem try again... - */ - - if (rc == LDAP_SERVER_DOWN || rc == LDAP_CONNECT_ERROR) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "LDAP search failed with status %d: %s", - rc, ldap_err2string(rc)); - cupsdLogMessage(CUPSD_LOG_INFO, - "We try the LDAP search once again after reconnecting to " - "the server"); - ldap_freeres(*res); - ldr = ldap_reconnect(); - -# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 - rc = ldap_search_ext_s(ldr, base, scope, filter, attrs, attrsonly, NULL, - NULL, NULL, LDAP_NO_LIMIT, res); -# else - rc = ldap_search_s(ldr, base, scope, filter, attrs, attrsonly, res); -# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */ - } - - if (rc == LDAP_NO_SUCH_OBJECT) - cupsdLogMessage(CUPSD_LOG_DEBUG, - "ldap_search_rec: LDAP entry/object not found"); - else if (rc != LDAP_SUCCESS) - cupsdLogMessage(CUPSD_LOG_ERROR, - "ldap_search_rec: LDAP search failed with status %d: %s", - rc, ldap_err2string(rc)); - - if (rc != LDAP_SUCCESS) - ldap_freeres(*res); - - return (rc); -} - - -/* - * 'ldap_freeres()' - Free LDAPMessage - */ - -static void -ldap_freeres(LDAPMessage *entry) /* I - LDAP handler */ -{ - int rc; /* Return value */ - - - rc = ldap_msgfree(entry); - if (rc == -1) - cupsdLogMessage(CUPSD_LOG_WARN, "Can't free LDAPMessage!"); - else if (rc == 0) - cupsdLogMessage(CUPSD_LOG_DEBUG2, "Freeing LDAPMessage was unnecessary"); -} - - -/* - * 'ldap_getval_char()' - Get first LDAP value and convert to string - */ - -static int /* O - Return code */ -ldap_getval_firststring( - LDAP *ld, /* I - LDAP handler */ - LDAPMessage *entry, /* I - LDAP message or search result */ - char *attr, /* I - the wanted attribute */ - char *retval, /* O - String to return */ - unsigned long maxsize) /* I - Max string size */ -{ - char *dn; /* LDAP DN */ - int rc = 0; /* Return code */ -# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 - struct berval **bval; /* LDAP value array */ - unsigned long size; /* String size */ - - - /* - * Get value from LDAPMessage... - */ - - if ((bval = ldap_get_values_len(ld, entry, attr)) == NULL) - { - rc = -1; - dn = ldap_get_dn(ld, entry); - cupsdLogMessage(CUPSD_LOG_WARN, - "Failed to get LDAP value %s for %s!", - attr, dn); - ldap_memfree(dn); - } - else - { - /* - * Check size and copy value into our string... - */ - - size = maxsize; - if (size < (bval[0]->bv_len + 1)) - { - rc = -1; - dn = ldap_get_dn(ld, entry); - cupsdLogMessage(CUPSD_LOG_WARN, - "Attribute %s is too big! (dn: %s)", - attr, dn); - ldap_memfree(dn); - } - else - size = bval[0]->bv_len + 1; - - strlcpy(retval, bval[0]->bv_val, size); - ldap_value_free_len(bval); - } -# else - char **value; /* LDAP value */ - - /* - * Get value from LDAPMessage... - */ - - if ((value = (char **)ldap_get_values(ld, entry, attr)) == NULL) - { - rc = -1; - dn = ldap_get_dn(ld, entry); - cupsdLogMessage(CUPSD_LOG_WARN, "Failed to get LDAP value %s for %s!", - attr, dn); - ldap_memfree(dn); - } - else - { - strlcpy(retval, *value, maxsize); - ldap_value_free(value); - } -# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */ - - return (rc); -} - - -/* - * 'send_ldap_ou()' - Send LDAP ou registrations. - */ - -static void -send_ldap_ou(char *ou, /* I - Servername/ou to register */ - char *basedn, /* I - Our base dn */ - char *descstring) /* I - Description for ou */ -{ - int i; /* Looping var... */ - LDAPMod mods[3]; /* The 3 attributes we will be adding */ - LDAPMod *pmods[4]; /* Pointers to the 3 attributes + NULL */ - LDAPMessage *res, /* Search result token */ - *e; /* Current entry from search */ - int rc; /* LDAP status */ - int rcmod; /* LDAP status for modifications */ - char dn[1024], /* DN of the organizational unit we are adding */ - *desc[2], /* Change records */ - *ou_value[2]; - char old_desc[1024]; /* Old description */ - static const char * const objectClass_values[] = - { /* The 2 objectClass's we use in */ - "top", /* our LDAP entries */ - "organizationalUnit", - NULL - }; - static const char * const ou_attrs[] =/* CUPS LDAP attributes */ - { - "description", - NULL - }; - - - cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_ldap_ou: %s", ou); - - /* - * Reconnect if LDAP Handle is invalid... - */ - - if (!BrowseLDAPHandle) - { - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "send_ldap_ou: LDAP Handle is invalid. Try reconnecting..."); - ldap_reconnect(); - return; - } - - /* - * Prepare ldap search... - */ - - snprintf(dn, sizeof(dn), "ou=%s, %s", ou, basedn); - cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_ldap_ou: dn=\"%s\"", dn); - - ou_value[0] = ou; - ou_value[1] = NULL; - desc[0] = descstring; - desc[1] = NULL; - - mods[0].mod_type = "ou"; - mods[0].mod_values = ou_value; - mods[1].mod_type = "description"; - mods[1].mod_values = desc; - mods[2].mod_type = "objectClass"; - mods[2].mod_values = (char **)objectClass_values; - - rc = ldap_search_rec(BrowseLDAPHandle, dn, LDAP_SCOPE_BASE, NULL, - (char **)ou_attrs, 0, &res); - - /* - * If ldap search was not successfull then exit function... - */ - - if (rc != LDAP_SUCCESS && rc != LDAP_NO_SUCH_OBJECT) - return; - - /* - * Check if we need to insert or update the LDAP entry... - */ - - if (ldap_count_entries(BrowseLDAPHandle, res) > 0 && - rc != LDAP_NO_SUCH_OBJECT) - { - /* - * Printserver has already been registered, check if - * modification is required... - */ - - e = ldap_first_entry(BrowseLDAPHandle, res); - - /* - * Get the required values from this entry... - */ - - if (ldap_getval_firststring(BrowseLDAPHandle, e, "description", old_desc, - sizeof(old_desc)) == -1) - old_desc[0] = '\0'; - - /* - * Check if modification is required... - */ - - if ( strcmp(desc[0], old_desc) == 0 ) - { - /* - * LDAP entry for the printer exists. - * Printer has already been registered, - * no modifications required... - */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "send_ldap_ou: No updates required for %s", ou); - } - else - { - - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "send_ldap_ou: Replace entry for %s", ou); - - for (i = 0; i < 3; i ++) - { - pmods[i] = mods + i; - pmods[i]->mod_op = LDAP_MOD_REPLACE; - } - pmods[i] = NULL; - -# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 - if ((rcmod = ldap_modify_ext_s(BrowseLDAPHandle, dn, pmods, NULL, - NULL)) != LDAP_SUCCESS) -# else - if ((rcmod = ldap_modify_s(BrowseLDAPHandle, dn, pmods)) != LDAP_SUCCESS) -# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */ - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "LDAP modify for %s failed with status %d: %s", - ou, rcmod, ldap_err2string(rcmod)); - if (rcmod == LDAP_SERVER_DOWN) - ldap_reconnect(); - } - } - } - else - { - /* - * Printserver has never been registered, - * add registration... - */ - - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "send_ldap_ou: Add entry for %s", ou); - - for (i = 0; i < 3; i ++) - { - pmods[i] = mods + i; - pmods[i]->mod_op = LDAP_MOD_ADD; - } - pmods[i] = NULL; - -# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 - if ((rcmod = ldap_add_ext_s(BrowseLDAPHandle, dn, pmods, NULL, - NULL)) != LDAP_SUCCESS) -# else - if ((rcmod = ldap_add_s(BrowseLDAPHandle, dn, pmods)) != LDAP_SUCCESS) -# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */ - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "LDAP add for %s failed with status %d: %s", - ou, rcmod, ldap_err2string(rcmod)); - if (rcmod == LDAP_SERVER_DOWN) - ldap_reconnect(); - } - } - - if (rc == LDAP_SUCCESS) - ldap_freeres(res); -} - - -/* - * 'send_ldap_browse()' - Send LDAP printer registrations. - */ - -static void -send_ldap_browse(cupsd_printer_t *p) /* I - Printer to register */ -{ - int i; /* Looping var... */ - LDAPMod mods[7]; /* The 7 attributes we will be adding */ - LDAPMod *pmods[8]; /* Pointers to the 7 attributes + NULL */ - LDAPMessage *res, /* Search result token */ - *e; /* Current entry from search */ - char *cn_value[2], /* Change records */ - *uri[2], - *info[2], - *location[2], - *make_model[2], - *type[2], - typestring[255], /* String to hold printer-type */ - dn[1024]; /* DN of the printer we are adding */ - int rc; /* LDAP status */ - int rcmod; /* LDAP status for modifications */ - char old_uri[HTTP_MAX_URI], /* Printer URI */ - old_location[1024], /* Printer location */ - old_info[1024], /* Printer information */ - old_make_model[1024], /* Printer make and model */ - old_type_string[30]; /* Temporary type number */ - int old_type; /* Printer type */ - static const char * const objectClass_values[] = - { /* The 3 objectClass's we use in */ - "top", /* our LDAP entries */ - "device", - "cupsPrinter", - NULL - }; - - - cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_ldap_browse: %s", p->name); - - /* - * Exit function if LDAP updates has been disabled... - */ - - if (!BrowseLDAPUpdate) - { - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "send_ldap_browse: Updates temporary disabled; " - "skipping..."); - return; - } - - /* - * Reconnect if LDAP Handle is invalid... - */ - - if (!BrowseLDAPHandle) - { - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "send_ldap_browse: LDAP Handle is invalid. Try " - "reconnecting..."); - ldap_reconnect(); - return; - } - - /* - * Everything in ldap is ** so we fudge around it... - */ - - sprintf(typestring, "%u", p->type); - - cn_value[0] = p->name; - cn_value[1] = NULL; - info[0] = p->info ? p->info : "Unknown"; - info[1] = NULL; - location[0] = p->location ? p->location : "Unknown"; - location[1] = NULL; - make_model[0] = p->make_model ? p->make_model : "Unknown"; - make_model[1] = NULL; - type[0] = typestring; - type[1] = NULL; - uri[0] = p->uri; - uri[1] = NULL; - - /* - * Get ldap entry for printer ... - */ - - snprintf(dn, sizeof(dn), "cn=%s, ou=%s, %s", p->name, ServerName, - BrowseLDAPDN); - cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_ldap_browse: dn=\"%s\"", dn); - - rc = ldap_search_rec(BrowseLDAPHandle, dn, LDAP_SCOPE_BASE, NULL, - (char **)ldap_attrs, 0, &res); - - /* - * If ldap search was not successfull then exit function - * and temporary disable LDAP updates... - */ - - if (rc != LDAP_SUCCESS && rc != LDAP_NO_SUCH_OBJECT) - { - if (BrowseLDAPUpdate && - (rc == LDAP_SERVER_DOWN || rc == LDAP_CONNECT_ERROR)) - { - BrowseLDAPUpdate = FALSE; - cupsdLogMessage(CUPSD_LOG_INFO, - "LDAP update temporary disabled"); - } - - return; - } - - /* - * Fill modification array... - */ - - mods[0].mod_type = "cn"; - mods[0].mod_values = cn_value; - mods[1].mod_type = "printerDescription"; - mods[1].mod_values = info; - mods[2].mod_type = "printerURI"; - mods[2].mod_values = uri; - mods[3].mod_type = "printerLocation"; - mods[3].mod_values = location; - mods[4].mod_type = "printerMakeAndModel"; - mods[4].mod_values = make_model; - mods[5].mod_type = "printerType"; - mods[5].mod_values = type; - mods[6].mod_type = "objectClass"; - mods[6].mod_values = (char **)objectClass_values; - - /* - * Check if we need to insert or update the LDAP entry... - */ - - if (ldap_count_entries(BrowseLDAPHandle, res) > 0 && - rc != LDAP_NO_SUCH_OBJECT) - { - /* - * Printer has already been registered, check if - * modification is required... - */ - - e = ldap_first_entry(BrowseLDAPHandle, res); - - /* - * Get the required values from this entry... - */ - - if (ldap_getval_firststring(BrowseLDAPHandle, e, "printerDescription", - old_info, sizeof(old_info)) == -1) - old_info[0] = '\0'; - - if (ldap_getval_firststring(BrowseLDAPHandle, e, "printerLocation", - old_location, sizeof(old_location)) == -1) - old_info[0] = '\0'; - - if (ldap_getval_firststring(BrowseLDAPHandle, e, "printerMakeAndModel", - old_make_model, sizeof(old_make_model)) == -1) - old_info[0] = '\0'; - - if (ldap_getval_firststring(BrowseLDAPHandle, e, "printerType", - old_type_string, sizeof(old_type_string)) == -1) - old_info[0] = '\0'; - - old_type = atoi(old_type_string); - - if (ldap_getval_firststring(BrowseLDAPHandle, e, "printerURI", old_uri, - sizeof(old_uri)) == -1) - old_info[0] = '\0'; - - /* - * Check if modification is required... - */ - - if (!strcmp(info[0], old_info) && !strcmp(uri[0], old_uri) && - !strcmp(location[0], old_location) && - !strcmp(make_model[0], old_make_model) && p->type == old_type) - { - /* - * LDAP entry for the printer exists. Printer has already been registered, - * no modifications required... - */ - - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "send_ldap_browse: No updates required for %s", p->name); - } - else - { - /* - * LDAP entry for the printer exists. Printer has already been registered, - * modify the current registration... - */ - - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "send_ldap_browse: Replace entry for %s", p->name); - - for (i = 0; i < 7; i ++) - { - pmods[i] = mods + i; - pmods[i]->mod_op = LDAP_MOD_REPLACE; - } - pmods[i] = NULL; - -# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 - if ((rcmod = ldap_modify_ext_s(BrowseLDAPHandle, dn, pmods, NULL, - NULL)) != LDAP_SUCCESS) -# else - if ((rcmod = ldap_modify_s(BrowseLDAPHandle, dn, pmods)) != LDAP_SUCCESS) -# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */ - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "LDAP modify for %s failed with status %d: %s", - p->name, rcmod, ldap_err2string(rcmod)); - if (rcmod == LDAP_SERVER_DOWN) - ldap_reconnect(); - } - } - } - else - { - /* - * No LDAP entry exists for the printer. Printer has never been registered, - * add the current registration... - */ - - send_ldap_ou(ServerName, BrowseLDAPDN, "CUPS Server"); - - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "send_ldap_browse: Add entry for %s", p->name); - - for (i = 0; i < 7; i ++) - { - pmods[i] = mods + i; - pmods[i]->mod_op = LDAP_MOD_ADD; - } - pmods[i] = NULL; - -# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 - if ((rcmod = ldap_add_ext_s(BrowseLDAPHandle, dn, pmods, NULL, - NULL)) != LDAP_SUCCESS) -# else - if ((rcmod = ldap_add_s(BrowseLDAPHandle, dn, pmods)) != LDAP_SUCCESS) -# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */ - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "LDAP add for %s failed with status %d: %s", - p->name, rcmod, ldap_err2string(rcmod)); - if (rcmod == LDAP_SERVER_DOWN) - ldap_reconnect(); - } - } - - if (rc == LDAP_SUCCESS) - ldap_freeres(res); -} - - -/* - * 'ldap_dereg_printer()' - Delete printer from directory - */ - -static void -ldap_dereg_printer(cupsd_printer_t *p) /* I - Printer to deregister */ -{ - char dn[1024]; /* DN of the printer */ - int rc; /* LDAP status */ - - - cupsdLogMessage(CUPSD_LOG_DEBUG2, "ldap_dereg_printer: Remove entry for %s", - p->name); - - /* - * Reconnect if LDAP Handle is invalid... - */ - - if (!BrowseLDAPHandle) - { - ldap_reconnect(); - return; - } - - /* - * Get dn for printer and delete LDAP entry... - */ - - snprintf(dn, sizeof(dn), "cn=%s, ou=%s, %s", p->name, ServerName, - BrowseLDAPDN); - cupsdLogMessage(CUPSD_LOG_DEBUG2, "ldap_dereg_printer: dn=\"%s\"", dn); - -# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 - if ((rc = ldap_delete_ext_s(BrowseLDAPHandle, dn, NULL, - NULL)) != LDAP_SUCCESS) -# else - if ((rc = ldap_delete_s(BrowseLDAPHandle, dn)) != LDAP_SUCCESS) -# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */ - { - cupsdLogMessage(CUPSD_LOG_WARN, - "LDAP delete for %s failed with status %d: %s", - p->name, rc, ldap_err2string(rc)); - - /* - * If we had a connection problem (connection timed out, etc.) - * we should reconnect and try again to delete the entry... - */ - - if (rc == LDAP_SERVER_DOWN || rc == LDAP_CONNECT_ERROR) - { - cupsdLogMessage(CUPSD_LOG_INFO, - "Retry deleting LDAP entry for %s after a reconnect...", p->name); - ldap_reconnect(); - -# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 - if ((rc = ldap_delete_ext_s(BrowseLDAPHandle, dn, NULL, - NULL)) != LDAP_SUCCESS) -# else - if ((rc = ldap_delete_s(BrowseLDAPHandle, dn)) != LDAP_SUCCESS) -# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */ - cupsdLogMessage(CUPSD_LOG_WARN, - "LDAP delete for %s failed with status %d: %s", - p->name, rc, ldap_err2string(rc)); - } - } -} - - -/* - * 'ldap_dereg_ou()' - Remove the organizational unit. - */ - -static void -ldap_dereg_ou(char *ou, /* I - Organizational unit (servername) */ - char *basedn) /* I - Dase dn */ -{ - char dn[1024]; /* DN of the printer */ - int rc; /* LDAP status */ - - - cupsdLogMessage(CUPSD_LOG_DEBUG2, "ldap_dereg_ou: Remove entry for %s", ou); - - /* - * Reconnect if LDAP Handle is invalid... - */ - - if (!BrowseLDAPHandle) - { - ldap_reconnect(); - return; - } - - /* - * Get dn for printer and delete LDAP entry... - */ - - snprintf(dn, sizeof(dn), "ou=%s, %s", ou, basedn); - cupsdLogMessage(CUPSD_LOG_DEBUG2, "ldap_dereg_ou: dn=\"%s\"", dn); - -# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 - if ((rc = ldap_delete_ext_s(BrowseLDAPHandle, dn, NULL, - NULL)) != LDAP_SUCCESS) -# else - if ((rc = ldap_delete_s(BrowseLDAPHandle, dn)) != LDAP_SUCCESS) -# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */ - { - cupsdLogMessage(CUPSD_LOG_WARN, - "LDAP delete for %s failed with status %d: %s", - ou, rc, ldap_err2string(rc)); - - /* - * If we had a connection problem (connection timed out, etc.) - * we should reconnect and try again to delete the entry... - */ - - if (rc == LDAP_SERVER_DOWN || rc == LDAP_CONNECT_ERROR) - { - cupsdLogMessage(CUPSD_LOG_INFO, - "Retry deleting LDAP entry for %s after a reconnect...", ou); - ldap_reconnect(); -# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 - if ((rc = ldap_delete_ext_s(BrowseLDAPHandle, dn, NULL, - NULL)) != LDAP_SUCCESS) -# else - if ((rc = ldap_delete_s(BrowseLDAPHandle, dn)) != LDAP_SUCCESS) -# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */ - cupsdLogMessage(CUPSD_LOG_WARN, - "LDAP delete for %s failed with status %d: %s", - ou, rc, ldap_err2string(rc)); - } - } -} -#endif /* HAVE_LDAP */ - - -#ifdef HAVE_LIBSLP -/* - * 'send_slp_browse()' - Register the specified printer with SLP. - */ - -static void -send_slp_browse(cupsd_printer_t *p) /* I - Printer to register */ -{ - char srvurl[HTTP_MAX_URI], /* Printer service URI */ - attrs[8192], /* Printer attributes */ - finishings[1024], /* Finishings to support */ - make_model[IPP_MAX_NAME * 2], - /* Make and model, quoted */ - location[IPP_MAX_NAME * 2], - /* Location, quoted */ - info[IPP_MAX_NAME * 2], /* Info, quoted */ - *src, /* Pointer to original string */ - *dst; /* Pointer to destination string */ - ipp_attribute_t *authentication; /* uri-authentication-supported value */ - SLPError error; /* SLP error, if any */ - - - cupsdLogMessage(CUPSD_LOG_DEBUG, "send_slp_browse(%p = \"%s\")", p, - p->name); - - /* - * Make the SLP service URL that conforms to the IANA - * 'printer:' template. - */ - - snprintf(srvurl, sizeof(srvurl), SLP_CUPS_SRVTYPE ":%s", p->uri); - - cupsdLogMessage(CUPSD_LOG_DEBUG2, "Service URL = \"%s\"", srvurl); - - /* - * Figure out the finishings string... - */ - - if (p->type & CUPS_PRINTER_STAPLE) - strcpy(finishings, "staple"); - else - finishings[0] = '\0'; - - if (p->type & CUPS_PRINTER_BIND) - { - if (finishings[0]) - strlcat(finishings, ",bind", sizeof(finishings)); - else - strcpy(finishings, "bind"); - } - - if (p->type & CUPS_PRINTER_PUNCH) - { - if (finishings[0]) - strlcat(finishings, ",punch", sizeof(finishings)); - else - strcpy(finishings, "punch"); - } - - if (p->type & CUPS_PRINTER_COVER) - { - if (finishings[0]) - strlcat(finishings, ",cover", sizeof(finishings)); - else - strcpy(finishings, "cover"); - } - - if (p->type & CUPS_PRINTER_SORT) - { - if (finishings[0]) - strlcat(finishings, ",sort", sizeof(finishings)); - else - strcpy(finishings, "sort"); - } - - if (!finishings[0]) - strcpy(finishings, "none"); - - /* - * Quote any commas in the make and model, location, and info strings... - */ - - for (src = p->make_model, dst = make_model; - src && *src && dst < (make_model + sizeof(make_model) - 2);) - { - if (*src == ',' || *src == '\\' || *src == ')') - *dst++ = '\\'; - - *dst++ = *src++; - } - - *dst = '\0'; - - if (!make_model[0]) - strcpy(make_model, "Unknown"); - - for (src = p->location, dst = location; - src && *src && dst < (location + sizeof(location) - 2);) - { - if (*src == ',' || *src == '\\' || *src == ')') - *dst++ = '\\'; - - *dst++ = *src++; - } - - *dst = '\0'; - - if (!location[0]) - strcpy(location, "Unknown"); - - for (src = p->info, dst = info; - src && *src && dst < (info + sizeof(info) - 2);) - { - if (*src == ',' || *src == '\\' || *src == ')') - *dst++ = '\\'; - - *dst++ = *src++; - } - - *dst = '\0'; - - if (!info[0]) - strcpy(info, "Unknown"); - - /* - * Get the authentication value... - */ - - authentication = ippFindAttribute(p->attrs, "uri-authentication-supported", - IPP_TAG_KEYWORD); - - /* - * Make the SLP attribute string list that conforms to - * the IANA 'printer:' template. - */ - - snprintf(attrs, sizeof(attrs), - "(printer-uri-supported=%s)," - "(uri-authentication-supported=%s>)," -#ifdef HAVE_SSL - "(uri-security-supported=tls>)," -#else - "(uri-security-supported=none>)," -#endif /* HAVE_SSL */ - "(printer-name=%s)," - "(printer-location=%s)," - "(printer-info=%s)," - "(printer-more-info=%s)," - "(printer-make-and-model=%s)," - "(printer-type=%d)," - "(charset-supported=utf-8)," - "(natural-language-configured=%s)," - "(natural-language-supported=de,en,es,fr,it)," - "(color-supported=%s)," - "(finishings-supported=%s)," - "(sides-supported=one-sided%s)," - "(multiple-document-jobs-supported=true)" - "(ipp-versions-supported=1.0,1.1)", - p->uri, authentication->values[0].string.text, p->name, location, - info, p->uri, make_model, p->type, DefaultLanguage, - p->type & CUPS_PRINTER_COLOR ? "true" : "false", - finishings, - p->type & CUPS_PRINTER_DUPLEX ? - ",two-sided-long-edge,two-sided-short-edge" : ""); - - cupsdLogMessage(CUPSD_LOG_DEBUG2, "Attributes = \"%s\"", attrs); - - /* - * Register the printer with the SLP server... - */ - - error = SLPReg(BrowseSLPHandle, srvurl, BrowseTimeout, - SLP_CUPS_SRVTYPE, attrs, SLP_TRUE, slp_reg_callback, 0); - - if (error != SLP_OK) - cupsdLogMessage(CUPSD_LOG_ERROR, "SLPReg of \"%s\" failed with status %d!", p->name, - error); -} - - -/* - * 'slp_attr_callback()' - SLP attribute callback - */ - -static SLPBoolean /* O - SLP_TRUE for success */ -slp_attr_callback( - SLPHandle hslp, /* I - SLP handle */ - const char *attrlist, /* I - Attribute list */ - SLPError errcode, /* I - Parsing status for this attr */ - void *cookie) /* I - Current printer */ -{ - char *tmp = 0; /* Temporary string */ - cupsd_printer_t *p = (cupsd_printer_t*)cookie; - /* Current printer */ - - - (void)hslp; /* anti-compiler-warning-code */ - - /* - * Bail if there was an error - */ - - if (errcode != SLP_OK) - return (SLP_TRUE); - - /* - * Parse the attrlist to obtain things needed to build CUPS browse packet - */ - - memset(p, 0, sizeof(cupsd_printer_t)); - - if (slp_get_attr(attrlist, "(printer-location=", &(p->location))) - return (SLP_FALSE); - if (slp_get_attr(attrlist, "(printer-info=", &(p->info))) - return (SLP_FALSE); - if (slp_get_attr(attrlist, "(printer-make-and-model=", &(p->make_model))) - return (SLP_FALSE); - if (!slp_get_attr(attrlist, "(printer-type=", &tmp)) - p->type = atoi(tmp); - else - p->type = CUPS_PRINTER_REMOTE; - - cupsdClearString(&tmp); - - return (SLP_TRUE); -} - - -/* - * 'slp_dereg_printer()' - SLPDereg() the specified printer - */ - -static void -slp_dereg_printer(cupsd_printer_t *p) /* I - Printer */ -{ - char srvurl[HTTP_MAX_URI]; /* Printer service URI */ - - - cupsdLogMessage(CUPSD_LOG_DEBUG, "slp_dereg_printer: printer=\"%s\"", p->name); - - if (!(p->type & CUPS_PRINTER_REMOTE)) - { - /* - * Make the SLP service URL that conforms to the IANA - * 'printer:' template. - */ - - snprintf(srvurl, sizeof(srvurl), SLP_CUPS_SRVTYPE ":%s", p->uri); - - /* - * Deregister the printer... - */ - - SLPDereg(BrowseSLPHandle, srvurl, slp_reg_callback, 0); - } -} - - -/* - * 'slp_get_attr()' - Get an attribute from an SLP registration. - */ - -static int /* O - 0 on success */ -slp_get_attr(const char *attrlist, /* I - Attribute list string */ - const char *tag, /* I - Name of attribute */ - char **valbuf) /* O - Value */ -{ - char *ptr1, /* Pointer into string */ - *ptr2; /* ... */ - - - cupsdClearString(valbuf); - - if ((ptr1 = strstr(attrlist, tag)) != NULL) - { - ptr1 += strlen(tag); - - if ((ptr2 = strchr(ptr1,')')) != NULL) - { - /* - * Copy the value... - */ - - *valbuf = calloc(ptr2 - ptr1 + 1, 1); - strncpy(*valbuf, ptr1, ptr2 - ptr1); - - /* - * Dequote the value... - */ - - for (ptr1 = *valbuf; *ptr1; ptr1 ++) - if (*ptr1 == '\\' && ptr1[1]) - _cups_strcpy(ptr1, ptr1 + 1); - - return (0); - } - } - - return (-1); -} - - -/* - * 'slp_reg_callback()' - Empty SLPRegReport. - */ - -static void -slp_reg_callback(SLPHandle hslp, /* I - SLP handle */ - SLPError errcode, /* I - Error code, if any */ - void *cookie) /* I - App data */ -{ - (void)hslp; - (void)errcode; - (void)cookie; - - return; -} - - -/* - * 'slp_url_callback()' - SLP service url callback - */ - -static SLPBoolean /* O - TRUE = OK, FALSE = error */ -slp_url_callback( - SLPHandle hslp, /* I - SLP handle */ - const char *srvurl, /* I - URL of service */ - unsigned short lifetime, /* I - Life of service */ - SLPError errcode, /* I - Existing error code */ - void *cookie) /* I - Pointer to service list */ -{ - slpsrvurl_t *s, /* New service entry */ - **head; /* Pointer to head of entry */ - - - /* - * Let the compiler know we won't be using these vars... - */ - - (void)hslp; - (void)lifetime; - - /* - * Bail if there was an error - */ - - if (errcode != SLP_OK) - return (SLP_TRUE); - - /* - * Grab the head of the list... - */ - - head = (slpsrvurl_t**)cookie; - - /* - * Allocate a *temporary* slpsrvurl_t to hold this entry. - */ - - if ((s = (slpsrvurl_t *)calloc(1, sizeof(slpsrvurl_t))) == NULL) - return (SLP_FALSE); - - /* - * Copy the SLP service URL... - */ - - strlcpy(s->url, srvurl, sizeof(s->url)); - - /* - * Link the SLP service URL into the head of the list - */ - - if (*head) - s->next = *head; - - *head = s; - - return (SLP_TRUE); -} -#endif /* HAVE_LIBSLP */ - - -/* - * 'update_cups_browse()' - Update the browse lists using the CUPS protocol. - */ - -static void -update_cups_browse(void) -{ - int i; /* Looping var */ - int auth; /* Authorization status */ - int len; /* Length of name string */ - int bytes; /* Number of bytes left */ - char packet[1541], /* Broadcast packet */ - *pptr; /* Pointer into packet */ - socklen_t srclen; /* Length of source address */ - http_addr_t srcaddr; /* Source address */ - char srcname[1024]; /* Source hostname */ - unsigned address[4]; /* Source address */ - unsigned type; /* Printer type */ - unsigned state; /* Printer state */ - char uri[HTTP_MAX_URI], /* Printer URI */ - host[HTTP_MAX_URI], /* Host portion of URI */ - resource[HTTP_MAX_URI], /* Resource portion of URI */ - info[IPP_MAX_NAME], /* Information string */ - location[IPP_MAX_NAME], /* Location string */ - make_model[IPP_MAX_NAME];/* Make and model string */ - int num_attrs; /* Number of attributes */ - cups_option_t *attrs; /* Attributes */ - - - /* - * Read a packet from the browse socket... - */ - - srclen = sizeof(srcaddr); - if ((bytes = recvfrom(BrowseSocket, packet, sizeof(packet) - 1, 0, - (struct sockaddr *)&srcaddr, &srclen)) < 0) - { - /* - * "Connection refused" is returned under Linux if the destination port - * or address is unreachable from a previous sendto(); check for the - * error here and ignore it for now... - */ - - if (errno != ECONNREFUSED && errno != EAGAIN) - { - cupsdLogMessage(CUPSD_LOG_ERROR, "Browse recv failed - %s.", - strerror(errno)); - cupsdLogMessage(CUPSD_LOG_ERROR, "CUPS browsing turned off."); - -#ifdef WIN32 - closesocket(BrowseSocket); -#else - close(BrowseSocket); -#endif /* WIN32 */ - - cupsdRemoveSelect(BrowseSocket); - BrowseSocket = -1; - - BrowseLocalProtocols &= ~BROWSE_CUPS; - BrowseRemoteProtocols &= ~BROWSE_CUPS; - } - - return; - } - - packet[bytes] = '\0'; - - /* - * If we're about to sleep, ignore incoming browse packets. - */ - - if (Sleeping) - return; - - /* - * Figure out where it came from... - */ - -#ifdef AF_INET6 - if (srcaddr.addr.sa_family == AF_INET6) - { - address[0] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[0]); - address[1] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[1]); - address[2] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[2]); - address[3] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[3]); - } - else -#endif /* AF_INET6 */ - { - address[0] = 0; - address[1] = 0; - address[2] = 0; - address[3] = ntohl(srcaddr.ipv4.sin_addr.s_addr); - } - - if (HostNameLookups) - httpAddrLookup(&srcaddr, srcname, sizeof(srcname)); - else - httpAddrString(&srcaddr, srcname, sizeof(srcname)); - - len = strlen(srcname); - - /* - * Do ACL stuff... - */ - - if (BrowseACL) - { - if (httpAddrLocalhost(&srcaddr) || !_cups_strcasecmp(srcname, "localhost")) - { - /* - * Access from localhost (127.0.0.1) is always allowed... - */ - - auth = CUPSD_AUTH_ALLOW; - } - else - { - /* - * Do authorization checks on the domain/address... - */ - - switch (BrowseACL->order_type) - { - default : - auth = CUPSD_AUTH_DENY; /* anti-compiler-warning-code */ - break; - - case CUPSD_AUTH_ALLOW : /* Order Deny,Allow */ - auth = CUPSD_AUTH_ALLOW; - - if (cupsdCheckAuth(address, srcname, len, BrowseACL->deny)) - auth = CUPSD_AUTH_DENY; - - if (cupsdCheckAuth(address, srcname, len, BrowseACL->allow)) - auth = CUPSD_AUTH_ALLOW; - break; - - case CUPSD_AUTH_DENY : /* Order Allow,Deny */ - auth = CUPSD_AUTH_DENY; - - if (cupsdCheckAuth(address, srcname, len, BrowseACL->allow)) - auth = CUPSD_AUTH_ALLOW; - - if (cupsdCheckAuth(address, srcname, len, BrowseACL->deny)) - auth = CUPSD_AUTH_DENY; - break; - } - } - } - else - auth = CUPSD_AUTH_ALLOW; - - if (auth == CUPSD_AUTH_DENY) - { - cupsdLogMessage(CUPSD_LOG_DEBUG, - "update_cups_browse: Refused %d bytes from %s", bytes, - srcname); - return; - } - - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "update_cups_browse: (%d bytes from %s) %s", bytes, - srcname, packet); - - /* - * Parse packet... - */ - - if (sscanf(packet, "%x%x%1023s", &type, &state, uri) < 3) - { - cupsdLogMessage(CUPSD_LOG_WARN, - "update_cups_browse: Garbled browse packet - %s", packet); - return; - } - - strcpy(location, "Location Unknown"); - strcpy(info, "No Information Available"); - make_model[0] = '\0'; - num_attrs = 0; - attrs = NULL; - - if ((pptr = strchr(packet, '\"')) != NULL) - { - /* - * Have extended information; can't use sscanf for it because not all - * sscanf's allow empty strings with %[^\"]... - */ - - for (i = 0, pptr ++; - i < (sizeof(location) - 1) && *pptr && *pptr != '\"'; - i ++, pptr ++) - location[i] = *pptr; - - if (i) - location[i] = '\0'; - - if (*pptr == '\"') - pptr ++; - - while (*pptr && isspace(*pptr & 255)) - pptr ++; - - if (*pptr == '\"') - { - for (i = 0, pptr ++; - i < (sizeof(info) - 1) && *pptr && *pptr != '\"'; - i ++, pptr ++) - info[i] = *pptr; - - info[i] = '\0'; - - if (*pptr == '\"') - pptr ++; - - while (*pptr && isspace(*pptr & 255)) - pptr ++; - - if (*pptr == '\"') - { - for (i = 0, pptr ++; - i < (sizeof(make_model) - 1) && *pptr && *pptr != '\"'; - i ++, pptr ++) - make_model[i] = *pptr; - - if (*pptr == '\"') - pptr ++; - - make_model[i] = '\0'; - - if (*pptr) - num_attrs = cupsParseOptions(pptr, num_attrs, &attrs); - } - } - } - - DEBUG_puts(packet); - DEBUG_printf(("type=%x, state=%x, uri=\"%s\"\n" - "location=\"%s\", info=\"%s\", make_model=\"%s\"\n", - type, state, uri, location, info, make_model)); - - /* - * Pull the URI apart to see if this is a local or remote printer... - */ - - if (is_local_queue(uri, host, sizeof(host), resource, sizeof(resource))) - { - cupsFreeOptions(num_attrs, attrs); - return; - } - - /* - * Do relaying... - */ - - for (i = 0; i < NumRelays; i ++) - if (cupsdCheckAuth(address, srcname, len, Relays[i].from)) - if (sendto(BrowseSocket, packet, bytes, 0, - (struct sockaddr *)&(Relays[i].to), - httpAddrLength(&(Relays[i].to))) <= 0) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "update_cups_browse: sendto failed for relay %d - %s.", - i + 1, strerror(errno)); - cupsFreeOptions(num_attrs, attrs); - return; - } - - /* - * Process the browse data... - */ - - process_browse_data(uri, host, resource, (cups_ptype_t)type, - (ipp_pstate_t)state, location, info, make_model, - num_attrs, attrs); -} - - -/* * 'update_lpd()' - Update the LPD configuration as needed. */ @@ -5478,41 +1599,6 @@ update_lpd(int onoff) /* - 1 = turn on, 0 = turn off */ /* - * 'update_polling()' - Read status messages from the poll daemons. - */ - -static void -update_polling(void) -{ - char *ptr, /* Pointer to end of line in buffer */ - message[1024]; /* Pointer to message text */ - int loglevel; /* Log level for message */ - - - while ((ptr = cupsdStatBufUpdate(PollStatusBuffer, &loglevel, - message, sizeof(message))) != NULL) - { - if (loglevel == CUPSD_LOG_INFO) - cupsdLogMessage(CUPSD_LOG_INFO, "%s", message); - - if (!strchr(PollStatusBuffer->buffer, '\n')) - break; - } - - if (ptr == NULL && !PollStatusBuffer->bufused) - { - /* - * All polling processes have died; stop polling... - */ - - cupsdLogMessage(CUPSD_LOG_ERROR, - "update_polling: all polling processes have exited!"); - cupsdStopPolling(); - } -} - - -/* * 'update_smb()' - Update the SMB configuration as needed. */ @@ -5580,5 +1666,5 @@ update_smb(int onoff) /* I - 1 = turn on, 0 = turn off */ /* - * End of "$Id: dirsvc.c 10243 2012-02-11 02:05:21Z mike $". + * End of "$Id: dirsvc.c 11173 2013-07-23 12:31:34Z msweet $". */ diff --git a/scheduler/dirsvc.h b/scheduler/dirsvc.h index be8774b..edc5ad3 100644 --- a/scheduler/dirsvc.h +++ b/scheduler/dirsvc.h @@ -1,9 +1,9 @@ /* - * "$Id: dirsvc.h 9632 2011-03-21 02:12:14Z mike $" + * "$Id: dirsvc.h 11173 2013-07-23 12:31:34Z msweet $" * * Directory services definitions for the CUPS scheduler. * - * Copyright 2007-2010 by Apple Inc. + * Copyright 2007-2012 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -14,68 +14,13 @@ */ /* - * Include necessary headers... - */ - -#ifdef HAVE_LIBSLP -# include <slp.h> -#endif /* HAVE_LIBSLP */ - -#ifdef HAVE_LDAP -# ifdef __sun -# include <lber.h> -# endif /* __sun */ -# include <ldap.h> -# ifdef HAVE_LDAP_SSL_H -# include <ldap_ssl.h> -# endif /* HAVE_LDAP_SSL_H */ -#endif /* HAVE_LDAP */ - -/* * Browse protocols... */ -#define BROWSE_CUPS 1 /* CUPS */ -#define BROWSE_SLP 2 /* SLPv2 */ -#define BROWSE_LDAP 4 /* LDAP */ -#define BROWSE_DNSSD 8 /* DNS Service Discovery (aka Bonjour) */ -#define BROWSE_SMB 16 /* SMB/Samba */ -#define BROWSE_LPD 32 /* LPD via xinetd or launchd */ -#define BROWSE_ALL 63 /* All protocols */ - - -/* - * Browse address... - */ - -typedef struct -{ - char iface[32]; /* Destination interface */ - http_addr_t to; /* Destination address */ -} cupsd_dirsvc_addr_t; - - -/* - * Relay structure... - */ - -typedef struct -{ - cups_array_t *from; /* Source address/name mask(s) */ - http_addr_t to; /* Destination address */ -} cupsd_dirsvc_relay_t; - - -/* - * Polling structure... - */ - -typedef struct -{ - char hostname[64]; /* Hostname (actually, IP address) */ - int port; /* Port number */ - int pid; /* Current poll server PID */ -} cupsd_dirsvc_poll_t; +#define BROWSE_DNSSD 1 /* DNS Service Discovery (aka Bonjour) */ +#define BROWSE_SMB 2 /* SMB/Samba */ +#define BROWSE_LPD 4 /* LPD via xinetd or launchd */ +#define BROWSE_ALL 7 /* All protocols */ /* @@ -87,98 +32,34 @@ VAR int Browsing VALUE(TRUE), BrowseWebIF VALUE(FALSE), /* Whether the web interface is advertised */ BrowseLocalProtocols - VALUE(BROWSE_ALL), + VALUE(BROWSE_ALL); /* Protocols to support for local printers */ - BrowseRemoteProtocols - VALUE(BROWSE_ALL), - /* Protocols to support for remote printers */ - BrowseShortNames VALUE(TRUE), - /* Short names for remote printers? */ - BrowseSocket VALUE(-1), - /* Socket for browsing */ - BrowsePort VALUE(IPP_PORT), - /* Port number for broadcasts */ - BrowseInterval VALUE(DEFAULT_INTERVAL), - /* Broadcast interval in seconds */ - BrowseTimeout VALUE(DEFAULT_TIMEOUT), - /* Time out for printers in seconds */ - UseNetworkDefault VALUE(CUPS_DEFAULT_USE_NETWORK_DEFAULT), - /* Use the network default printer? */ - NumBrowsers VALUE(0); - /* Number of broadcast addresses */ -VAR char *BrowseLocalOptions - VALUE(NULL), - /* Options to add to local printer URIs */ - *BrowseRemoteOptions - VALUE(NULL); - /* Options to add to remote printer URIs */ -VAR cupsd_dirsvc_addr_t *Browsers VALUE(NULL); - /* Broadcast addresses */ -VAR cupsd_location_t *BrowseACL VALUE(NULL); - /* Browser access control list */ -VAR cupsd_printer_t *BrowseNext VALUE(NULL); - /* Next class/printer to broadcast */ -VAR int NumRelays VALUE(0); - /* Number of broadcast relays */ -VAR cupsd_dirsvc_relay_t *Relays VALUE(NULL); - /* Broadcast relays */ -VAR int NumPolled VALUE(0); - /* Number of polled servers */ -VAR cupsd_dirsvc_poll_t *Polled VALUE(NULL); - /* Polled servers */ -VAR int PollPipe VALUE(0); - /* Status pipe for pollers */ -VAR cupsd_statbuf_t *PollStatusBuffer VALUE(NULL); - /* Status buffer for pollers */ - -#ifdef HAVE_DNSSD +#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) VAR char *DNSSDComputerName VALUE(NULL), /* Computer/server name */ *DNSSDHostName VALUE(NULL), /* Hostname */ - *DNSSDRegType VALUE(NULL); - /* Bonjour registration type */ + *DNSSDSubTypes VALUE(NULL); + /* Bonjour registration subtypes */ VAR cups_array_t *DNSSDAlias VALUE(NULL); /* List of dynamic ServerAlias's */ VAR int DNSSDPort VALUE(0); /* Port number to register */ VAR cups_array_t *DNSSDPrinters VALUE(NULL); /* Printers we have registered */ -VAR DNSServiceRef DNSSDRef VALUE(NULL), +# ifdef HAVE_DNSSD +VAR DNSServiceRef DNSSDMaster VALUE(NULL); /* Master DNS-SD service reference */ - WebIFRef VALUE(NULL), +# else /* HAVE_AVAHI */ +VAR AvahiThreadedPoll *DNSSDMaster VALUE(NULL); + /* Master polling interface for Avahi */ +VAR AvahiClient *DNSSDClient VALUE(NULL); + /* Client information */ +# endif /* HAVE_DNSSD */ +VAR cupsd_srv_t WebIFSrv VALUE(NULL); /* Service reference for the web interface */ - RemoteRef VALUE(NULL); - /* Remote printer browse reference */ -#endif /* HAVE_DNSSD */ - -#ifdef HAVE_LIBSLP -VAR SLPHandle BrowseSLPHandle VALUE(NULL); - /* SLP API handle */ -VAR time_t BrowseSLPRefresh VALUE(0); - /* Next SLP refresh time */ -#endif /* HAVE_LIBSLP */ +#endif /* HAVE_DNSSD || HAVE_AVAHI */ -#ifdef HAVE_LDAP -VAR LDAP *BrowseLDAPHandle VALUE(NULL); - /* Handle to LDAP server */ -VAR time_t BrowseLDAPRefresh VALUE(0); - /* Next LDAP refresh time */ -VAR char *BrowseLDAPBindDN VALUE(NULL), - /* LDAP login DN */ - *BrowseLDAPDN VALUE(NULL), - /* LDAP search DN */ - *BrowseLDAPPassword VALUE(NULL), - /* LDAP login password */ - *BrowseLDAPServer VALUE(NULL); - /* LDAP server to use */ -VAR int BrowseLDAPUpdate VALUE(TRUE); - /* enables LDAP updates */ -# ifdef HAVE_LDAP_SSL -VAR char *BrowseLDAPCACertFile VALUE(NULL); - /* LDAP CA CERT file to use */ -# endif /* HAVE_LDAP_SSL */ -#endif /* HAVE_LDAP */ VAR char *LPDConfigFile VALUE(NULL), /* LPD configuration file */ *SMBConfigFile VALUE(NULL); @@ -190,24 +71,14 @@ VAR char *LPDConfigFile VALUE(NULL), */ extern void cupsdDeregisterPrinter(cupsd_printer_t *p, int removeit); -extern void cupsdLoadRemoteCache(void); extern void cupsdRegisterPrinter(cupsd_printer_t *p); -extern void cupsdRestartPolling(void); -extern void cupsdSaveRemoteCache(void); -extern void cupsdSendBrowseList(void); extern void cupsdStartBrowsing(void); -extern void cupsdStartPolling(void); extern void cupsdStopBrowsing(void); -extern void cupsdStopPolling(void); -#ifdef HAVE_DNSSD +#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) extern void cupsdUpdateDNSSDName(void); -#endif /* HAVE_DNSSD */ -#ifdef HAVE_LDAP -extern void cupsdUpdateLDAPBrowse(void); -#endif /* HAVE_LDAP */ -extern void cupsdUpdateSLPBrowse(void); +#endif /* HAVE_DNSSD || HAVE_AVAHI */ /* - * End of "$Id: dirsvc.h 9632 2011-03-21 02:12:14Z mike $". + * End of "$Id: dirsvc.h 11173 2013-07-23 12:31:34Z msweet $". */ diff --git a/scheduler/env.c b/scheduler/env.c index ec12d15..ba11aad 100644 --- a/scheduler/env.c +++ b/scheduler/env.c @@ -1,5 +1,5 @@ /* - * "$Id: env.c 9459 2011-01-11 03:48:42Z mike $" + * "$Id: env.c 11173 2013-07-23 12:31:34Z msweet $" * * Environment management routines for the CUPS scheduler. * @@ -62,7 +62,7 @@ cupsdInitEnv(void) #if defined(__APPLE__) /* - * Add special voodoo magic for MacOS X - this allows MacOS X + * Add special voodoo magic for MacOS X - this allows MacOS X * programs to access their bundle resources properly... * * This string is replaced in cupsdStartProcess()... @@ -227,6 +227,8 @@ cupsdUpdateEnv(void) set_if_undefined("TZ", NULL); set_if_undefined("USER", "root"); set_if_undefined("VG_ARGS", NULL); + + cupsdSetEnvf("CUPS_MAX_MESSAGE", "%d", CUPSD_SB_BUFFER_SIZE - 1); } @@ -267,5 +269,5 @@ find_env(const char *name) /* I - Variable name */ /* - * End of "$Id: env.c 9459 2011-01-11 03:48:42Z mike $". + * End of "$Id: env.c 11173 2013-07-23 12:31:34Z msweet $". */ diff --git a/scheduler/file.c b/scheduler/file.c index 4dcf54d..84ceef1 100644 --- a/scheduler/file.c +++ b/scheduler/file.c @@ -1,5 +1,5 @@ /* - * "$Id: file.c 9766 2011-05-11 22:17:34Z mike $" + * "$Id: file.c 11221 2013-08-06 16:16:01Z msweet $" * * File functions for the CUPS scheduler. * @@ -109,6 +109,29 @@ cupsdCloseCreatedConfFile( /* + * Synchronize changes to disk if SyncOnClose is enabled. + */ + + if (SyncOnClose) + { + if (cupsFileFlush(fp)) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to write changes to \"%s\": %s", + filename, strerror(errno)); + cupsFileClose(fp); + return (-1); + } + + if (fsync(cupsFileNumber(fp))) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to sync changes to \"%s\": %s", + filename, strerror(errno)); + cupsFileClose(fp); + return (-1); + } + } + + /* * First close the file... */ @@ -446,5 +469,5 @@ overwrite_data(int fd, /* I - File descriptor */ /* - * End of "$Id: file.c 9766 2011-05-11 22:17:34Z mike $". + * End of "$Id: file.c 11221 2013-08-06 16:16:01Z msweet $". */ diff --git a/scheduler/filter.c b/scheduler/filter.c index 5cde777..6979b5c 100644 --- a/scheduler/filter.c +++ b/scheduler/filter.c @@ -1,5 +1,5 @@ /* - * "$Id: filter.c 9705 2011-04-22 04:38:28Z mike $" + * "$Id: filter.c 11173 2013-07-23 12:31:34Z msweet $" * * File type conversion routines for CUPS. * @@ -500,5 +500,5 @@ mime_find_filters( /* - * End of "$Id: filter.c 9705 2011-04-22 04:38:28Z mike $". + * End of "$Id: filter.c 11173 2013-07-23 12:31:34Z msweet $". */ diff --git a/scheduler/ipp.c b/scheduler/ipp.c index fa3d96e..6968cd5 100644 --- a/scheduler/ipp.c +++ b/scheduler/ipp.c @@ -1,9 +1,9 @@ /* - * "$Id: ipp.c 10274 2012-02-13 20:42:51Z mike $" + * "$Id: ipp.c 11173 2013-07-23 12:31:34Z msweet $" * * IPP routines for the CUPS scheduler. * - * Copyright 2007-2011 by Apple Inc. + * Copyright 2007-2013 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * This file contains Kerberos support code, copyright 2006 by @@ -23,8 +23,6 @@ * add_class() - Add a class to the system. * add_file() - Add a file to a job. * add_job() - Add a job to a print queue. - * add_job_state_reasons() - Add the "job-state-reasons" attribute based - * upon the job and printer state... * add_job_subscriptions() - Add any subscriptions for a job. * add_job_uuid() - Add job-uuid attribute to a job. * add_printer() - Add a printer to the system. @@ -32,10 +30,6 @@ * based upon the printer state... * add_queued_job_count() - Add the "queued-job-count" attribute for the * specified printer or class. - * apple_init_profile() - Initialize a color profile. - * apple_register_profiles() - Register color profiles for a printer. - * apple_unregister_profiles() - Remove color profiles for the specified - * printer. * apply_printer_defaults() - Apply printer default options to a job. * authenticate_job() - Set job authentication info. * cancel_all_jobs() - Cancel all or selected print jobs. @@ -45,7 +39,6 @@ * feed URI. * check_quotas() - Check quotas for a printer and user. * close_job() - Close a multi-file job. - * copy_attribute() - Copy a single attribute. * copy_attrs() - Copy attributes from one request to another. * copy_banner() - Copy a banner file to the requests directory * for the specified job. @@ -114,11 +107,9 @@ #include <cups/ppd-private.h> #ifdef __APPLE__ -# include <ApplicationServices/ApplicationServices.h> -# ifdef HAVE_COLORSYNCREGISTERDEVICE +/*# include <ApplicationServices/ApplicationServices.h> extern CFUUIDRef ColorSyncCreateUUIDFromUInt32(unsigned id); -# endif /* HAVE_COLORSYNCREGISTERDEVICE */ -# include <CoreFoundation/CoreFoundation.h> +# include <CoreFoundation/CoreFoundation.h>*/ # ifdef HAVE_MEMBERSHIP_H # include <membership.h> # endif /* HAVE_MEMBERSHIP_H */ @@ -142,25 +133,12 @@ static int add_file(cupsd_client_t *con, cupsd_job_t *job, mime_type_t *filetype, int compression); static cupsd_job_t *add_job(cupsd_client_t *con, cupsd_printer_t *printer, mime_type_t *filetype); -static void add_job_state_reasons(cupsd_client_t *con, cupsd_job_t *job); static void add_job_subscriptions(cupsd_client_t *con, cupsd_job_t *job); static void add_job_uuid(cupsd_job_t *job); static void add_printer(cupsd_client_t *con, ipp_attribute_t *uri); static void add_printer_state_reasons(cupsd_client_t *con, cupsd_printer_t *p); static void add_queued_job_count(cupsd_client_t *con, cupsd_printer_t *p); -#ifdef __APPLE__ -static void apple_init_profile(ppd_file_t *ppd, cups_array_t *languages, -# ifdef HAVE_COLORSYNCREGISTERDEVICE - CFMutableDictionaryRef profile, -# else - CMDeviceProfileInfo *profile, -# endif /* HAVE_COLORSYNCREGISTERDEVICE */ - unsigned id, const char *name, - const char *text, const char *iccfile); -static void apple_register_profiles(cupsd_printer_t *p); -static void apple_unregister_profiles(cupsd_printer_t *p); -#endif /* __APPLE__ */ static void apply_printer_defaults(cupsd_printer_t *printer, cupsd_job_t *job); static void authenticate_job(cupsd_client_t *con, ipp_attribute_t *uri); @@ -169,8 +147,6 @@ static void cancel_job(cupsd_client_t *con, ipp_attribute_t *uri); static void cancel_subscription(cupsd_client_t *con, int id); static int check_rss_recipient(const char *recipient); static int check_quotas(cupsd_client_t *con, cupsd_printer_t *p); -static ipp_attribute_t *copy_attribute(ipp_t *to, ipp_attribute_t *attr, - int quickcopy); static void close_job(cupsd_client_t *con, ipp_attribute_t *uri); static void copy_attrs(ipp_t *to, ipp_t *from, cups_array_t *ra, ipp_tag_t group, int quickcopy, @@ -228,10 +204,7 @@ static void send_http_error(cupsd_client_t *con, http_status_t status, cupsd_printer_t *printer); static void send_ipp_status(cupsd_client_t *con, ipp_status_t status, const char *message, ...) -# ifdef __GNUC__ -__attribute__ ((__format__ (__printf__, 3, 4))) -# endif /* __GNUC__ */ -; + __attribute__((__format__(__printf__, 3, 4))); static void set_default(cupsd_client_t *con, ipp_attribute_t *uri); static void set_job_attrs(cupsd_client_t *con, ipp_attribute_t *uri); static void set_printer_attrs(cupsd_client_t *con, ipp_attribute_t *uri); @@ -853,8 +826,7 @@ cupsdTimeoutJob(cupsd_job_t *job) /* I - Job to timeout */ printer = cupsdFindDest(job->dest); attr = ippFindAttribute(job->attrs, "job-sheets", IPP_TAG_NAME); - if (printer && - !(printer->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)) && + if (printer && !(printer->type & CUPS_PRINTER_REMOTE) && attr && attr->num_values > 1) { /* @@ -969,7 +941,6 @@ add_class(cupsd_client_t *con, /* I - Client connection */ cups_ptype_t dtype; /* Destination type */ ipp_attribute_t *attr; /* Printer attribute */ int modify; /* Non-zero if we just modified */ - char newname[IPP_MAX_NAME]; /* New class name */ int need_restart_job; /* Need to restart job? */ @@ -1023,8 +994,7 @@ add_class(cupsd_client_t *con, /* I - Client connection */ * Class doesn't exist; see if we have a printer of the same name... */ - if ((pclass = cupsdFindPrinter(resource + 9)) != NULL && - !(pclass->type & CUPS_PRINTER_DISCOVERED)) + if ((pclass = cupsdFindPrinter(resource + 9)) != NULL) { /* * Yes, return an error... @@ -1049,56 +1019,6 @@ add_class(cupsd_client_t *con, /* I - Client connection */ pclass = cupsdAddClass(resource + 9); modify = 0; } - else if (pclass->type & CUPS_PRINTER_IMPLICIT) - { - /* - * Check the default policy, then rename the implicit class to "AnyClass" - * or remove it... - */ - - if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK) - { - send_http_error(con, status, NULL); - return; - } - - if (ImplicitAnyClasses) - { - snprintf(newname, sizeof(newname), "Any%s", resource + 9); - cupsdRenamePrinter(pclass, newname); - } - else - cupsdDeletePrinter(pclass, 1); - - /* - * Add the class as a new local class... - */ - - pclass = cupsdAddClass(resource + 9); - modify = 0; - } - else if (pclass->type & CUPS_PRINTER_DISCOVERED) - { - /* - * Check the default policy, then rename the remote class to "Class"... - */ - - if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK) - { - send_http_error(con, status, NULL); - return; - } - - snprintf(newname, sizeof(newname), "%s@%s", resource + 9, pclass->hostname); - cupsdRenamePrinter(pclass, newname); - - /* - * Add the class as a new local class... - */ - - pclass = cupsdAddClass(resource + 9); - modify = 0; - } else if ((status = cupsdCheckPolicy(pclass->op_policy_ptr, con, NULL)) != HTTP_OK) { @@ -1365,6 +1285,21 @@ add_job(cupsd_client_t *con, /* I - Client connection */ ipp_attribute_t *media_col, /* media-col attribute */ *media_margin; /* media-*-margin attribute */ ipp_t *unsup_col; /* media-col in unsupported response */ + static const char * const readonly[] =/* List of read-only attributes */ + { + "job-id", + "job-k-octets", + /*"job-impressions",*/ /* For now we allow this since cupsd can't count */ + "job-impressions-completed", + "job-media-sheets", + "job-media-sheets-completed", + "job-state", + "job-state-message", + "job-state-reasons", + "time-at-completed", + "time-at-creation", + "time-at-processing" + }; cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_job(%p[%d], %p(%s), %p(%s/%s))", @@ -1433,6 +1368,27 @@ add_job(cupsd_client_t *con, /* I - Client connection */ * copies, number-up, and page-ranges... */ + for (i = 0; i < (int)(sizeof(readonly) / sizeof(readonly[0])); i ++) + { + if ((attr = ippFindAttribute(con->request, readonly[i], + IPP_TAG_ZERO)) != NULL) + { + ippDeleteAttribute(con->request, attr); + + if (StrictConformance) + { + send_ipp_status(con, IPP_BAD_REQUEST, + _("The '%s' Job Description attribute cannot be " + "supplied in a job creation request."), readonly[i]); + return (NULL); + } + + cupsdLogMessage(CUPSD_LOG_WARN, + "Unexpected '%s' Job Description attribute in a job " + "creation request.", readonly[i]); + } + } + if (filetype && printer->filetypes && !cupsArrayFind(printer->filetypes, filetype)) { @@ -1618,9 +1574,71 @@ add_job(cupsd_client_t *con, /* I - Client connection */ priority); } - if (!ippFindAttribute(con->request, "job-name", IPP_TAG_NAME)) + if ((attr = ippFindAttribute(con->request, "job-name", IPP_TAG_ZERO)) == NULL) ippAddString(con->request, IPP_TAG_JOB, IPP_TAG_NAME, "job-name", NULL, "Untitled"); + else if ((attr->value_tag != IPP_TAG_NAME && + attr->value_tag != IPP_TAG_NAMELANG) || + attr->num_values != 1) + { + send_ipp_status(con, IPP_ATTRIBUTES, + _("Bad job-name value: Wrong type or count.")); + if ((attr = ippCopyAttribute(con->response, attr, 0)) != NULL) + attr->group_tag = IPP_TAG_UNSUPPORTED_GROUP; + return (NULL); + } + else + { + const char *ptr; /* Pointer into string */ + + for (ptr = attr->values[0].string.text; *ptr; ptr ++) + { + if ((*ptr & 0xe0) == 0xc0) + { + ptr ++; + if ((*ptr & 0xc0) != 0x80) + break; + } + else if ((*ptr & 0xf0) == 0xe0) + { + ptr ++; + if ((*ptr & 0xc0) != 0x80) + break; + ptr ++; + if ((*ptr & 0xc0) != 0x80) + break; + } + else if ((*ptr & 0xf8) == 0xf0) + { + ptr ++; + if ((*ptr & 0xc0) != 0x80) + break; + ptr ++; + if ((*ptr & 0xc0) != 0x80) + break; + ptr ++; + if ((*ptr & 0xc0) != 0x80) + break; + } + else if (*ptr & 0x80) + break; + } + + if (*ptr || (ptr - attr->values[0].string.text) > (IPP_MAX_NAME - 1)) + { + if (*ptr) + send_ipp_status(con, IPP_ATTRIBUTES, + _("Bad job-name value: Bad UTF-8 sequence.")); + else + send_ipp_status(con, IPP_ATTRIBUTES, + _("Bad job-name value: Name too long.")); + + if ((attr = ippCopyAttribute(con->response, attr, 0)) != NULL) + attr->group_tag = IPP_TAG_UNSUPPORTED_GROUP; + + return (NULL); + } + } if ((job = cupsdAddJob(priority, printer->name)) == NULL) { @@ -1630,8 +1648,7 @@ add_job(cupsd_client_t *con, /* I - Client connection */ return (NULL); } - job->dtype = printer->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT | - CUPS_PRINTER_REMOTE); + job->dtype = printer->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_REMOTE); job->attrs = con->request; job->dirty = 1; con->request = ippNewRequest(job->attrs->request.op.operation_id); @@ -1720,10 +1737,10 @@ add_job(cupsd_client_t *con, /* I - Client connection */ { _cupsStrFree(attr->values[i].string.text); attr->values[i].string.text = NULL; - if (attr->values[i].string.charset) + if (attr->values[i].string.language) { - _cupsStrFree(attr->values[i].string.charset); - attr->values[i].string.charset = NULL; + _cupsStrFree(attr->values[i].string.language); + attr->values[i].string.language = NULL; } } @@ -1770,6 +1787,8 @@ add_job(cupsd_client_t *con, /* I - Client connection */ job->state = ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_ENUM, "job-state", IPP_JOB_STOPPED); job->state_value = (ipp_jstate_t)job->state->values[0].integer; + job->reasons = ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_KEYWORD, + "job-state-reasons", NULL, "job-incoming"); job->sheets = ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-media-sheets-completed", 0); ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_URI, "job-printer-uri", NULL, @@ -1803,6 +1822,8 @@ add_job(cupsd_client_t *con, /* I - Client connection */ job->state->values[0].integer = IPP_JOB_HELD; job->state_value = IPP_JOB_HELD; + + ippSetString(job->attrs, &job->reasons, 0, "job-hold-until-specified"); } else if (job->attrs->request.op.operation_id == IPP_CREATE_JOB) { @@ -1814,10 +1835,11 @@ add_job(cupsd_client_t *con, /* I - Client connection */ { job->state->values[0].integer = IPP_JOB_PENDING; job->state_value = IPP_JOB_PENDING; + + ippSetString(job->attrs, &job->reasons, 0, "none"); } - if (!(printer->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)) || - Classification) + if (!(printer->type & CUPS_PRINTER_REMOTE) || Classification) { /* * Add job sheets options... @@ -1950,7 +1972,7 @@ add_job(cupsd_client_t *con, /* I - Client connection */ * See if we need to add the starting sheet... */ - if (!(printer->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT))) + if (!(printer->type & CUPS_PRINTER_REMOTE)) { cupsdLogJob(job, CUPSD_LOG_INFO, "Adding start banner page \"%s\".", attr->values[0].string.text); @@ -1983,7 +2005,8 @@ add_job(cupsd_client_t *con, /* I - Client connection */ ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_ENUM, "job-state", job->state_value); - add_job_state_reasons(con, job); + ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD, "job-state-reasons", + NULL, job->reasons->values[0].string.text); con->response->request.status.status_code = IPP_OK; @@ -2015,76 +2038,6 @@ add_job(cupsd_client_t *con, /* I - Client connection */ /* - * 'add_job_state_reasons()' - Add the "job-state-reasons" attribute based - * upon the job and printer state... - */ - -static void -add_job_state_reasons( - cupsd_client_t *con, /* I - Client connection */ - cupsd_job_t *job) /* I - Job info */ -{ - cupsd_printer_t *dest; /* Destination printer */ - ipp_attribute_t *attr; /* job-hold attribute */ - - cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_job_state_reasons(%p[%d], %d)", - con, con->http.fd, job ? job->id : 0); - - switch (job ? job->state_value : IPP_JOB_CANCELED) - { - case IPP_JOB_PENDING : - dest = cupsdFindDest(job->dest); - - if (dest && dest->state == IPP_PRINTER_STOPPED) - ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD, - "job-state-reasons", NULL, "printer-stopped"); - else - ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD, - "job-state-reasons", NULL, "none"); - break; - - case IPP_JOB_HELD : - if ((attr = ippFindAttribute(job->attrs, "job-hold-until", - IPP_TAG_KEYWORD)) == NULL) - attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_NAME); - - if (!attr || strcmp(attr->values[0].string.text, "no-hold")) - ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD, - "job-state-reasons", NULL, "job-hold-until-specified"); - else - ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD, - "job-state-reasons", NULL, "job-incoming"); - break; - - case IPP_JOB_PROCESSING : - ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD, - "job-state-reasons", NULL, "job-printing"); - break; - - case IPP_JOB_STOPPED : - ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD, - "job-state-reasons", NULL, "job-stopped"); - break; - - case IPP_JOB_CANCELED : - ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD, - "job-state-reasons", NULL, "job-canceled-by-user"); - break; - - case IPP_JOB_ABORTED : - ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD, - "job-state-reasons", NULL, "aborted-by-system"); - break; - - case IPP_JOB_COMPLETED : - ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD, - "job-state-reasons", NULL, "job-completed-successfully"); - break; - } -} - - -/* * 'add_job_subscriptions()' - Add any subscriptions for a job. */ @@ -2302,7 +2255,7 @@ add_job_subscriptions( * Free and remove this attribute... */ - _ippFreeAttr(attr); + ippDeleteAttribute(NULL, attr); if (prev) prev->next = next; @@ -2363,7 +2316,6 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ char srcfile[1024], /* Source Script/PPD file */ dstfile[1024]; /* Destination Script/PPD file */ int modify; /* Non-zero if we are modifying */ - char newname[IPP_MAX_NAME]; /* New printer name */ int changed_driver, /* Changed the PPD/interface script? */ need_restart_job, /* Need to restart job? */ set_device_uri, /* Did we set the device URI? */ @@ -2419,8 +2371,7 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ * Printer doesn't exist; see if we have a class of the same name... */ - if ((printer = cupsdFindClass(resource + 10)) != NULL && - !(printer->type & CUPS_PRINTER_DISCOVERED)) + if ((printer = cupsdFindClass(resource + 10)) != NULL) { /* * Yes, return an error... @@ -2445,58 +2396,6 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ printer = cupsdAddPrinter(resource + 10); modify = 0; } - else if (printer->type & CUPS_PRINTER_IMPLICIT) - { - /* - * Check the default policy, then rename the implicit printer to - * "AnyPrinter" or delete it... - */ - - if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK) - { - send_http_error(con, status, NULL); - return; - } - - if (ImplicitAnyClasses) - { - snprintf(newname, sizeof(newname), "Any%s", resource + 10); - cupsdRenamePrinter(printer, newname); - } - else - cupsdDeletePrinter(printer, 1); - - /* - * Add the printer as a new local printer... - */ - - printer = cupsdAddPrinter(resource + 10); - modify = 0; - } - else if (printer->type & CUPS_PRINTER_DISCOVERED) - { - /* - * Check the default policy, then rename the remote printer to - * "Printer@server"... - */ - - if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK) - { - send_http_error(con, status, NULL); - return; - } - - snprintf(newname, sizeof(newname), "%s@%s", resource + 10, - printer->hostname); - cupsdRenamePrinter(printer, newname); - - /* - * Add the printer as a new local printer... - */ - - printer = cupsdAddPrinter(resource + 10); - modify = 0; - } else if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK) { @@ -2533,6 +2432,21 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ http_uri_status_t uri_status; /* URI separation status */ char old_device_uri[1024]; /* Old device URI */ + static const char * const uri_status_strings[] = + { + "URI too large.", + "Bad arguments to function.", + "Bad resource path.", + "Bad port number.", + "Bad hostname/address.", + "Bad username/password.", + "Bad URI scheme.", + "Bad URI.", + "OK", + "Missing URI scheme.", + "Unknown URI scheme", + "Missing resource path." + }; need_restart_job = 1; @@ -2544,12 +2458,14 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ host, sizeof(host), &port, resource, sizeof(resource)); + cupsdLogMessage(CUPSD_LOG_DEBUG, + "%s device-uri: %s", printer->name, + uri_status_strings[uri_status - HTTP_URI_OVERFLOW]); + if (uri_status < HTTP_URI_OK) { send_ipp_status(con, IPP_NOT_POSSIBLE, _("Bad device-uri \"%s\"."), attr->values[0].string.text); - cupsdLogMessage(CUPSD_LOG_DEBUG, - "add_printer: httpSeparateURI returned %d", uri_status); return; } @@ -2568,7 +2484,7 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ send_ipp_status(con, IPP_NOT_POSSIBLE, _("File device URIs have been disabled. " "To enable, see the FileDevice directive in " - "\"%s/cupsd.conf\"."), + "\"%s/cups-files.conf\"."), ServerRoot); return; } @@ -2925,17 +2841,11 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ cupsdSetPrinterReasons(printer, "none"); -#ifdef __APPLE__ /* * (Re)register color profiles... */ - if (!RunUser) - { - apple_unregister_profiles(printer); - apple_register_profiles(printer); - } -#endif /* __APPLE__ */ + cupsdRegisterColor(printer); } /* @@ -2955,7 +2865,7 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ snprintf(srcfile, sizeof(srcfile), "%s/ppd/%s.ppd", ServerRoot, printer->name); - if ((ppd = ppdOpenFile(srcfile)) != NULL) + if ((ppd = _ppdOpenFile(srcfile, _PPD_LOCALIZATION_NONE)) != NULL) { for (ppdattr = ppdFindAttr(ppd, "cupsPortMonitor", NULL); ppdattr; @@ -3069,888 +2979,6 @@ add_queued_job_count( } -#ifdef __APPLE__ -/* - * 'apple_init_profile()' - Initialize a color profile. - */ - -static void -apple_init_profile( - ppd_file_t *ppd, /* I - PPD file */ - cups_array_t *languages, /* I - Languages in the PPD file */ -# ifdef HAVE_COLORSYNCREGISTERDEVICE - CFMutableDictionaryRef profile, /* I - Profile dictionary */ -# else - CMDeviceProfileInfo *profile, /* I - Profile record */ -# endif /* HAVE_COLORSYNCREGISTERDEVICE */ - unsigned id, /* I - Profile ID */ - const char *name, /* I - Profile name */ - const char *text, /* I - Profile UI text */ - const char *iccfile) /* I - ICC filename */ -{ -# ifdef HAVE_COLORSYNCREGISTERDEVICE - CFURLRef url; /* URL for profile filename */ -# endif /* HAVE_COLORSYNCREGISTERDEVICE */ - CFMutableDictionaryRef dict; /* Dictionary for name */ - char *language; /* Current language */ - ppd_attr_t *attr; /* Profile attribute */ - CFStringRef cflang, /* Language string */ - cftext; /* Localized text */ - - - (void)id; - - /* - * Build the profile name dictionary... - */ - - dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - if (!dict) - { - cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to initialize profile \"%s\".", - iccfile); - return; - } - - cftext = CFStringCreateWithCString(kCFAllocatorDefault, text, - kCFStringEncodingUTF8); - - if (cftext) - { - CFDictionarySetValue(dict, CFSTR("en_US"), cftext); - CFRelease(cftext); - } - - if (languages) - { - /* - * Find localized names for the color profiles... - */ - - cupsArraySave(ppd->sorted_attrs); - - for (language = (char *)cupsArrayFirst(languages); - language; - language = (char *)cupsArrayNext(languages)) - { - if (iccfile) - { - if ((attr = _ppdLocalizedAttr(ppd, "cupsICCProfile", name, - language)) == NULL) - attr = _ppdLocalizedAttr(ppd, "APTiogaProfile", name, language); - } - else - attr = _ppdLocalizedAttr(ppd, "ColorModel", name, language); - - if (attr && attr->text[0]) - { - cflang = CFStringCreateWithCString(kCFAllocatorDefault, language, - kCFStringEncodingUTF8); - cftext = CFStringCreateWithCString(kCFAllocatorDefault, attr->text, - kCFStringEncodingUTF8); - - if (cflang && cftext) - CFDictionarySetValue(dict, cflang, cftext); - - if (cflang) - CFRelease(cflang); - - if (cftext) - CFRelease(cftext); - } - } - - cupsArrayRestore(ppd->sorted_attrs); - } - - /* - * Fill in the profile data... - */ - -# ifdef HAVE_COLORSYNCREGISTERDEVICE - if (iccfile) - { - url = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, - (const UInt8 *)iccfile, - strlen(iccfile), false); - - if (url) - { - CFDictionarySetValue(profile, kColorSyncDeviceProfileURL, url); - CFRelease(url); - } - } - - CFDictionarySetValue(profile, kColorSyncDeviceModeDescriptions, dict); - CFRelease(dict); - -# else - profile->dataVersion = cmDeviceProfileInfoVersion1; - profile->profileID = id; - profile->profileLoc.locType = iccfile ? cmPathBasedProfile : cmNoProfileBase; - profile->profileName = dict; - - if (iccfile) - strlcpy(profile->profileLoc.u.pathLoc.path, iccfile, - sizeof(profile->profileLoc.u.pathLoc.path)); -# endif /* HAVE_COLORSYNCREGISTERDEVICE */ -} - - -/* - * 'apple_register_profiles()' - Register color profiles for a printer. - */ - -static void -apple_register_profiles( - cupsd_printer_t *p) /* I - Printer */ -{ - int i; /* Looping var */ - char ppdfile[1024], /* PPD filename */ - iccfile[1024], /* ICC filename */ - selector[PPD_MAX_NAME]; - /* Profile selection string */ - ppd_file_t *ppd; /* PPD file */ - ppd_attr_t *attr, /* Profile attributes */ - *profileid_attr,/* cupsProfileID attribute */ - *q1_attr, /* ColorModel (or other) qualifier */ - *q2_attr, /* MediaType (or other) qualifier */ - *q3_attr; /* Resolution (or other) qualifier */ - char q_keyword[PPD_MAX_NAME]; - /* Qualifier keyword */ - const char *q1_choice, /* ColorModel (or other) choice */ - *q2_choice, /* MediaType (or other) choice */ - *q3_choice; /* Resolution (or other) choice */ - const char *profile_key; /* Profile keyword */ - ppd_option_t *cm_option; /* Color model option */ - ppd_choice_t *cm_choice; /* Color model choice */ - int num_profiles; /* Number of profiles */ - OSStatus error = 0; /* Last error */ - unsigned device_id, /* Printer device ID */ - profile_id = 0, /* Profile ID */ - default_profile_id = 0; - /* Default profile ID */ - CFMutableDictionaryRef device_name; /* Printer device name dictionary */ - CFStringRef printer_name; /* Printer name string */ - cups_array_t *languages; /* Languages array */ -# ifdef HAVE_COLORSYNCREGISTERDEVICE - CFMutableDictionaryRef profiles, /* Dictionary of profiles */ - profile; /* Current profile info dictionary */ - CFStringRef dict_key; /* Key in factory profile dictionary */ -# else - CMDeviceScope scope = /* Scope of the registration */ - { - kCFPreferencesAnyUser, - kCFPreferencesCurrentHost - }; - CMDeviceProfileArrayPtr profiles; /* Profiles */ - CMDeviceProfileInfo *profile; /* Current profile */ -# endif /* HAVE_COLORSYNCREGISTERDEVICE */ - - - /* - * Make sure ColorSync is available... - */ - -# ifdef HAVE_COLORSYNCREGISTERDEVICE - if (ColorSyncRegisterDevice == NULL) - return; - -# else - if (CMRegisterColorDevice == NULL) - return; -# endif /* HAVE_COLORSYNCREGISTERDEVICE */ - - /* - * Try opening the PPD file for this printer... - */ - - snprintf(ppdfile, sizeof(ppdfile), "%s/ppd/%s.ppd", ServerRoot, p->name); - if ((ppd = ppdOpenFile(ppdfile)) == NULL) - return; - - /* - * See if we have any profiles... - */ - - if ((attr = ppdFindAttr(ppd, "APTiogaProfile", NULL)) != NULL) - profile_key = "APTiogaProfile"; - else - { - attr = ppdFindAttr(ppd, "cupsICCProfile", NULL); - profile_key = "cupsICCProfile"; - } - - for (num_profiles = 0; attr; attr = ppdFindNextAttr(ppd, profile_key, NULL)) - if (attr->spec[0] && attr->value && attr->value[0]) - { - if (attr->value[0] != '/') - snprintf(iccfile, sizeof(iccfile), "%s/profiles/%s", DataDir, - attr->value); - else - strlcpy(iccfile, attr->value, sizeof(iccfile)); - - if (access(iccfile, 0)) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "%s: ICC Profile \"%s\" does not exist.", p->name, - iccfile); - continue; - } - - num_profiles ++; - } - -# ifdef HAVE_COLORSYNCREGISTERDEVICE - /* - * Create a dictionary for the factory profiles... - */ - - profiles = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - if (!profiles) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to allocate memory for factory profiles."); - ppdClose(ppd); - return; - } -# endif /* HAVE_COLORSYNCREGISTERDEVICE */ - - /* - * If we have profiles, add them... - */ - - if (num_profiles > 0) - { - if (profile_key[0] == 'A') - { - /* - * For Tioga PPDs, get the default profile using the DefaultAPTiogaProfile - * attribute... - */ - - if ((attr = ppdFindAttr(ppd, "DefaultAPTiogaProfile", NULL)) != NULL && - attr->value) - default_profile_id = atoi(attr->value); - - q1_choice = q2_choice = q3_choice = NULL; - } - else - { - /* - * For CUPS PPDs, figure out the default profile selector values... - */ - - if ((attr = ppdFindAttr(ppd, "cupsICCQualifier1", NULL)) != NULL && - attr->value && attr->value[0]) - { - snprintf(q_keyword, sizeof(q_keyword), "Default%s", attr->value); - q1_attr = ppdFindAttr(ppd, q_keyword, NULL); - } - else if ((q1_attr = ppdFindAttr(ppd, "DefaultColorModel", NULL)) == NULL) - q1_attr = ppdFindAttr(ppd, "DefaultColorSpace", NULL); - - if (q1_attr && q1_attr->value && q1_attr->value[0]) - q1_choice = q1_attr->value; - else - q1_choice = ""; - - if ((attr = ppdFindAttr(ppd, "cupsICCQualifier2", NULL)) != NULL && - attr->value && attr->value[0]) - { - snprintf(q_keyword, sizeof(q_keyword), "Default%s", attr->value); - q2_attr = ppdFindAttr(ppd, q_keyword, NULL); - } - else - q2_attr = ppdFindAttr(ppd, "DefaultMediaType", NULL); - - if (q2_attr && q2_attr->value && q2_attr->value[0]) - q2_choice = q2_attr->value; - else - q2_choice = NULL; - - if ((attr = ppdFindAttr(ppd, "cupsICCQualifier3", NULL)) != NULL && - attr->value && attr->value[0]) - { - snprintf(q_keyword, sizeof(q_keyword), "Default%s", attr->value); - q3_attr = ppdFindAttr(ppd, q_keyword, NULL); - } - else - q3_attr = ppdFindAttr(ppd, "DefaultResolution", NULL); - - if (q3_attr && q3_attr->value && q3_attr->value[0]) - q3_choice = q3_attr->value; - else - q3_choice = NULL; - } - -# ifndef HAVE_COLORSYNCREGISTERDEVICE - /* - * Build the array of profiles... - * - * Note: This calloc actually requests slightly more memory than needed. - */ - - if ((profiles = calloc(num_profiles, sizeof(CMDeviceProfileArray))) == NULL) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to allocate memory for factory profiles."); - ppdClose(ppd); - return; - } - - profiles->profileCount = num_profiles; - profile = profiles->profiles; -# endif /* !HAVE_COLORSYNCREGISTERDEVICE */ - - /* - * Loop through the profiles listed in the PPD... - */ - - languages = _ppdGetLanguages(ppd); - - for (attr = ppdFindAttr(ppd, profile_key, NULL); - attr; - attr = ppdFindNextAttr(ppd, profile_key, NULL)) - if (attr->spec[0] && attr->value && attr->value[0]) - { - /* - * Add this profile... - */ - - if (attr->value[0] != '/') - snprintf(iccfile, sizeof(iccfile), "%s/profiles/%s", DataDir, - attr->value); - else - strlcpy(iccfile, attr->value, sizeof(iccfile)); - - if (_cupsFileCheck(iccfile, _CUPS_FILE_CHECK_FILE, !RunUser, - cupsdLogFCMessage, p)) - continue; - - if (profile_key[0] == 'c') - { - cupsArraySave(ppd->sorted_attrs); - - if ((profileid_attr = ppdFindAttr(ppd, "cupsProfileID", - attr->spec)) != NULL && - profileid_attr->value && isdigit(profileid_attr->value[0] & 255)) - profile_id = (unsigned)strtoul(profileid_attr->value, NULL, 10); - else - profile_id = _ppdHashName(attr->spec); - - cupsArrayRestore(ppd->sorted_attrs); - } - else - profile_id = atoi(attr->spec); - -# ifdef HAVE_COLORSYNCREGISTERDEVICE - profile = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - if (!profile) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to allocate memory for color profile."); - CFRelease(profiles); - ppdClose(ppd); - return; - } - - apple_init_profile(ppd, languages, profile, profile_id, attr->spec, - attr->text[0] ? attr->text : attr->spec, iccfile); - - dict_key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, - CFSTR("%u"), profile_id); - if (dict_key) - { - CFDictionarySetValue(profiles, dict_key, profile); - CFRelease(dict_key); - } - - CFRelease(profile); - -# else - apple_init_profile(ppd, languages, profile, profile_id, attr->spec, - attr->text[0] ? attr->text : attr->spec, iccfile); - - profile ++; -# endif /* HAVE_COLORSYNCREGISTERDEVICE */ - - /* - * See if this is the default profile... - */ - - if (!default_profile_id && q1_choice && q2_choice && q3_choice) - { - snprintf(selector, sizeof(selector), "%s.%s.%s", q1_choice, q2_choice, - q3_choice); - if (!strcmp(selector, attr->spec)) - default_profile_id = profile_id; - } - - if (!default_profile_id && q1_choice && q2_choice) - { - snprintf(selector, sizeof(selector), "%s.%s.", q1_choice, q2_choice); - if (!strcmp(selector, attr->spec)) - default_profile_id = profile_id; - } - - if (!default_profile_id && q1_choice && q3_choice) - { - snprintf(selector, sizeof(selector), "%s..%s", q1_choice, q3_choice); - if (!strcmp(selector, attr->spec)) - default_profile_id = profile_id; - } - - if (!default_profile_id && q1_choice) - { - snprintf(selector, sizeof(selector), "%s..", q1_choice); - if (!strcmp(selector, attr->spec)) - default_profile_id = profile_id; - } - - if (!default_profile_id && q2_choice && q3_choice) - { - snprintf(selector, sizeof(selector), ".%s.%s", q2_choice, q3_choice); - if (!strcmp(selector, attr->spec)) - default_profile_id = profile_id; - } - - if (!default_profile_id && q2_choice) - { - snprintf(selector, sizeof(selector), ".%s.", q2_choice); - if (!strcmp(selector, attr->spec)) - default_profile_id = profile_id; - } - - if (!default_profile_id && q3_choice) - { - snprintf(selector, sizeof(selector), "..%s", q3_choice); - if (!strcmp(selector, attr->spec)) - default_profile_id = profile_id; - } - } - - _ppdFreeLanguages(languages); - } - else if ((cm_option = ppdFindOption(ppd, "ColorModel")) != NULL) - { - /* - * Extract profiles from ColorModel option... - */ - - const char *profile_name; /* Name of generic profile */ - - - num_profiles = cm_option->num_choices; - -# ifndef HAVE_COLORSYNCREGISTERDEVICE - /* - * Create an array for the factory profiles... - */ - - if ((profiles = calloc(num_profiles, sizeof(CMDeviceProfileArray))) == NULL) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to allocate memory for factory profiles."); - ppdClose(ppd); - return; - } - - profiles->profileCount = num_profiles; - profile = profiles->profiles; -# endif /* HAVE_COLORSYNCREGISTERDEVICE */ - - for (i = cm_option->num_choices, cm_choice = cm_option->choices; - i > 0; - i --, cm_choice ++) - { - if (!strcmp(cm_choice->choice, "Gray") || - !strcmp(cm_choice->choice, "Black")) - profile_name = "Gray"; - else if (!strcmp(cm_choice->choice, "RGB") || - !strcmp(cm_choice->choice, "CMY")) - profile_name = "RGB"; - else if (!strcmp(cm_choice->choice, "CMYK") || - !strcmp(cm_choice->choice, "KCMY")) - profile_name = "CMYK"; - else - profile_name = "DeviceN"; - - snprintf(selector, sizeof(selector), "%s..", profile_name); - profile_id = _ppdHashName(selector); - -# ifdef HAVE_COLORSYNCREGISTERDEVICE - profile = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - if (!profile) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to allocate memory for color profile."); - CFRelease(profiles); - ppdClose(ppd); - return; - } - - apple_init_profile(ppd, NULL, profile, profile_id, cm_choice->choice, - cm_choice->text, NULL); - - dict_key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, - CFSTR("%u"), profile_id); - if (dict_key) - { - CFDictionarySetValue(profiles, dict_key, profile); - CFRelease(dict_key); - } - - CFRelease(profile); - -# else - apple_init_profile(ppd, NULL, profile, profile_id, cm_choice->choice, - cm_choice->text, NULL); - profile ++; -# endif /* HAVE_COLORSYNCREGISTERDEVICE */ - - if (cm_choice->marked) - default_profile_id = profile_id; - } - } - else - { - /* - * Use the default colorspace... - */ - - attr = ppdFindAttr(ppd, "DefaultColorSpace", NULL); - - num_profiles = (attr && ppd->colorspace == PPD_CS_GRAY) ? 1 : 2; - -# ifdef HAVE_COLORSYNCREGISTERDEVICE - /* - * Add the grayscale profile first. We always have a grayscale profile. - */ - - profile = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - - if (!profile) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to allocate memory for color profile."); - CFRelease(profiles); - ppdClose(ppd); - return; - } - - profile_id = _ppdHashName("Gray.."); - apple_init_profile(ppd, NULL, profile, profile_id, "Gray", "Gray", NULL); - - dict_key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%u"), - profile_id); - if (dict_key) - { - CFDictionarySetValue(profiles, dict_key, profile); - CFRelease(dict_key); - } - - CFRelease(profile); - - /* - * Then add the RGB/CMYK/DeviceN color profile... - */ - - profile = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - - if (!profile) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to allocate memory for color profile."); - CFRelease(profiles); - ppdClose(ppd); - return; - } - - switch (ppd->colorspace) - { - default : - case PPD_CS_RGB : - case PPD_CS_CMY : - profile_id = _ppdHashName("RGB.."); - apple_init_profile(ppd, NULL, profile, profile_id, "RGB", "RGB", - NULL); - break; - - case PPD_CS_RGBK : - case PPD_CS_CMYK : - profile_id = _ppdHashName("CMYK.."); - apple_init_profile(ppd, NULL, profile, profile_id, "CMYK", "CMYK", - NULL); - break; - - case PPD_CS_GRAY : - if (attr) - break; - - case PPD_CS_N : - profile_id = _ppdHashName("DeviceN.."); - apple_init_profile(ppd, NULL, profile, profile_id, "DeviceN", - "DeviceN", NULL); - break; - } - - if (CFDictionaryGetCount(profile) > 0) - { - dict_key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, - CFSTR("%u"), profile_id); - if (dict_key) - { - CFDictionarySetValue(profiles, dict_key, profile); - CFRelease(dict_key); - } - } - - CFRelease(profile); - -# else - /* - * Create an array for the factory profiles... - */ - - if ((profiles = calloc(num_profiles, sizeof(CMDeviceProfileArray))) == NULL) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to allocate memory for factory profiles."); - ppdClose(ppd); - return; - } - - profiles->profileCount = num_profiles; - - /* - * Add the grayscale profile first. We always have a grayscale profile. - */ - - profile_id = _ppdHashName("Gray.."); - apple_init_profile(ppd, NULL, profiles->profiles, profile_id, "Gray", - "Gray", NULL); - - /* - * Then add the RGB/CMYK/DeviceN color profile... - */ - - switch (ppd->colorspace) - { - default : - case PPD_CS_RGB : - case PPD_CS_CMY : - profile_id = _ppdHashName("RGB.."); - apple_init_profile(ppd, NULL, profiles->profiles + 1, profile_id, - "RGB", "RGB", NULL); - break; - case PPD_CS_RGBK : - case PPD_CS_CMYK : - profile_id = _ppdHashName("CMYK.."); - apple_init_profile(ppd, NULL, profiles->profiles + 1, profile_id, - "CMYK", "CMYK", NULL); - break; - - case PPD_CS_GRAY : - if (attr) - break; - - case PPD_CS_N : - profile_id = _ppdHashName("DeviceN.."); - apple_init_profile(ppd, NULL, profiles->profiles + 1, profile_id, - "DeviceN", "DeviceN", NULL); - break; - } -# endif /* HAVE_COLORSYNCREGISTERDEVICE */ - } - - if (num_profiles > 0) - { - /* - * Make sure we have a default profile ID... - */ - - if (!default_profile_id) - default_profile_id = profile_id; /* Last profile */ - -# ifdef HAVE_COLORSYNCREGISTERDEVICE - dict_key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%u"), - default_profile_id); - if (dict_key) - { - CFDictionarySetValue(profiles, kColorSyncDeviceDefaultProfileID, - dict_key); - CFRelease(dict_key); - } -# endif /* HAVE_COLORSYNCREGISTERDEVICE */ - - /* - * Get the device ID hash and pathelogical name dictionary. - */ - - cupsdLogMessage(CUPSD_LOG_INFO, "Registering ICC color profiles for \"%s\"", - p->name); - - device_id = _ppdHashName(p->name); - device_name = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - printer_name = CFStringCreateWithCString(kCFAllocatorDefault, - p->name, kCFStringEncodingUTF8); - - if (device_name && printer_name) - { - CFDictionarySetValue(device_name, CFSTR("en_US"), printer_name); - - /* - * Register the device with ColorSync... - */ - -# ifdef HAVE_COLORSYNCREGISTERDEVICE - CFTypeRef deviceDictKeys[] = - { /* Device keys */ - kColorSyncDeviceDescriptions, - kColorSyncFactoryProfiles, - kColorSyncDeviceUserScope, - kColorSyncDeviceHostScope - }; - CFTypeRef deviceDictVals[] = - { /* Device values */ - device_name, - profiles, - kCFPreferencesAnyUser, - kCFPreferencesCurrentHost - }; - CFDictionaryRef deviceDict; /* Device dictionary */ - CFUUIDRef deviceUUID; /* Device UUID */ - - deviceDict = CFDictionaryCreate(kCFAllocatorDefault, - (const void **)deviceDictKeys, - (const void **)deviceDictVals, - sizeof(deviceDictKeys) / - sizeof(deviceDictKeys[0]), - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - deviceUUID = ColorSyncCreateUUIDFromUInt32(device_id); - - if (!deviceDict || !deviceUUID || - !ColorSyncRegisterDevice(kColorSyncPrinterDeviceClass, deviceUUID, - deviceDict)) - error = 1001; - - if (deviceUUID) - CFRelease(deviceUUID); - - if (deviceDict) - CFRelease(deviceDict); - -# else - error = CMRegisterColorDevice(cmPrinterDeviceClass, device_id, - device_name, &scope); - - /* - * Register the profiles... - */ - - if (error == noErr) - error = CMSetDeviceFactoryProfiles(cmPrinterDeviceClass, device_id, - default_profile_id, profiles); -# endif /* HAVE_COLORSYNCREGISTERDEVICE */ - } - else - error = 1000; - - /* - * Clean up... - */ - - if (error != noErr) - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to register ICC color profiles for \"%s\": %d", - p->name, (int)error); - - if (printer_name) - CFRelease(printer_name); - - if (device_name) - CFRelease(device_name); - } - - /* - * Free any memory we used... - */ - -# ifdef HAVE_COLORSYNCREGISTERDEVICE - CFRelease(profiles); - -# else - if (num_profiles > 0) - { - for (profile = profiles->profiles; - num_profiles > 0; - profile ++, num_profiles --) - CFRelease(profile->profileName); - - free(profiles); - } -# endif /* HAVE_COLORSYNCREGISTERDEVICE */ - - ppdClose(ppd); -} - - -/* - * 'apple_unregister_profiles()' - Remove color profiles for the specified - * printer. - */ - -static void -apple_unregister_profiles( - cupsd_printer_t *p) /* I - Printer */ -{ - /* - * Make sure ColorSync is available... - */ - -# ifdef HAVE_COLORSYNCREGISTERDEVICE - if (ColorSyncUnregisterDevice != NULL) - { - /* - * Because we may have registered the printer profiles using a prior device - * ID-based UUID, remove both the old style UUID and current UUID for the - * printer. - */ - - CFUUIDRef deviceUUID; /* Device UUID */ - - deviceUUID = ColorSyncCreateUUIDFromUInt32(_ppdHashName(p->name)); - if (deviceUUID) - { - ColorSyncUnregisterDevice(kColorSyncPrinterDeviceClass, deviceUUID); - CFRelease(deviceUUID); - } - } - -# else - if (CMUnregisterColorDevice != NULL) - CMUnregisterColorDevice(cmPrinterDeviceClass, _ppdHashName(p->name)); -# endif /* HAVE_COLORSYNCREGISTERDEVICE */ -} -#endif /* __APPLE__ */ - - /* * 'apply_printer_defaults()' - Apply printer default options to a job. */ @@ -5042,8 +4070,6 @@ close_job(cupsd_client_t *con, /* I - Client connection */ ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_ENUM, "job-state", job->state_value); - add_job_state_reasons(con, job); - con->response->request.status.status_code = IPP_OK; /* @@ -5055,192 +4081,6 @@ close_job(cupsd_client_t *con, /* I - Client connection */ /* - * 'copy_attribute()' - Copy a single attribute. - */ - -static ipp_attribute_t * /* O - New attribute */ -copy_attribute( - ipp_t *to, /* O - Destination request/response */ - ipp_attribute_t *attr, /* I - Attribute to copy */ - int quickcopy) /* I - Do a quick copy? */ -{ - int i; /* Looping var */ - ipp_attribute_t *toattr; /* Destination attribute */ - - - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "copy_attribute(%p, %p[%s,%x,%x])", to, attr, - attr->name ? attr->name : "(null)", attr->group_tag, - attr->value_tag); - - switch (attr->value_tag & ~IPP_TAG_COPY) - { - case IPP_TAG_ZERO : - toattr = ippAddSeparator(to); - break; - - case IPP_TAG_INTEGER : - case IPP_TAG_ENUM : - toattr = ippAddIntegers(to, attr->group_tag, attr->value_tag, - attr->name, attr->num_values, NULL); - - for (i = 0; i < attr->num_values; i ++) - toattr->values[i].integer = attr->values[i].integer; - break; - - case IPP_TAG_BOOLEAN : - toattr = ippAddBooleans(to, attr->group_tag, attr->name, - attr->num_values, NULL); - - for (i = 0; i < attr->num_values; i ++) - toattr->values[i].boolean = attr->values[i].boolean; - break; - - case IPP_TAG_STRING : - case IPP_TAG_TEXT : - case IPP_TAG_NAME : - case IPP_TAG_KEYWORD : - case IPP_TAG_URI : - case IPP_TAG_URISCHEME : - case IPP_TAG_CHARSET : - case IPP_TAG_LANGUAGE : - case IPP_TAG_MIMETYPE : - toattr = ippAddStrings(to, attr->group_tag, - (ipp_tag_t)(attr->value_tag | quickcopy), - attr->name, attr->num_values, NULL, NULL); - - if (quickcopy) - { - for (i = 0; i < attr->num_values; i ++) - toattr->values[i].string.text = attr->values[i].string.text; - } - else if (attr->value_tag & IPP_TAG_COPY) - { - for (i = 0; i < attr->num_values; i ++) - toattr->values[i].string.text = - _cupsStrAlloc(attr->values[i].string.text); - } - else - { - for (i = 0; i < attr->num_values; i ++) - toattr->values[i].string.text = - _cupsStrRetain(attr->values[i].string.text); - } - break; - - case IPP_TAG_DATE : - toattr = ippAddDate(to, attr->group_tag, attr->name, - attr->values[0].date); - break; - - case IPP_TAG_RESOLUTION : - toattr = ippAddResolutions(to, attr->group_tag, attr->name, - attr->num_values, IPP_RES_PER_INCH, - NULL, NULL); - - for (i = 0; i < attr->num_values; i ++) - { - toattr->values[i].resolution.xres = attr->values[i].resolution.xres; - toattr->values[i].resolution.yres = attr->values[i].resolution.yres; - toattr->values[i].resolution.units = attr->values[i].resolution.units; - } - break; - - case IPP_TAG_RANGE : - toattr = ippAddRanges(to, attr->group_tag, attr->name, - attr->num_values, NULL, NULL); - - for (i = 0; i < attr->num_values; i ++) - { - toattr->values[i].range.lower = attr->values[i].range.lower; - toattr->values[i].range.upper = attr->values[i].range.upper; - } - break; - - case IPP_TAG_TEXTLANG : - case IPP_TAG_NAMELANG : - toattr = ippAddStrings(to, attr->group_tag, - (ipp_tag_t)(attr->value_tag | quickcopy), - attr->name, attr->num_values, NULL, NULL); - - if (quickcopy) - { - for (i = 0; i < attr->num_values; i ++) - { - toattr->values[i].string.charset = attr->values[i].string.charset; - toattr->values[i].string.text = attr->values[i].string.text; - } - } - else if (attr->value_tag & IPP_TAG_COPY) - { - for (i = 0; i < attr->num_values; i ++) - { - if (!i) - toattr->values[i].string.charset = - _cupsStrAlloc(attr->values[i].string.charset); - else - toattr->values[i].string.charset = - toattr->values[0].string.charset; - - toattr->values[i].string.text = - _cupsStrAlloc(attr->values[i].string.text); - } - } - else - { - for (i = 0; i < attr->num_values; i ++) - { - if (!i) - toattr->values[i].string.charset = - _cupsStrRetain(attr->values[i].string.charset); - else - toattr->values[i].string.charset = - toattr->values[0].string.charset; - - toattr->values[i].string.text = - _cupsStrRetain(attr->values[i].string.text); - } - } - break; - - case IPP_TAG_BEGIN_COLLECTION : - toattr = ippAddCollections(to, attr->group_tag, attr->name, - attr->num_values, NULL); - - for (i = 0; i < attr->num_values; i ++) - { - toattr->values[i].collection = attr->values[i].collection; - attr->values[i].collection->use ++; - } - break; - - default : - toattr = ippAddIntegers(to, attr->group_tag, attr->value_tag, - attr->name, attr->num_values, NULL); - - for (i = 0; i < attr->num_values; i ++) - { - toattr->values[i].unknown.length = attr->values[i].unknown.length; - - if (toattr->values[i].unknown.length > 0) - { - if ((toattr->values[i].unknown.data = - malloc(toattr->values[i].unknown.length)) == NULL) - toattr->values[i].unknown.length = 0; - else - memcpy(toattr->values[i].unknown.data, - attr->values[i].unknown.data, - toattr->values[i].unknown.length); - } - } - break; /* anti-compiler-warning-code */ - } - - return (toattr); -} - - -/* * 'copy_attrs()' - Copy attributes from one request to another. */ @@ -5307,7 +4147,7 @@ copy_attrs(ipp_t *to, /* I - Destination request */ !strcmp(fromattr->name, "media-col-database"))) continue; - copy_attribute(to, fromattr, quickcopy); + ippCopyAttribute(to, fromattr, quickcopy); } } } @@ -5528,7 +4368,7 @@ copy_banner(cupsd_client_t *con, /* I - Client connection */ cupsFilePrintf(out, "%dx%d%s", attr->values[i].resolution.xres, attr->values[i].resolution.yres, attr->values[i].resolution.units == IPP_RES_PER_INCH ? - "dpi" : "dpc"); + "dpi" : "dpcm"); break; case IPP_TAG_URI : @@ -5791,11 +4631,22 @@ copy_model(cupsd_client_t *con, /* I - Client connection */ } /* + * Open the source file for a copy... + */ + + if ((src = cupsFileOpen(tempfile, "rb")) == NULL) + { + unlink(tempfile); + return (-1); + } + + /* * Read the source file and see what page sizes are supported... */ - if ((ppd = ppdOpenFile(tempfile)) == NULL) + if ((ppd = _ppdOpen(src, _PPD_LOCALIZATION_NONE)) == NULL) { + cupsFileClose(src); unlink(tempfile); return (-1); } @@ -5863,17 +4714,6 @@ copy_model(cupsd_client_t *con, /* I - Client connection */ ppdClose(ppd); /* - * Open the source file for a copy... - */ - - if ((src = cupsFileOpen(tempfile, "rb")) == NULL) - { - cupsFreeOptions(num_defaults, defaults); - unlink(tempfile); - return (-1); - } - - /* * Open the destination file for a copy... */ @@ -5889,6 +4729,8 @@ copy_model(cupsd_client_t *con, /* I - Client connection */ * Copy the source file to the destination... */ + cupsFileRewind(src); + while (cupsFileGets(src, buffer, sizeof(buffer))) { if (!strncmp(buffer, "*Default", 8)) @@ -5953,10 +4795,10 @@ copy_job_attrs(cupsd_client_t *con, /* I - Client connection */ if (!cupsArrayFind(exclude, "all")) { - if ((!exclude || !cupsArrayFind(exclude, "document-count")) && - (!ra || cupsArrayFind(ra, "document-count"))) + if ((!exclude || !cupsArrayFind(exclude, "number-of-documents")) && + (!ra || cupsArrayFind(ra, "number-of-documents"))) ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, - "document-count", job->num_files); + "number-of-documents", job->num_files); if ((!exclude || !cupsArrayFind(exclude, "job-media-progress")) && (!ra || cupsArrayFind(ra, "job-media-progress"))) @@ -5989,16 +4831,13 @@ copy_job_attrs(cupsd_client_t *con, /* I - Client connection */ { httpAssembleURIf(HTTP_URI_CODING_ALL, job_uri, sizeof(job_uri), "ipp", NULL, con->servername, con->serverport, - job->dtype & (CUPS_PRINTER_IMPLICIT | CUPS_PRINTER_CLASS) ? - "/classes/%s" : "/printers/%s", + (job->dtype & CUPS_PRINTER_CLASS) ? "/classes/%s" : + "/printers/%s", job->dest); ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_URI, "job-printer-uri", NULL, job_uri); } - if (!ra || cupsArrayFind(ra, "job-state-reasons")) - add_job_state_reasons(con, job); - if (!ra || cupsArrayFind(ra, "job-uri")) { httpAssembleURIf(HTTP_URI_CODING_ALL, job_uri, sizeof(job_uri), "ipp", NULL, @@ -6089,7 +4928,7 @@ copy_printer_attrs( ippAddDate(con->response, IPP_TAG_PRINTER, "printer-current-time", ippTimeToDate(curtime)); -#ifdef HAVE_DNSSD +#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) if (!ra || cupsArrayFind(ra, "printer-dns-sd-name")) { if (printer->reg_name) @@ -6099,7 +4938,7 @@ copy_printer_attrs( ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_NOVALUE, "printer-dns-sd-name", 0); } -#endif /* HAVE_DNSSD */ +#endif /* HAVE_DNSSD || HAVE_AVAHI */ if (!ra || cupsArrayFind(ra, "printer-error-policy")) ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_NAME, @@ -6115,7 +4954,7 @@ copy_printer_attrs( "stop-printer" }; - if (printer->type & (CUPS_PRINTER_IMPLICIT | CUPS_PRINTER_CLASS)) + if (printer->type & CUPS_PRINTER_CLASS) ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_NAME | IPP_TAG_COPY, "printer-error-policy-supported", NULL, "retry-current-job"); else @@ -6142,8 +4981,7 @@ copy_printer_attrs( ippAddBoolean(con->response, IPP_TAG_PRINTER, "printer-is-shared", printer->shared); - if ((!ra || cupsArrayFind(ra, "printer-more-info")) && - !(printer->type & CUPS_PRINTER_DISCOVERED)) + if (!ra || cupsArrayFind(ra, "printer-more-info")) { httpAssembleURIf(HTTP_URI_CODING_ALL, printer_uri, sizeof(printer_uri), "http", NULL, con->servername, con->serverport, @@ -6199,8 +5037,7 @@ copy_printer_attrs( ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "printer-up-time", curtime); - if ((!ra || cupsArrayFind(ra, "printer-uri-supported")) && - !(printer->type & CUPS_PRINTER_DISCOVERED)) + if (!ra || cupsArrayFind(ra, "printer-uri-supported")) { httpAssembleURIf(HTTP_URI_CODING_ALL, printer_uri, sizeof(printer_uri), "ipp", NULL, con->servername, con->serverport, @@ -6350,8 +5187,16 @@ static void create_job(cupsd_client_t *con, /* I - Client connection */ ipp_attribute_t *uri) /* I - Printer URI */ { + int i; /* Looping var */ cupsd_printer_t *printer; /* Printer */ cupsd_job_t *job; /* New job */ + static const char * const forbidden_attrs[] = + { /* List of forbidden attributes */ + "compression", + "document-format", + "document-name", + "document-natural-language" + }; cupsdLogMessage(CUPSD_LOG_DEBUG2, "create_job(%p[%d], %s)", con, @@ -6373,6 +5218,29 @@ create_job(cupsd_client_t *con, /* I - Client connection */ } /* + * Check for invalid Create-Job attributes and log a warning or error depending + * on whether cupsd is running in "strict conformance" mode... + */ + + for (i = 0; + i < (int)(sizeof(forbidden_attrs) / sizeof(forbidden_attrs[0])); + i ++) + if (ippFindAttribute(con->request, forbidden_attrs[i], IPP_TAG_ZERO)) + { + if (StrictConformance) + { + send_ipp_status(con, IPP_BAD_REQUEST, + _("The '%s' operation attribute cannot be supplied in a " + "Create-Job request."), forbidden_attrs[i]); + return; + } + + cupsdLogMessage(CUPSD_LOG_WARN, + "Unexpected '%s' operation attribute in a Create-Job " + "request.", forbidden_attrs[i]); + } + + /* * Create the job object... */ @@ -6432,6 +5300,7 @@ create_requested_array(ipp_t *request) /* I - IPP request */ if (!strcmp(value, "job-template")) { + /* Only includes the set of Job Template attributes supported by CUPS */ cupsArrayAdd(ra, "copies"); cupsArrayAdd(ra, "copies-default"); cupsArrayAdd(ra, "copies-supported"); @@ -6448,6 +5317,8 @@ create_requested_array(ipp_t *request) /* I - IPP request */ cupsArrayAdd(ra, "job-sheets-default"); cupsArrayAdd(ra, "job-sheets-supported"); cupsArrayAdd(ra, "media"); + cupsArrayAdd(ra, "media-col"); + cupsArrayAdd(ra, "media-col-default"); cupsArrayAdd(ra, "media-default"); cupsArrayAdd(ra, "media-supported"); cupsArrayAdd(ra, "multiple-document-handling"); @@ -6455,24 +5326,49 @@ create_requested_array(ipp_t *request) /* I - IPP request */ cupsArrayAdd(ra, "multiple-document-handling-supported"); cupsArrayAdd(ra, "number-up"); cupsArrayAdd(ra, "number-up-default"); + cupsArrayAdd(ra, "number-up-layout"); + cupsArrayAdd(ra, "number-up-layout-default"); + cupsArrayAdd(ra, "number-up-layout-supported"); cupsArrayAdd(ra, "number-up-supported"); cupsArrayAdd(ra, "orientation-requested"); cupsArrayAdd(ra, "orientation-requested-default"); cupsArrayAdd(ra, "orientation-requested-supported"); + cupsArrayAdd(ra, "output-bin"); + cupsArrayAdd(ra, "output-bin-default"); + cupsArrayAdd(ra, "output-bin-supported"); + cupsArrayAdd(ra, "page-delivery"); + cupsArrayAdd(ra, "page-delivery-default"); + cupsArrayAdd(ra, "page-delivery-supported"); + cupsArrayAdd(ra, "page-order-received"); + cupsArrayAdd(ra, "page-order-received-default"); + cupsArrayAdd(ra, "page-order-received-supported"); cupsArrayAdd(ra, "page-ranges"); cupsArrayAdd(ra, "page-ranges-supported"); - cupsArrayAdd(ra, "printer-resolution"); - cupsArrayAdd(ra, "printer-resolution-default"); - cupsArrayAdd(ra, "printer-resolution-supported"); + cupsArrayAdd(ra, "presentation-direction-number-up"); + cupsArrayAdd(ra, "presentation-direction-number-up-default"); + cupsArrayAdd(ra, "presentation-direction-number-up-supported"); + cupsArrayAdd(ra, "print-color-mode"); + cupsArrayAdd(ra, "print-color-mode-default"); + cupsArrayAdd(ra, "print-color-mode-supported"); + cupsArrayAdd(ra, "print-content-optimize"); + cupsArrayAdd(ra, "print-content-optimize-default"); + cupsArrayAdd(ra, "print-content-optimize-supported"); cupsArrayAdd(ra, "print-quality"); cupsArrayAdd(ra, "print-quality-default"); cupsArrayAdd(ra, "print-quality-supported"); + cupsArrayAdd(ra, "printer-resolution"); + cupsArrayAdd(ra, "printer-resolution-default"); + cupsArrayAdd(ra, "printer-resolution-supported"); + cupsArrayAdd(ra, "sheet-collate"); + cupsArrayAdd(ra, "sheet-collate-default"); + cupsArrayAdd(ra, "sheet-collate-supported"); cupsArrayAdd(ra, "sides"); cupsArrayAdd(ra, "sides-default"); cupsArrayAdd(ra, "sides-supported"); } else if (!strcmp(value, "job-description")) { + /* Only includes the set of Job Description attributes supported by CUPS */ cupsArrayAdd(ra, "date-time-at-completed"); cupsArrayAdd(ra, "date-time-at-creation"); cupsArrayAdd(ra, "date-time-at-processing"); @@ -6483,6 +5379,7 @@ create_requested_array(ipp_t *request) /* I - IPP request */ cupsArrayAdd(ra, "job-impressions-completed"); cupsArrayAdd(ra, "job-k-octets"); cupsArrayAdd(ra, "job-k-octets-processed"); + cupsArrayAdd(ra, "job-mandatory-attributes"); cupsArrayAdd(ra, "job-media-progress"); cupsArrayAdd(ra, "job-media-sheets"); cupsArrayAdd(ra, "job-media-sheets-completed"); @@ -6505,6 +5402,7 @@ create_requested_array(ipp_t *request) /* I - IPP request */ } else if (!strcmp(value, "printer-description")) { + /* Only includes the set of Printer Description attributes supported by CUPS */ cupsArrayAdd(ra, "charset-configured"); cupsArrayAdd(ra, "charset-supported"); cupsArrayAdd(ra, "color-supported"); @@ -6513,43 +5411,54 @@ create_requested_array(ipp_t *request) /* I - IPP request */ cupsArrayAdd(ra, "document-format-supported"); cupsArrayAdd(ra, "generated-natural-language-supported"); cupsArrayAdd(ra, "ipp-versions-supported"); + cupsArrayAdd(ra, "job-creation-attributes-supported"); + cupsArrayAdd(ra, "job-ids-supported"); cupsArrayAdd(ra, "job-impressions-supported"); cupsArrayAdd(ra, "job-k-octets-supported"); cupsArrayAdd(ra, "job-media-sheets-supported"); cupsArrayAdd(ra, "job-settable-attributes-supported"); + cupsArrayAdd(ra, "jpeg-k-octets-supported"); + cupsArrayAdd(ra, "jpeg-x-dimension-supported"); + cupsArrayAdd(ra, "jpeg-y-dimension-supported"); + cupsArrayAdd(ra, "media-bottom-margin-supported"); + cupsArrayAdd(ra, "media-col-supported"); + cupsArrayAdd(ra, "media-key-supported"); + cupsArrayAdd(ra, "media-left-margin-supported"); + cupsArrayAdd(ra, "media-right-margin-supported"); + cupsArrayAdd(ra, "media-size-supported"); + cupsArrayAdd(ra, "media-source-supported"); + cupsArrayAdd(ra, "media-top-margin-supported"); + cupsArrayAdd(ra, "media-type-supported"); cupsArrayAdd(ra, "multiple-document-jobs-supported"); cupsArrayAdd(ra, "multiple-operation-time-out"); cupsArrayAdd(ra, "natural-language-configured"); - cupsArrayAdd(ra, "notify-attributes-supported"); - cupsArrayAdd(ra, "notify-lease-duration-default"); - cupsArrayAdd(ra, "notify-lease-duration-supported"); cupsArrayAdd(ra, "notify-max-events-supported"); - cupsArrayAdd(ra, "notify-events-default"); - cupsArrayAdd(ra, "notify-events-supported"); - cupsArrayAdd(ra, "notify-pull-method-supported"); cupsArrayAdd(ra, "notify-schemes-supported"); cupsArrayAdd(ra, "operations-supported"); cupsArrayAdd(ra, "pages-per-minute"); cupsArrayAdd(ra, "pages-per-minute-color"); + cupsArrayAdd(ra, "pdf-k-octets-supported"); cupsArrayAdd(ra, "pdl-override-supported"); cupsArrayAdd(ra, "printer-alert"); cupsArrayAdd(ra, "printer-alert-description"); cupsArrayAdd(ra, "printer-commands"); cupsArrayAdd(ra, "printer-current-time"); - cupsArrayAdd(ra, "printer-driver-installer"); cupsArrayAdd(ra, "printer-dns-sd-name"); cupsArrayAdd(ra, "printer-info"); cupsArrayAdd(ra, "printer-is-accepting-jobs"); + cupsArrayAdd(ra, "printer-is-shared"); cupsArrayAdd(ra, "printer-location"); cupsArrayAdd(ra, "printer-make-and-model"); cupsArrayAdd(ra, "printer-message-from-operator"); cupsArrayAdd(ra, "printer-more-info"); cupsArrayAdd(ra, "printer-more-info-manufacturer"); cupsArrayAdd(ra, "printer-name"); + cupsArrayAdd(ra, "printer-settable-attributes-supported"); cupsArrayAdd(ra, "printer-state"); + cupsArrayAdd(ra, "printer-state-change-date-time"); + cupsArrayAdd(ra, "printer-state-change-time"); cupsArrayAdd(ra, "printer-state-message"); cupsArrayAdd(ra, "printer-state-reasons"); - cupsArrayAdd(ra, "printer-settable-attributes-supported"); cupsArrayAdd(ra, "printer-type"); cupsArrayAdd(ra, "printer-up-time"); cupsArrayAdd(ra, "printer-uri-supported"); @@ -6557,6 +5466,7 @@ create_requested_array(ipp_t *request) /* I - IPP request */ cupsArrayAdd(ra, "reference-uri-schemes-supported"); cupsArrayAdd(ra, "uri-authentication-supported"); cupsArrayAdd(ra, "uri-security-supported"); + cupsArrayAdd(ra, "which-jobs-supported"); } else if (!strcmp(value, "printer-defaults")) { @@ -6568,14 +5478,32 @@ create_requested_array(ipp_t *request) /* I - IPP request */ name = (char *)cupsArrayNext(CommonDefaults)) cupsArrayAdd(ra, name); } + else if (!strcmp(value, "subscription-description")) + { + /* Only includes the set of Subscription Description attributes supported by CUPS */ + cupsArrayAdd(ra, "notify-job-id"); + cupsArrayAdd(ra, "notify-lease-expiration-time"); + cupsArrayAdd(ra, "notify-printer-up-time"); + cupsArrayAdd(ra, "notify-printer-uri"); + cupsArrayAdd(ra, "notify-sequence-number"); + cupsArrayAdd(ra, "notify-subscriber-user-name"); + cupsArrayAdd(ra, "notify-subscription-id"); + } else if (!strcmp(value, "subscription-template")) { + /* Only includes the set of Subscription Template attributes supported by CUPS */ cupsArrayAdd(ra, "notify-attributes"); + cupsArrayAdd(ra, "notify-attributes-supported"); cupsArrayAdd(ra, "notify-charset"); cupsArrayAdd(ra, "notify-events"); + cupsArrayAdd(ra, "notify-events-default"); + cupsArrayAdd(ra, "notify-events-supported"); cupsArrayAdd(ra, "notify-lease-duration"); + cupsArrayAdd(ra, "notify-lease-duration-default"); + cupsArrayAdd(ra, "notify-lease-duration-supported"); cupsArrayAdd(ra, "notify-natural-language"); cupsArrayAdd(ra, "notify-pull-method"); + cupsArrayAdd(ra, "notify-pull-method-supported"); cupsArrayAdd(ra, "notify-recipient-uri"); cupsArrayAdd(ra, "notify-time-interval"); cupsArrayAdd(ra, "notify-user-data"); @@ -7034,13 +5962,11 @@ delete_printer(cupsd_client_t *con, /* I - Client connection */ snprintf(filename, sizeof(filename), "%s/%s.data", CacheDir, printer->name); unlink(filename); -#ifdef __APPLE__ /* * Unregister color profiles... */ - apple_unregister_profiles(printer); -#endif /* __APPLE__ */ + cupsdUnregisterColor(printer); if (dtype & CUPS_PRINTER_CLASS) { @@ -8062,11 +6988,10 @@ get_ppd(cupsd_client_t *con, /* I - Client connection */ "printer-uri", NULL, dest->uri); return; } - else if (dtype & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT)) + else if (dtype & CUPS_PRINTER_CLASS) { for (i = 0; i < dest->num_printers; i ++) - if (!(dest->printers[i]->type & - (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT))) + if (!(dest->printers[i]->type & CUPS_PRINTER_CLASS)) { snprintf(filename, sizeof(filename), "%s/ppd/%s.ppd", ServerRoot, dest->printers[i]->name); @@ -8514,15 +7439,6 @@ get_printers(cupsd_client_t *con, /* I - Client connection */ (printer->location && !_cups_strcasecmp(printer->location, location)))) { /* - * If HideImplicitMembers is enabled, see if this printer or class - * is a member of an implicit class... - */ - - if (ImplicitClasses && HideImplicitMembers && - printer->in_implicit_class) - continue; - - /* * If a username is specified, see if it is allowed or denied * access... */ @@ -9416,7 +8332,7 @@ print_job(cupsd_client_t *con, /* I - Client connection */ * Grab format from client... */ - if (sscanf(format->values[0].string.text, "%15[^/]/%31[^;]", super, + if (sscanf(format->values[0].string.text, "%15[^/]/%255[^;]", super, type) != 2) { send_ipp_status(con, IPP_BAD_REQUEST, @@ -9433,7 +8349,7 @@ print_job(cupsd_client_t *con, /* I - Client connection */ * Use default document format... */ - if (sscanf(default_format, "%15[^/]/%31[^;]", super, type) != 2) + if (sscanf(default_format, "%15[^/]/%255[^;]", super, type) != 2) { send_ipp_status(con, IPP_BAD_REQUEST, _("Bad document-format \"%s\"."), @@ -9747,14 +8663,14 @@ read_job_ticket(cupsd_client_t *con) /* I - Client connection */ if (con->request->last == attr2) con->request->last = prev2; - _ippFreeAttr(attr2); + ippDeleteAttribute(NULL, attr2); } /* * Add new option by copying it... */ - copy_attribute(con->request, attr, 0); + ippCopyAttribute(con->request, attr, 0); } /* @@ -10035,6 +8951,7 @@ release_job(cupsd_client_t *con, /* I - Client connection */ cupsdAddEvent(CUPSD_EVENT_JOB_CONFIG_CHANGED, cupsdFindDest(job->dest), job, "Job job-hold-until value changed by user."); + ippSetString(job->attrs, &job->reasons, 0, "none"); } /* @@ -10362,7 +9279,7 @@ save_auth_info( fchown(cupsFileNumber(fp), 0, 0); fchmod(cupsFileNumber(fp), 0400); - cupsFilePuts(fp, "CUPSD-AUTH-V2\n"); + cupsFilePuts(fp, "CUPSD-AUTH-V3\n"); for (i = 0; i < (int)(sizeof(job->auth_env) / sizeof(job->auth_env[0])); @@ -10380,9 +9297,15 @@ save_auth_info( i < (int)(sizeof(job->auth_env) / sizeof(job->auth_env[0])); i ++) { - httpEncode64_2(line, sizeof(line), auth_info->values[i].string.text, - strlen(auth_info->values[i].string.text)); - cupsFilePutConf(fp, dest->auth_info_required[i], line); + if (strcmp(dest->auth_info_required[i], "negotiate")) + { + httpEncode64_2(line, sizeof(line), auth_info->values[i].string.text, + strlen(auth_info->values[i].string.text)); + cupsFilePutConf(fp, dest->auth_info_required[i], line); + } + else + cupsFilePutConf(fp, dest->auth_info_required[i], + auth_info->values[i].string.text); if (!strcmp(dest->auth_info_required[i], "username")) cupsdSetStringf(job->auth_env + i, "AUTH_USERNAME=%s", @@ -10646,7 +9569,7 @@ send_document(cupsd_client_t *con, /* I - Client connection */ * Grab format from client... */ - if (sscanf(format->values[0].string.text, "%15[^/]/%31[^;]", + if (sscanf(format->values[0].string.text, "%15[^/]/%255[^;]", super, type) != 2) { send_ipp_status(con, IPP_BAD_REQUEST, _("Bad document-format \"%s\"."), @@ -10662,7 +9585,7 @@ send_document(cupsd_client_t *con, /* I - Client connection */ * Use default document format... */ - if (sscanf(default_format, "%15[^/]/%31[^;]", super, type) != 2) + if (sscanf(default_format, "%15[^/]/%255[^;]", super, type) != 2) { send_ipp_status(con, IPP_BAD_REQUEST, _("Bad document-format-default \"%s\"."), default_format); @@ -10804,6 +9727,8 @@ send_document(cupsd_client_t *con, /* I - Client connection */ { job->state->values[0].integer = IPP_JOB_PENDING; job->state_value = IPP_JOB_PENDING; + + ippSetString(job->attrs, &job->reasons, 0, "none"); } else if (job->state_value == IPP_JOB_HELD) { @@ -10815,7 +9740,11 @@ send_document(cupsd_client_t *con, /* I - Client connection */ { job->state->values[0].integer = IPP_JOB_PENDING; job->state_value = IPP_JOB_PENDING; + + ippSetString(job->attrs, &job->reasons, 0, "none"); } + else + ippSetString(job->attrs, &job->reasons, 0, "job-hold-until-specified"); } job->dirty = 1; @@ -10834,8 +9763,10 @@ send_document(cupsd_client_t *con, /* I - Client connection */ job->state->values[0].integer = IPP_JOB_HELD; job->state_value = IPP_JOB_HELD; job->hold_until = time(NULL) + MultipleOperationTimeout; - job->dirty = 1; + ippSetString(job->attrs, &job->reasons, 0, "job-incoming"); + + job->dirty = 1; cupsdMarkDirty(CUPSD_DIRTY_JOBS); } @@ -10855,7 +9786,8 @@ send_document(cupsd_client_t *con, /* I - Client connection */ ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_ENUM, "job-state", job->state_value); - add_job_state_reasons(con, job); + ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD, "job-state-reasons", + NULL, job->reasons->values[0].string.text); con->response->request.status.status_code = IPP_OK; @@ -10940,7 +9872,7 @@ send_http_error( if (auth) { if (auth->type == CUPSD_AUTH_DEFAULT) - auth_type = DefaultAuthType; + auth_type = cupsdDefaultAuthType(); else auth_type = auth->type; } @@ -11055,7 +9987,7 @@ set_default(cupsd_client_t *con, /* I - Client connection */ "%s is now the default printer.", printer->name); cupsdMarkDirty(CUPSD_DIRTY_PRINTERS | CUPSD_DIRTY_CLASSES | - CUPSD_DIRTY_REMOTE | CUPSD_DIRTY_PRINTCAP); + CUPSD_DIRTY_PRINTCAP); cupsdLogMessage(CUPSD_LOG_INFO, "Default destination set to \"%s\" by \"%s\".", @@ -11233,9 +10165,8 @@ set_job_attrs(cupsd_client_t *con, /* I - Client connection */ send_ipp_status(con, IPP_ATTRIBUTES_NOT_SETTABLE, _("%s cannot be changed."), attr->name); - if ((attr2 = copy_attribute(con->response, attr, 0)) != NULL) - attr2->group_tag = IPP_TAG_UNSUPPORTED_GROUP; - + attr2 = ippCopyAttribute(con->response, attr, 0); + ippSetGroupTag(con->response, &attr2, IPP_TAG_UNSUPPORTED_GROUP); continue; } @@ -11249,8 +10180,8 @@ set_job_attrs(cupsd_client_t *con, /* I - Client connection */ { send_ipp_status(con, IPP_REQUEST_VALUE, _("Bad job-priority value.")); - if ((attr2 = copy_attribute(con->response, attr, 0)) != NULL) - attr2->group_tag = IPP_TAG_UNSUPPORTED_GROUP; + attr2 = ippCopyAttribute(con->response, attr, 0); + ippSetGroupTag(con->response, &attr2, IPP_TAG_UNSUPPORTED_GROUP); } else if (job->state_value >= IPP_JOB_PROCESSING) { @@ -11279,8 +10210,8 @@ set_job_attrs(cupsd_client_t *con, /* I - Client connection */ { send_ipp_status(con, IPP_REQUEST_VALUE, _("Bad job-state value.")); - if ((attr2 = copy_attribute(con->response, attr, 0)) != NULL) - attr2->group_tag = IPP_TAG_UNSUPPORTED_GROUP; + attr2 = ippCopyAttribute(con->response, attr, 0); + ippSetGroupTag(con->response, &attr2, IPP_TAG_UNSUPPORTED_GROUP); } else { @@ -11354,13 +10285,13 @@ set_job_attrs(cupsd_client_t *con, /* I - Client connection */ if (job->attrs->last == attr2) job->attrs->last = job->attrs->prev; - _ippFreeAttr(attr2); + ippDeleteAttribute(NULL, attr2); /* * Then copy the attribute... */ - copy_attribute(job->attrs, attr, 0); + ippCopyAttribute(job->attrs, attr, 0); /* * See if the job-name or job-hold-until is being changed. @@ -11401,7 +10332,7 @@ set_job_attrs(cupsd_client_t *con, /* I - Client connection */ if (attr2 == job->attrs->last) job->attrs->last = job->attrs->prev; - _ippFreeAttr(attr2); + ippDeleteAttribute(NULL, attr2); event |= CUPSD_EVENT_JOB_CONFIG_CHANGED; } @@ -11412,7 +10343,7 @@ set_job_attrs(cupsd_client_t *con, /* I - Client connection */ * Add new option by copying it... */ - copy_attribute(job->attrs, attr, 0); + ippCopyAttribute(job->attrs, attr, 0); event |= CUPSD_EVENT_JOB_CONFIG_CHANGED; } @@ -11677,7 +10608,7 @@ set_printer_defaults( continue; if (strcmp(attr->values[0].string.text, "retry-current-job") && - ((printer->type & (CUPS_PRINTER_IMPLICIT | CUPS_PRINTER_CLASS)) || + ((printer->type & CUPS_PRINTER_CLASS) || (strcmp(attr->values[0].string.text, "abort-job") && strcmp(attr->values[0].string.text, "retry-job") && strcmp(attr->values[0].string.text, "stop-printer")))) @@ -11767,7 +10698,7 @@ set_printer_defaults( sprintf(value, "%dx%d%s", attr->values[0].resolution.xres, attr->values[0].resolution.yres, attr->values[0].resolution.units == IPP_RES_PER_INCH ? - "dpi" : "dpc"); + "dpi" : "dpcm"); printer->num_options = cupsAddOption(name, value, printer->num_options, &(printer->options)); @@ -12110,7 +11041,8 @@ validate_job(cupsd_client_t *con, /* I - Client connection */ http_status_t status; /* Policy status */ ipp_attribute_t *attr, /* Current attribute */ *auth_info; /* auth-info attribute */ - ipp_attribute_t *format; /* Document-format attribute */ + ipp_attribute_t *format, /* Document-format attribute */ + *name; /* Job-name attribute */ cups_ptype_t dtype; /* Destination type (printer/class) */ char super[MIME_MAX_SUPER], /* Supertype of file */ @@ -12137,7 +11069,7 @@ validate_job(cupsd_client_t *con, /* I - Client connection */ ) { send_ipp_status(con, IPP_ATTRIBUTES, - _("Unsupported compression \"%s\"."), + _("Unsupported 'compression' value \"%s\"."), attr->values[0].string.text); ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_KEYWORD, "compression", NULL, attr->values[0].string.text); @@ -12152,10 +11084,11 @@ validate_job(cupsd_client_t *con, /* I - Client connection */ if ((format = ippFindAttribute(con->request, "document-format", IPP_TAG_MIMETYPE)) != NULL) { - if (sscanf(format->values[0].string.text, "%15[^/]/%31[^;]", + if (sscanf(format->values[0].string.text, "%15[^/]/%255[^;]", super, type) != 2) { - send_ipp_status(con, IPP_BAD_REQUEST, _("Bad document-format \"%s\"."), + send_ipp_status(con, IPP_BAD_REQUEST, + _("Bad 'document-format' value \"%s\"."), format->values[0].string.text); return; } @@ -12166,7 +11099,7 @@ validate_job(cupsd_client_t *con, /* I - Client connection */ cupsdLogMessage(CUPSD_LOG_INFO, "Hint: Do you have the raw file printing rules enabled?"); send_ipp_status(con, IPP_DOCUMENT_FORMAT, - _("Unsupported document-format \"%s\"."), + _("Unsupported 'document-format' value \"%s\"."), format->values[0].string.text); ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_MIMETYPE, "document-format", NULL, format->values[0].string.text); @@ -12175,6 +11108,86 @@ validate_job(cupsd_client_t *con, /* I - Client connection */ } /* + * Is the job-name valid? + */ + + if ((name = ippFindAttribute(con->request, "job-name", IPP_TAG_ZERO)) != NULL) + { + int bad_name = 0; /* Is the job-name value bad? */ + + if ((name->value_tag != IPP_TAG_NAME && name->value_tag != IPP_TAG_NAMELANG) || + name->num_values != 1) + { + bad_name = 1; + } + else + { + /* + * Validate that job-name conforms to RFC 5198 (Network Unicode) and + * IPP Everywhere requirements for "name" values... + */ + + const unsigned char *nameptr; /* Pointer into "job-name" attribute */ + + for (nameptr = (unsigned char *)name->values[0].string.text; + *nameptr; + nameptr ++) + { + if (*nameptr < ' ' && *nameptr != '\t') + break; + else if (*nameptr == 0x7f) + break; + else if ((*nameptr & 0xe0) == 0xc0) + { + if ((nameptr[1] & 0xc0) != 0x80) + break; + + nameptr ++; + } + else if ((*nameptr & 0xf0) == 0xe0) + { + if ((nameptr[1] & 0xc0) != 0x80 || + (nameptr[2] & 0xc0) != 0x80) + break; + + nameptr += 2; + } + else if ((*nameptr & 0xf8) == 0xf0) + { + if ((nameptr[1] & 0xc0) != 0x80 || + (nameptr[2] & 0xc0) != 0x80 || + (nameptr[3] & 0xc0) != 0x80) + break; + + nameptr += 3; + } + else if (*nameptr & 0x80) + break; + } + + if (*nameptr) + bad_name = 1; + } + + if (bad_name) + { + if (StrictConformance) + { + send_ipp_status(con, IPP_ATTRIBUTES, + _("Unsupported 'job-name' value.")); + ippCopyAttribute(con->response, name, 0); + return; + } + else + { + cupsdLogMessage(CUPSD_LOG_WARN, + "Unsupported 'job-name' value, deleting from request."); + ippDeleteAttribute(con->request, name); + } + } + } + + /* * Is the destination valid? */ @@ -12299,5 +11312,5 @@ validate_user(cupsd_job_t *job, /* I - Job */ /* - * End of "$Id: ipp.c 10274 2012-02-13 20:42:51Z mike $". + * End of "$Id: ipp.c 11173 2013-07-23 12:31:34Z msweet $". */ diff --git a/scheduler/job.c b/scheduler/job.c index 92e1955..d8f56b5 100644 --- a/scheduler/job.c +++ b/scheduler/job.c @@ -1,5 +1,5 @@ /* - * "$Id: job.c 10420 2012-04-20 03:01:06Z mike $" + * "$Id: job.c 11173 2013-07-23 12:31:34Z msweet $" * * Job management routines for the CUPS scheduler. * @@ -14,54 +14,58 @@ * * Contents: * - * cupsdAddJob() - Add a new job to the job queue. - * cupsdCancelJobs() - Cancel all jobs for the given - * destination/user. - * cupsdCheckJobs() - Check the pending jobs and start any if the - * destination is available. - * cupsdCleanJobs() - Clean out old jobs. - * cupsdContinueJob() - Continue printing with the next file in a job. - * cupsdDeleteJob() - Free all memory used by a job. - * cupsdFreeAllJobs() - Free all jobs from memory. - * cupsdFindJob() - Find the specified job. - * cupsdGetPrinterJobCount() - Get the number of pending, processing, or held - * jobs in a printer or class. - * cupsdGetUserJobCount() - Get the number of pending, processing, or held - * jobs for a user. - * cupsdLoadAllJobs() - Load all jobs from disk. - * cupsdLoadJob() - Load a single job. - * cupsdMoveJob() - Move the specified job to a different - * destination. - * cupsdReleaseJob() - Release the specified job. - * cupsdRestartJob() - Restart the specified job. - * cupsdSaveAllJobs() - Save a summary of all jobs to disk. - * cupsdSaveJob() - Save a job to disk. - * cupsdSetJobHoldUntil() - Set the hold time for a job. - * cupsdSetJobPriority() - Set the priority of a job, moving it up/down - * in the list as needed. - * cupsdSetJobState() - Set the state of the specified print job. - * cupsdStopAllJobs() - Stop all print jobs. + * cupsdAddJob() - Add a new job to the job queue. + * cupsdCancelJobs() - Cancel all jobs for the given + * destination/user. + * cupsdCheckJobs() - Check the pending jobs and start any if the + * destination is available. + * cupsdCleanJobs() - Clean out old jobs. + * cupsdContinueJob() - Continue printing with the next file in a + * job. + * cupsdDeleteJob() - Free all memory used by a job. + * cupsdFreeAllJobs() - Free all jobs from memory. + * cupsdFindJob() - Find the specified job. + * cupsdGetPrinterJobCount() - Get the number of pending, processing, or + * held jobs in a printer or class. + * cupsdGetUserJobCount() - Get the number of pending, processing, or + * held jobs for a user. + * cupsdLoadAllJobs() - Load all jobs from disk. + * cupsdLoadJob() - Load a single job. + * cupsdMoveJob() - Move the specified job to a different + * destination. + * cupsdReleaseJob() - Release the specified job. + * cupsdRestartJob() - Restart the specified job. + * cupsdSaveAllJobs() - Save a summary of all jobs to disk. + * cupsdSaveJob() - Save a job to disk. + * cupsdSetJobHoldUntil() - Set the hold time for a job. + * cupsdSetJobPriority() - Set the priority of a job, moving it up/down + * in the list as needed. + * cupsdSetJobState() - Set the state of the specified print job. + * cupsdStopAllJobs() - Stop all print jobs. * cupsdUnloadCompletedJobs() - Flush completed job history from memory. - * compare_active_jobs() - Compare the job IDs and priorities of two - * jobs. - * compare_jobs() - Compare the job IDs of two jobs. - * dump_job_history() - Dump any debug messages for a job. - * free_job_history() - Free any log history. - * finalize_job() - Cleanup after job filter processes and support - * data. - * get_options() - Get a string containing the job options. - * ipp_length() - Compute the size of the buffer needed to hold - * the textual IPP attributes. - * load_job_cache() - Load jobs from the job.cache file. - * load_next_job_id() - Load the NextJobId value from the job.cache - * file. - * load_request_root() - Load jobs from the RequestRoot directory. - * set_time() - Set one of the "time-at-xyz" attributes. - * start_job() - Start a print job. - * stop_job() - Stop a print job. - * unload_job() - Unload a job from memory. - * update_job() - Read a status update from a job's filters. - * update_job_attrs() - Update the job-printer-* attributes. + * cupsdUpdateJobs() - Update the history/file files for all jobs. + * compare_active_jobs() - Compare the job IDs and priorities of two + * jobs. + * compare_jobs() - Compare the job IDs of two jobs. + * dump_job_history() - Dump any debug messages for a job. + * free_job_history() - Free any log history. + * finalize_job() - Cleanup after job filter processes and + * support data. + * get_options() - Get a string containing the job options. + * ipp_length() - Compute the size of the buffer needed to hold + * the textual IPP attributes. + * load_job_cache() - Load jobs from the job.cache file. + * load_next_job_id() - Load the NextJobId value from the job.cache + * file. + * load_request_root() - Load jobs from the RequestRoot directory. + * remove_job_files() - Remove the document files for a job. + * remove_job_history() - Remove the control file for a job. + * set_time() - Set one of the "time-at-xyz" attributes. + * start_job() - Start a print job. + * stop_job() - Stop a print job. + * unload_job() - Unload a job from memory. + * update_job() - Read a status update from a job's filters. + * update_job_attrs() - Update the job-printer-* attributes. */ /* @@ -181,6 +185,8 @@ static size_t ipp_length(ipp_t *ipp); static void load_job_cache(const char *filename); static void load_next_job_id(const char *filename); static void load_request_root(void); +static void remove_job_files(cupsd_job_t *job); +static void remove_job_history(cupsd_job_t *job); static void set_time(cupsd_job_t *job, const char *name); static void start_job(cupsd_job_t *job, cupsd_printer_t *printer); static void stop_job(cupsd_job_t *job, cupsd_jobaction_t action); @@ -281,23 +287,32 @@ cupsdCheckJobs(void) time_t curtime; /* Current time */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "cupsdCheckJobs: %d active jobs, sleeping=%d, reload=%d", - cupsArrayCount(ActiveJobs), Sleeping, NeedReload); - curtime = time(NULL); + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdCheckJobs: %d active jobs, sleeping=%d, reload=%d, " + "curtime=%ld", cupsArrayCount(ActiveJobs), Sleeping, + NeedReload, (long)curtime); + for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs); job; job = (cupsd_job_t *)cupsArrayNext(ActiveJobs)) { + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdCheckJobs: Job %d - dest=\"%s\", printer=%p, " + "state=%d, cancel_time=%ld, hold_until=%ld, kill_time=%ld, " + "pending_cost=%d, pending_timeout=%ld", job->id, job->dest, + job->printer, job->state_value, (long)job->cancel_time, + (long)job->hold_until, (long)job->kill_time, + job->pending_cost, (long)job->pending_timeout); + /* * Kill jobs if they are unresponsive... */ if (job->kill_time && job->kill_time <= curtime) { - cupsdLogMessage(CUPSD_LOG_ERROR, "[Job %d] Stopping unresponsive job!", + cupsdLogMessage(CUPSD_LOG_ERROR, "[Job %d] Stopping unresponsive job.", job->id); stop_job(job, CUPSD_JOB_FORCE); @@ -305,6 +320,17 @@ cupsdCheckJobs(void) } /* + * Cancel stuck jobs... + */ + + if (job->cancel_time && job->cancel_time <= curtime) + { + cupsdSetJobState(job, IPP_JOB_CANCELED, CUPSD_JOB_DEFAULT, + "Canceling stuck job after %d seconds.", MaxJobTime); + continue; + } + + /* * Start held jobs if they are ready... */ @@ -322,7 +348,6 @@ cupsdCheckJobs(void) cupsd_client_t *con; /* Current client connection */ - for (con = (cupsd_client_t *)cupsArrayFirst(Clients); con; con = (cupsd_client_t *)cupsArrayNext(Clients)) @@ -362,8 +387,7 @@ cupsdCheckJobs(void) printer = cupsdFindDest(job->dest); pclass = NULL; - while (printer && - (printer->type & (CUPS_PRINTER_IMPLICIT | CUPS_PRINTER_CLASS))) + while (printer && (printer->type & CUPS_PRINTER_CLASS)) { /* * If the class is remote, just pass it to the remote server... @@ -415,10 +439,7 @@ cupsdCheckJobs(void) cupsdMarkDirty(CUPSD_DIRTY_JOBS); } - if ((!(printer->type & CUPS_PRINTER_DISCOVERED) && /* Printer is local */ - printer->state == IPP_PRINTER_IDLE) || /* and idle, OR */ - ((printer->type & CUPS_PRINTER_DISCOVERED) && /* Printer is remote */ - !printer->job)) /* and not printing */ + if (!printer->job && printer->state == IPP_PRINTER_IDLE) { /* * Start the job... @@ -440,16 +461,56 @@ void cupsdCleanJobs(void) { cupsd_job_t *job; /* Current job */ + time_t curtime; /* Current time */ - if (MaxJobs <= 0 && JobHistory) + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdCleanJobs: MaxJobs=%d, JobHistory=%d, JobFiles=%d", + MaxJobs, JobHistory, JobFiles); + + if (MaxJobs <= 0 && JobHistory == INT_MAX && JobFiles == INT_MAX) return; + curtime = time(NULL); + JobHistoryUpdate = 0; + for (job = (cupsd_job_t *)cupsArrayFirst(Jobs); - job && (cupsArrayCount(Jobs) >= MaxJobs || !JobHistory); + job; job = (cupsd_job_t *)cupsArrayNext(Jobs)) + { if (job->state_value >= IPP_JOB_CANCELED && !job->printer) - cupsdDeleteJob(job, CUPSD_JOB_PURGE); + { + /* + * Expire old jobs (or job files)... + */ + + if ((MaxJobs > 0 && cupsArrayCount(Jobs) >= MaxJobs) || + (job->history_time && job->history_time <= curtime)) + { + cupsdLogJob(job, CUPSD_LOG_DEBUG, "Removing from history."); + cupsdDeleteJob(job, CUPSD_JOB_PURGE); + } + else if (job->file_time && job->file_time <= curtime) + { + cupsdLogJob(job, CUPSD_LOG_DEBUG, "Removing document files."); + remove_job_files(job); + + if (job->history_time < JobHistoryUpdate || !JobHistoryUpdate) + JobHistoryUpdate = job->history_time; + } + else + { + if (job->history_time < JobHistoryUpdate || !JobHistoryUpdate) + JobHistoryUpdate = job->history_time; + + if (job->file_time < JobHistoryUpdate || !JobHistoryUpdate) + JobHistoryUpdate = job->file_time; + } + } + } + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdCleanJobs: JobHistoryUpdate=%ld", + (long)JobHistoryUpdate); } @@ -499,7 +560,7 @@ cupsdContinueJob(cupsd_job_t *job) /* I - Job */ /* CONTENT_TYPE env variable */ device_uri[1024], /* DEVICE_URI env variable */ - final_content_type[1024], + final_content_type[1024] = "", /* FINAL_CONTENT_TYPE env variable */ lang[255], /* LANG env variable */ #ifdef __APPLE__ @@ -565,16 +626,55 @@ cupsdContinueJob(cupsd_job_t *job) /* I - Job */ if (!filters) { cupsdLogJob(job, CUPSD_LOG_ERROR, - "Unable to convert file %d to printable format!", + "Unable to convert file %d to printable format.", job->current_file); abort_message = "Aborting job because it cannot be printed."; abort_state = IPP_JOB_ABORTED; + ippSetString(job->attrs, &job->reasons, 0, "document-unprintable-error"); goto abort_job; } /* + * Figure out the final content type... + */ + + cupsdLogJob(job, CUPSD_LOG_DEBUG, "%d filters for job:", + cupsArrayCount(filters)); + for (filter = (mime_filter_t *)cupsArrayFirst(filters); + filter; + filter = (mime_filter_t *)cupsArrayNext(filters)) + cupsdLogJob(job, CUPSD_LOG_DEBUG, "%s (%s/%s to %s/%s, cost %d)", + filter->filter, + filter->src ? filter->src->super : "???", + filter->src ? filter->src->type : "???", + filter->dst ? filter->dst->super : "???", + filter->dst ? filter->dst->type : "???", + filter->cost); + + if (!job->printer->remote) + { + for (filter = (mime_filter_t *)cupsArrayLast(filters); + filter && filter->dst; + filter = (mime_filter_t *)cupsArrayPrev(filters)) + if (strcmp(filter->dst->super, "printer") || + strcmp(filter->dst->type, job->printer->name)) + break; + + if (filter && filter->dst) + { + if ((ptr = strchr(filter->dst->type, '/')) != NULL) + snprintf(final_content_type, sizeof(final_content_type), + "FINAL_CONTENT_TYPE=%s", ptr + 1); + else + snprintf(final_content_type, sizeof(final_content_type), + "FINAL_CONTENT_TYPE=%s/%s", filter->dst->super, + filter->dst->type); + } + } + + /* * Remove NULL ("-") filters... */ @@ -719,12 +819,14 @@ cupsdContinueJob(cupsd_job_t *job) /* I - Job */ if (cupsArrayCount(filters) > MAX_FILTERS) { cupsdLogJob(job, CUPSD_LOG_DEBUG, - "Too many filters (%d > %d), unable to print!", + "Too many filters (%d > %d), unable to print.", cupsArrayCount(filters), MAX_FILTERS); abort_message = "Aborting job because it needs too many filters to print."; abort_state = IPP_JOB_ABORTED; + ippSetString(job->attrs, &job->reasons, 0, "document-unprintable-error"); + goto abort_job; } @@ -738,7 +840,7 @@ cupsdContinueJob(cupsd_job_t *job) /* I - Job */ if ((job->job_sheets = ippFindAttribute(job->attrs, "job-sheets", IPP_TAG_ZERO)) != NULL) cupsdLogJob(job, CUPSD_LOG_DEBUG, - "... but someone added one without setting job_sheets!"); + "... but someone added one without setting job_sheets."); } else if (job->job_sheets->num_values == 1) cupsdLogJob(job, CUPSD_LOG_DEBUG, "job-sheets=%s", @@ -748,7 +850,7 @@ cupsdContinueJob(cupsd_job_t *job) /* I - Job */ job->job_sheets->values[0].string.text, job->job_sheets->values[1].string.text); - if (job->printer->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)) + if (job->printer->type & CUPS_PRINTER_REMOTE) banner_page = 0; else if (job->job_sheets == NULL) banner_page = 0; @@ -969,25 +1071,8 @@ cupsdContinueJob(cupsd_job_t *job) /* I - Job */ envp[envc ++] = banner_page ? "CUPS_FILETYPE=job-sheet" : "CUPS_FILETYPE=document"; - if (!job->printer->remote && !job->printer->raw) - { - filter = (mime_filter_t *)cupsArrayLast(filters); - - if (job->printer->port_monitor) - filter = (mime_filter_t *)cupsArrayPrev(filters); - - if (filter && filter->dst) - { - if ((ptr = strchr(filter->dst->type, '/')) != NULL) - snprintf(final_content_type, sizeof(final_content_type), - "FINAL_CONTENT_TYPE=%s", ptr + 1); - else - snprintf(final_content_type, sizeof(final_content_type), - "FINAL_CONTENT_TYPE=%s/%s", filter->dst->super, - filter->dst->type); - envp[envc ++] = final_content_type; - } - } + if (final_content_type[0]) + envp[envc ++] = final_content_type; if (Classification && !banner_page) { @@ -1006,7 +1091,7 @@ cupsdContinueJob(cupsd_job_t *job) /* I - Job */ envp[envc ++] = classification; } - if (job->dtype & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT)) + if (job->dtype & CUPS_PRINTER_CLASS) { snprintf(class_name, sizeof(class_name), "CLASS=%s", job->dest); envp[envc ++] = class_name; @@ -1317,25 +1402,13 @@ cupsdDeleteJob(cupsd_job_t *job, /* I - Job */ cupsd_jobaction_t action)/* I - Action */ { int i; /* Looping var */ - char filename[1024]; /* Job filename */ if (job->printer) finalize_job(job, 1); if (action == CUPSD_JOB_PURGE) - { - /* - * Remove the job info file... - */ - - snprintf(filename, sizeof(filename), "%s/c%05d", RequestRoot, - job->id); - if (Classification) - cupsdRemoveFile(filename); - else - unlink(filename); - } + remove_job_history(job); cupsdClearString(&job->username); cupsdClearString(&job->dest); @@ -1345,27 +1418,14 @@ cupsdDeleteJob(cupsd_job_t *job, /* I - Job */ cupsdClearString(job->auth_env + i); cupsdClearString(&job->auth_uid); - if (job->num_files > 0) + if (action == CUPSD_JOB_PURGE) + remove_job_files(job); + else if (job->num_files > 0) { free(job->compressions); free(job->filetypes); - if (action == CUPSD_JOB_PURGE) - { - while (job->num_files > 0) - { - snprintf(filename, sizeof(filename), "%s/d%05d-%03d", RequestRoot, - job->id, job->num_files); - if (Classification) - cupsdRemoveFile(filename); - else - unlink(filename); - - job->num_files --; - } - } - else - job->num_files = 0; + job->num_files = 0; } if (job->history) @@ -1572,7 +1632,7 @@ cupsdLoadJob(cupsd_job_t *job) /* I - Job */ if ((job->attrs = ippNew()) == NULL) { - cupsdLogJob(job, CUPSD_LOG_ERROR, "Ran out of memory for job attributes!"); + cupsdLogJob(job, CUPSD_LOG_ERROR, "Ran out of memory for job attributes."); return (0); } @@ -1583,22 +1643,8 @@ cupsdLoadJob(cupsd_job_t *job) /* I - Job */ cupsdLogMessage(CUPSD_LOG_DEBUG, "[Job %d] Loading attributes...", job->id); snprintf(jobfile, sizeof(jobfile), "%s/c%05d", RequestRoot, job->id); - if ((fp = cupsFileOpen(jobfile, "r")) == NULL) - { - char newfile[1024]; /* New job filename */ - - snprintf(newfile, sizeof(newfile), "%s/c%05d.N", RequestRoot, job->id); - if ((fp = cupsFileOpen(newfile, "r")) == NULL) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "[Job %d] Unable to open job control file \"%s\": %s", - job->id, jobfile, strerror(errno)); - goto error; - } - - unlink(jobfile); - rename(newfile, jobfile); - } + if ((fp = cupsdOpenConfFile(jobfile)) == NULL) + goto error; if (ippReadIO(fp, (ipp_iocb_t)cupsFileRead, 1, NULL, job->attrs) != IPP_DATA) { @@ -1619,7 +1665,7 @@ cupsdLoadJob(cupsd_job_t *job) /* I - Job */ { cupsdLogMessage(CUPSD_LOG_ERROR, "[Job %d] Missing or bad time-at-creation attribute in " - "control file!", job->id); + "control file.", job->id); goto error; } @@ -1628,11 +1674,40 @@ cupsdLoadJob(cupsd_job_t *job) /* I - Job */ { cupsdLogMessage(CUPSD_LOG_ERROR, "[Job %d] Missing or bad job-state attribute in control " - "file!", job->id); + "file.", job->id); goto error; } - job->state_value = (ipp_jstate_t)job->state->values[0].integer; + job->state_value = (ipp_jstate_t)job->state->values[0].integer; + job->file_time = 0; + job->history_time = 0; + + if (job->state_value >= IPP_JOB_CANCELED && + (attr = ippFindAttribute(job->attrs, "time-at-completed", + IPP_TAG_INTEGER)) != NULL) + { + if (JobHistory < INT_MAX) + job->history_time = attr->values[0].integer + JobHistory; + else + job->history_time = INT_MAX; + + if (job->history_time < time(NULL)) + goto error; /* Expired, remove from history */ + + if (job->history_time < JobHistoryUpdate || !JobHistoryUpdate) + JobHistoryUpdate = job->history_time; + + if (JobFiles < INT_MAX) + job->file_time = attr->values[0].integer + JobFiles; + else + job->file_time = INT_MAX; + + if (job->file_time < JobHistoryUpdate || !JobHistoryUpdate) + JobHistoryUpdate = job->file_time; + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdLoadJob: JobHistoryUpdate=%ld", + (long)JobHistoryUpdate); + } if (!job->dest) { @@ -1640,7 +1715,7 @@ cupsdLoadJob(cupsd_job_t *job) /* I - Job */ IPP_TAG_URI)) == NULL) { cupsdLogMessage(CUPSD_LOG_ERROR, - "[Job %d] No job-printer-uri attribute in control file!", + "[Job %d] No job-printer-uri attribute in control file.", job->id); goto error; } @@ -1649,7 +1724,7 @@ cupsdLoadJob(cupsd_job_t *job) /* I - Job */ &destptr)) == NULL) { cupsdLogMessage(CUPSD_LOG_ERROR, - "[Job %d] Unable to queue job for destination \"%s\"!", + "[Job %d] Unable to queue job for destination \"%s\".", job->id, attr->values[0].string.text); goto error; } @@ -1659,11 +1734,74 @@ cupsdLoadJob(cupsd_job_t *job) /* I - Job */ else if ((destptr = cupsdFindDest(job->dest)) == NULL) { cupsdLogMessage(CUPSD_LOG_ERROR, - "[Job %d] Unable to queue job for destination \"%s\"!", + "[Job %d] Unable to queue job for destination \"%s\".", job->id, job->dest); goto error; } + if ((job->reasons = ippFindAttribute(job->attrs, "job-state-reasons", + IPP_TAG_KEYWORD)) == NULL) + { + const char *reason; /* job-state-reason keyword */ + + cupsdLogMessage(CUPSD_LOG_DEBUG, + "[Job %d] Adding missing job-state-reasons attribute to " + " control file.", job->id); + + switch (job->state_value) + { + default : + case IPP_JOB_PENDING : + if (destptr->state == IPP_PRINTER_STOPPED) + reason = "printer-stopped"; + else + reason = "none"; + break; + + case IPP_JOB_HELD : + if ((attr = ippFindAttribute(job->attrs, "job-hold-until", + IPP_TAG_ZERO)) != NULL && + (attr->value_tag == IPP_TAG_NAME || + attr->value_tag == IPP_TAG_NAMELANG || + attr->value_tag == IPP_TAG_KEYWORD) && + strcmp(attr->values[0].string.text, "no-hold")) + reason = "job-hold-until-specified"; + else + reason = "job-incoming"; + break; + + case IPP_JOB_PROCESSING : + reason = "job-printing"; + break; + + case IPP_JOB_STOPPED : + reason = "job-stopped"; + break; + + case IPP_JOB_CANCELED : + reason = "job-canceled-by-user"; + break; + + case IPP_JOB_ABORTED : + reason = "aborted-by-system"; + break; + + case IPP_JOB_COMPLETED : + reason = "job-completed-successfully"; + break; + } + + job->reasons = ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_KEYWORD, + "job-state-reasons", NULL, reason); + } + else if (job->state_value == IPP_JOB_PENDING) + { + if (destptr->state == IPP_PRINTER_STOPPED) + ippSetString(job->attrs, &job->reasons, 0, "printer-stopped"); + else + ippSetString(job->attrs, &job->reasons, 0, "none"); + } + job->sheets = ippFindAttribute(job->attrs, "job-media-sheets-completed", IPP_TAG_INTEGER); job->job_sheets = ippFindAttribute(job->attrs, "job-sheets", IPP_TAG_NAME); @@ -1675,7 +1813,7 @@ cupsdLoadJob(cupsd_job_t *job) /* I - Job */ { cupsdLogMessage(CUPSD_LOG_ERROR, "[Job %d] Missing or bad job-priority attribute in " - "control file!", job->id); + "control file.", job->id); goto error; } @@ -1689,7 +1827,7 @@ cupsdLoadJob(cupsd_job_t *job) /* I - Job */ { cupsdLogMessage(CUPSD_LOG_ERROR, "[Job %d] Missing or bad job-originating-user-name " - "attribute in control file!", job->id); + "attribute in control file.", job->id); goto error; } @@ -1757,7 +1895,7 @@ cupsdLoadJob(cupsd_job_t *job) /* I - Job */ if (!compressions || !filetypes) { cupsdLogMessage(CUPSD_LOG_ERROR, - "[Job %d] Ran out of memory for job file types!", + "[Job %d] Ran out of memory for job file types.", job->id); ippDelete(job->attrs); @@ -1823,7 +1961,7 @@ cupsdLoadJob(cupsd_job_t *job) /* I - Job */ if (cupsFileGets(fp, line, sizeof(line)) && - !strcmp(line, "CUPSD-AUTH-V2")) + !strcmp(line, "CUPSD-AUTH-V3")) { i = 0; while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum)) @@ -1832,8 +1970,11 @@ cupsdLoadJob(cupsd_job_t *job) /* I - Job */ * Decode value... */ - bytes = sizeof(data); - httpDecode64_2(data, &bytes, value); + if (strcmp(line, "negotiate") && strcmp(line, "uid")) + { + bytes = sizeof(data); + httpDecode64_2(data, &bytes, value); + } /* * Assign environment variables... @@ -1846,7 +1987,7 @@ cupsdLoadJob(cupsd_job_t *job) /* I - Job */ } else if (i >= (int)(sizeof(job->auth_env) / sizeof(job->auth_env[0]))) break; - + if (!strcmp(line, "username")) cupsdSetStringf(job->auth_env + i, "AUTH_USERNAME=%s", data); else if (!strcmp(line, "domain")) @@ -1854,7 +1995,7 @@ cupsdLoadJob(cupsd_job_t *job) /* I - Job */ else if (!strcmp(line, "password")) cupsdSetStringf(job->auth_env + i, "AUTH_PASSWORD=%s", data); else if (!strcmp(line, "negotiate")) - cupsdSetStringf(job->auth_env + i, "AUTH_NEGOTIATE=%s", data); + cupsdSetStringf(job->auth_env + i, "AUTH_NEGOTIATE=%s", value); else continue; @@ -1878,24 +2019,8 @@ cupsdLoadJob(cupsd_job_t *job) /* I - Job */ ippDelete(job->attrs); job->attrs = NULL; - if (job->compressions) - { - free(job->compressions); - job->compressions = NULL; - } - - if (job->filetypes) - { - free(job->filetypes); - job->filetypes = NULL; - } - - job->num_files = 0; - - if (Classification) - cupsdRemoveFile(jobfile); - else - unlink(jobfile); + remove_job_history(job); + remove_job_files(job); return (0); } @@ -1945,8 +2070,7 @@ cupsdMoveJob(cupsd_job_t *job, /* I - Job */ p->name); cupsdSetString(&job->dest, p->name); - job->dtype = p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_REMOTE | - CUPS_PRINTER_IMPLICIT); + job->dtype = p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_REMOTE); if ((attr = ippFindAttribute(job->attrs, "job-printer-uri", IPP_TAG_URI)) != NULL) @@ -2069,8 +2193,7 @@ cupsdSaveAllJobs(void) void cupsdSaveJob(cupsd_job_t *job) /* I - Job */ { - char filename[1024], /* Job control filename */ - newfile[1024]; /* New job control filename */ + char filename[1024]; /* Job control filename */ cups_file_t *fp; /* Job file */ @@ -2078,17 +2201,10 @@ cupsdSaveJob(cupsd_job_t *job) /* I - Job */ job, job->id, job->attrs); snprintf(filename, sizeof(filename), "%s/c%05d", RequestRoot, job->id); - snprintf(newfile, sizeof(newfile), "%s/c%05d.N", RequestRoot, job->id); - if ((fp = cupsFileOpen(newfile, "w")) == NULL) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "[Job %d] Unable to create job control file \"%s\": %s", - job->id, newfile, strerror(errno)); + if ((fp = cupsdCreateConfFile(filename, ConfigFilePerm & 0600)) == NULL) return; - } - fchmod(cupsFileNumber(fp), 0600); fchown(cupsFileNumber(fp), RunUser, Group); job->attrs->state = IPP_IDLE; @@ -2099,23 +2215,19 @@ cupsdSaveJob(cupsd_job_t *job) /* I - Job */ cupsdLogMessage(CUPSD_LOG_ERROR, "[Job %d] Unable to write job control file.", job->id); cupsFileClose(fp); - unlink(newfile); return; } - if (cupsFileClose(fp)) - cupsdLogMessage(CUPSD_LOG_ERROR, - "[Job %d] Unable to close job control file: %s", - job->id, strerror(errno)); - else + if (!cupsdCloseCreatedConfFile(fp, filename)) { + /* + * Remove backup file and mark this job as clean... + */ + + strlcat(filename, ".O", sizeof(filename)); unlink(filename); - if (rename(newfile, filename)) - cupsdLogMessage(CUPSD_LOG_ERROR, - "[Job %d] Unable to finalize job control file: %s", - job->id, strerror(errno)); - else - job->dirty = 0; + + job->dirty = 0; } } @@ -2168,12 +2280,16 @@ cupsdSetJobHoldUntil(cupsd_job_t *job, /* I - Job */ job->dirty = 1; cupsdMarkDirty(CUPSD_DIRTY_JOBS); } + + ippSetString(job->attrs, &job->reasons, 0, "job-hold-until-specified"); } /* * Update the hold time... */ + job->cancel_time = 0; + if (!strcmp(when, "indefinite") || !strcmp(when, "auth-info-required")) { /* @@ -2181,6 +2297,9 @@ cupsdSetJobHoldUntil(cupsd_job_t *job, /* I - Job */ */ job->hold_until = 0; + + if (MaxHoldTime > 0) + job->cancel_time = time(NULL) + MaxHoldTime; } else if (!strcmp(when, "day-time")) { @@ -2382,8 +2501,10 @@ cupsdSetJobState( * Set the new job state... */ - job->state->values[0].integer = newstate; - job->state_value = newstate; + job->state_value = newstate; + + if (job->state) + job->state->values[0].integer = newstate; switch (newstate) { @@ -2409,6 +2530,7 @@ cupsdSetJobState( case IPP_JOB_CANCELED : case IPP_JOB_COMPLETED : set_time(job, "time-at-completed"); + ippSetString(job->attrs, &job->reasons, 0, "processing-to-stop-point"); break; } @@ -2537,27 +2659,7 @@ cupsdSetJobState( */ if (!JobHistory || !JobFiles || action == CUPSD_JOB_PURGE) - { - for (i = 1; i <= job->num_files; i ++) - { - snprintf(filename, sizeof(filename), "%s/d%05d-%03d", RequestRoot, - job->id, i); - if (Classification) - cupsdRemoveFile(filename); - else - unlink(filename); - } - - if (job->num_files > 0) - { - free(job->filetypes); - free(job->compressions); - - job->num_files = 0; - job->filetypes = NULL; - job->compressions = NULL; - } - } + remove_job_files(job); if (JobHistory && action != CUPSD_JOB_PURGE) { @@ -2649,6 +2751,62 @@ cupsdUnloadCompletedJobs(void) /* + * 'cupsdUpdateJobs()' - Update the history/file files for all jobs. + */ + +void +cupsdUpdateJobs(void) +{ + cupsd_job_t *job; /* Current job */ + time_t curtime; /* Current time */ + ipp_attribute_t *attr; /* time-at-completed attribute */ + + + curtime = time(NULL); + JobHistoryUpdate = 0; + + for (job = (cupsd_job_t *)cupsArrayFirst(Jobs); + job; + job = (cupsd_job_t *)cupsArrayNext(Jobs)) + { + if (job->state_value >= IPP_JOB_CANCELED && + (attr = ippFindAttribute(job->attrs, "time-at-completed", + IPP_TAG_INTEGER)) != NULL) + { + /* + * Update history/file expiration times... + */ + + if (JobHistory < INT_MAX) + job->history_time = attr->values[0].integer + JobHistory; + else + job->history_time = INT_MAX; + + if (job->history_time < curtime) + { + cupsdDeleteJob(job, CUPSD_JOB_PURGE); + continue; + } + + if (job->history_time < JobHistoryUpdate || !JobHistoryUpdate) + JobHistoryUpdate = job->history_time; + + if (JobFiles < INT_MAX) + job->file_time = attr->values[0].integer + JobFiles; + else + job->file_time = INT_MAX; + + if (job->file_time < JobHistoryUpdate || !JobHistoryUpdate) + JobHistoryUpdate = job->file_time; + } + } + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdUpdateAllJobs: JobHistoryUpdate=%ld", + (long)JobHistoryUpdate); +} + + +/* * 'compare_active_jobs()' - Compare the job IDs and priorities of two jobs. */ @@ -2854,7 +3012,8 @@ finalize_job(cupsd_job_t *job, /* I - Job */ * rarely have current information for network devices... */ - if (strncmp(job->printer->device_uri, "usb:", 4)) + if (strncmp(job->printer->device_uri, "usb:", 4) && + strncmp(job->printer->device_uri, "ippusb:", 7)) cupsdSetPrinterReasons(job->printer, "-offline-report"); /* @@ -2865,10 +3024,11 @@ finalize_job(cupsd_job_t *job, /* I - Job */ job->profile = NULL; /* - * Clear the unresponsive job watchdog timer... + * Clear the unresponsive job watchdog timers... */ - job->kill_time = 0; + job->cancel_time = 0; + job->kill_time = 0; /* * Close pipes and status buffer... @@ -2907,14 +3067,21 @@ finalize_job(cupsd_job_t *job, /* I - Job */ case IPP_JOB_COMPLETED : job_state = IPP_JOB_COMPLETED; message = "Job completed."; + + ippSetString(job->attrs, &job->reasons, 0, + "job-completed-successfully"); break; case IPP_JOB_STOPPED : message = "Job stopped."; + + ippSetString(job->attrs, &job->reasons, 0, "job-stopped"); break; case IPP_JOB_CANCELED : message = "Job canceled."; + + ippSetString(job->attrs, &job->reasons, 0, "job-canceled-by-user"); break; case IPP_JOB_ABORTED : @@ -2940,7 +3107,10 @@ finalize_job(cupsd_job_t *job, /* I - Job */ if (WIFEXITED(exit_code)) exit_code = WEXITSTATUS(exit_code); else + { + ippSetString(job->attrs, &job->reasons, 0, "cups-backend-crashed"); exit_code = job->status; + } cupsdLogJob(job, CUPSD_LOG_INFO, "Backend returned status %d (%s)", exit_code, @@ -2950,6 +3120,8 @@ finalize_job(cupsd_job_t *job, /* I - Job */ exit_code == CUPS_BACKEND_HOLD ? "hold job" : exit_code == CUPS_BACKEND_STOP ? "stop printer" : exit_code == CUPS_BACKEND_CANCEL ? "cancel job" : + exit_code == CUPS_BACKEND_RETRY ? "retry job later" : + exit_code == CUPS_BACKEND_RETRY_CURRENT ? "retry job immediately" : exit_code < 0 ? "crashed" : "unknown"); /* @@ -2965,7 +3137,7 @@ finalize_job(cupsd_job_t *job, /* I - Job */ * act... */ - if (job->dtype & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT)) + if (job->dtype & CUPS_PRINTER_CLASS) { /* * Queued on a class - mark the job as pending and we'll retry on @@ -2976,6 +3148,9 @@ finalize_job(cupsd_job_t *job, /* I - Job */ { job_state = IPP_JOB_PENDING; message = "Retrying job on another printer."; + + ippSetString(job->attrs, &job->reasons, 0, + "resources-are-not-ready"); } } else if (!strcmp(job->printer->error_policy, "retry-current-job")) @@ -2989,6 +3164,8 @@ finalize_job(cupsd_job_t *job, /* I - Job */ { job_state = IPP_JOB_PENDING; message = "Retrying job on same printer."; + + ippSetString(job->attrs, &job->reasons, 0, "none"); } } else if ((job->printer->type & CUPS_PRINTER_FAX) || @@ -3015,6 +3192,8 @@ finalize_job(cupsd_job_t *job, /* I - Job */ JobRetryLimit); job_state = IPP_JOB_ABORTED; message = buffer; + + ippSetString(job->attrs, &job->reasons, 0, "aborted-by-system"); } else { @@ -3029,6 +3208,9 @@ finalize_job(cupsd_job_t *job, /* I - Job */ job->hold_until = time(NULL) + JobRetryInterval; job_state = IPP_JOB_HELD; message = buffer; + + ippSetString(job->attrs, &job->reasons, 0, + "resources-are-not-ready"); } } } @@ -3038,6 +3220,8 @@ finalize_job(cupsd_job_t *job, /* I - Job */ job_state = IPP_JOB_ABORTED; message = "Job aborted due to backend errors; please consult " "the error_log file for details."; + + ippSetString(job->attrs, &job->reasons, 0, "aborted-by-system"); } else if (job->state_value == IPP_JOB_PROCESSING) { @@ -3045,19 +3229,22 @@ finalize_job(cupsd_job_t *job, /* I - Job */ printer_state = IPP_PRINTER_STOPPED; message = "Printer stopped due to backend errors; please " "consult the error_log file for details."; + + ippSetString(job->attrs, &job->reasons, 0, "none"); } break; case CUPS_BACKEND_CANCEL : /* - * Abort the job... + * Cancel the job... */ if (job_state == IPP_JOB_COMPLETED) { - job_state = IPP_JOB_ABORTED; - message = "Job aborted due to backend errors; please consult " - "the error_log file for details."; + job_state = IPP_JOB_CANCELED; + message = "Job canceled at printer."; + + ippSetString(job->attrs, &job->reasons, 0, "canceled-at-device"); } break; @@ -3069,6 +3256,8 @@ finalize_job(cupsd_job_t *job, /* I - Job */ */ cupsdSetJobHoldUntil(job, "indefinite", 1); + ippSetString(job->attrs, &job->reasons, 0, + "job-hold-until-specified"); job_state = IPP_JOB_HELD; message = "Job held indefinitely due to backend errors; please " @@ -3086,7 +3275,12 @@ finalize_job(cupsd_job_t *job, /* I - Job */ "consult the error_log file for details."; if (job_state == IPP_JOB_COMPLETED) + { job_state = IPP_JOB_PENDING; + + ippSetString(job->attrs, &job->reasons, 0, + "resources-are-not-ready"); + } break; case CUPS_BACKEND_AUTH_REQUIRED : @@ -3100,6 +3294,9 @@ finalize_job(cupsd_job_t *job, /* I - Job */ job_state = IPP_JOB_HELD; message = "Job held for authentication."; + + ippSetString(job->attrs, &job->reasons, 0, + "cups-held-for-authentication"); } break; @@ -3124,6 +3321,8 @@ finalize_job(cupsd_job_t *job, /* I - Job */ JobRetryLimit); job_state = IPP_JOB_ABORTED; message = buffer; + + ippSetString(job->attrs, &job->reasons, 0, "aborted-by-system"); } else { @@ -3138,6 +3337,9 @@ finalize_job(cupsd_job_t *job, /* I - Job */ job->hold_until = time(NULL) + JobRetryInterval; job_state = IPP_JOB_HELD; message = buffer; + + ippSetString(job->attrs, &job->reasons, 0, + "resources-are-not-ready"); } } break; @@ -3151,6 +3353,8 @@ finalize_job(cupsd_job_t *job, /* I - Job */ { job_state = IPP_JOB_PENDING; message = "Retrying job on same printer."; + + ippSetString(job->attrs, &job->reasons, 0, "none"); } break; } @@ -3166,6 +3370,11 @@ finalize_job(cupsd_job_t *job, /* I - Job */ job_state = IPP_JOB_STOPPED; message = "Job stopped due to filter errors; please consult the " "error_log file for details."; + + if (WIFSIGNALED(job->status)) + ippSetString(job->attrs, &job->reasons, 0, "cups-filter-crashed"); + else + ippSetString(job->attrs, &job->reasons, 0, "job-completed-with-errors"); } } @@ -3193,6 +3402,21 @@ finalize_job(cupsd_job_t *job, /* I - Job */ cupsArrayRemove(PrintingJobs, job); /* + * Apply any PPD updates... + */ + + if (job->num_keywords) + { + if (cupsdUpdatePrinterPPD(job->printer, job->num_keywords, job->keywords)) + cupsdSetPrinterAttrs(job->printer); + + cupsFreeOptions(job->num_keywords, job->keywords); + + job->num_keywords = 0; + job->keywords = NULL; + } + + /* * Clear the printer <-> job association... */ @@ -3409,7 +3633,7 @@ get_options(cupsd_job_t *job, /* I - Job */ if (!optptr) { cupsdLogJob(job, CUPSD_LOG_CRIT, - "Unable to allocate " CUPS_LLFMT " bytes for option buffer!", + "Unable to allocate " CUPS_LLFMT " bytes for option buffer.", CUPS_LLCAST newlength); return (NULL); } @@ -3460,7 +3684,13 @@ get_options(cupsd_job_t *job, /* I - Job */ attr->value_tag == IPP_TAG_BEGIN_COLLECTION) /* Not yet supported */ continue; - if (!strcmp(attr->name, "job-hold-until")) + if (!strcmp(attr->name, "job-hold-until") || + !strcmp(attr->name, "job-id") || + !strcmp(attr->name, "job-k-octets") || + !strcmp(attr->name, "job-media-sheets") || + !strcmp(attr->name, "job-media-sheets-completed") || + !strcmp(attr->name, "job-state") || + !strcmp(attr->name, "job-state-reasons")) continue; if (!strncmp(attr->name, "job-", 4) && @@ -3537,7 +3767,7 @@ get_options(cupsd_job_t *job, /* I - Job */ "%dx%d%s", attr->values[i].resolution.xres, attr->values[i].resolution.yres, attr->values[i].resolution.units == IPP_RES_PER_INCH ? - "dpi" : "dpc"); + "dpi" : "dpcm"); break; case IPP_TAG_STRING : @@ -3758,14 +3988,14 @@ load_job_cache(const char *filename) /* I - job.cache filename */ { if (job) { - cupsdLogMessage(CUPSD_LOG_ERROR, "Missing </Job> directive on line %d!", + cupsdLogMessage(CUPSD_LOG_ERROR, "Missing </Job> directive on line %d.", linenum); continue; } if (!value) { - cupsdLogMessage(CUPSD_LOG_ERROR, "Missing job ID on line %d!", linenum); + cupsdLogMessage(CUPSD_LOG_ERROR, "Missing job ID on line %d.", linenum); continue; } @@ -3773,7 +4003,7 @@ load_job_cache(const char *filename) /* I - job.cache filename */ if (jobid < 1) { - cupsdLogMessage(CUPSD_LOG_ERROR, "Bad job ID %d on line %d!", jobid, + cupsdLogMessage(CUPSD_LOG_ERROR, "Bad job ID %d on line %d.", jobid, linenum); continue; } @@ -3784,7 +4014,7 @@ load_job_cache(const char *filename) /* I - job.cache filename */ snprintf(jobfile, sizeof(jobfile), "%s/c%05d.N", RequestRoot, jobid); if (access(jobfile, 0)) { - cupsdLogMessage(CUPSD_LOG_ERROR, "[Job %d] Files have gone away!", + cupsdLogMessage(CUPSD_LOG_ERROR, "[Job %d] Files have gone away.", jobid); continue; } @@ -3794,7 +4024,7 @@ load_job_cache(const char *filename) /* I - job.cache filename */ if (!job) { cupsdLogMessage(CUPSD_LOG_EMERG, - "[Job %d] Unable to allocate memory for job!", jobid); + "[Job %d] Unable to allocate memory for job.", jobid); break; } @@ -3814,7 +4044,7 @@ load_job_cache(const char *filename) /* I - job.cache filename */ else if (!job) { cupsdLogMessage(CUPSD_LOG_ERROR, - "Missing <Job #> directive on line %d!", linenum); + "Missing <Job #> directive on line %d.", linenum); continue; } else if (!_cups_strcasecmp(line, "</Job>")) @@ -3828,7 +4058,7 @@ load_job_cache(const char *filename) /* I - job.cache filename */ } else if (!value) { - cupsdLogMessage(CUPSD_LOG_ERROR, "Missing value on line %d!", linenum); + cupsdLogMessage(CUPSD_LOG_ERROR, "Missing value on line %d.", linenum); continue; } else if (!_cups_strcasecmp(line, "State")) @@ -3866,7 +4096,7 @@ load_job_cache(const char *filename) /* I - job.cache filename */ if (job->num_files < 0) { - cupsdLogMessage(CUPSD_LOG_ERROR, "Bad NumFiles value %d on line %d!", + cupsdLogMessage(CUPSD_LOG_ERROR, "Bad NumFiles value %d on line %d.", job->num_files, linenum); job->num_files = 0; continue; @@ -3878,7 +4108,7 @@ load_job_cache(const char *filename) /* I - job.cache filename */ job->id); if (access(jobfile, 0)) { - cupsdLogMessage(CUPSD_LOG_INFO, "[Job %d] Data files have gone away!", + cupsdLogMessage(CUPSD_LOG_INFO, "[Job %d] Data files have gone away.", job->id); job->num_files = 0; continue; @@ -3890,7 +4120,7 @@ load_job_cache(const char *filename) /* I - job.cache filename */ if (!job->filetypes || !job->compressions) { cupsdLogMessage(CUPSD_LOG_EMERG, - "[Job %d] Unable to allocate memory for %d files!", + "[Job %d] Unable to allocate memory for %d files.", job->id, job->num_files); break; } @@ -3907,13 +4137,13 @@ load_job_cache(const char *filename) /* I - job.cache filename */ if (sscanf(value, "%d%*[ \t]%15[^/]/%255s%d", &number, super, type, &compression) != 4) { - cupsdLogMessage(CUPSD_LOG_ERROR, "Bad File on line %d!", linenum); + cupsdLogMessage(CUPSD_LOG_ERROR, "Bad File on line %d.", linenum); continue; } if (number < 1 || number > job->num_files) { - cupsdLogMessage(CUPSD_LOG_ERROR, "Bad File number %d on line %d!", + cupsdLogMessage(CUPSD_LOG_ERROR, "Bad File number %d on line %d.", number, linenum); continue; } @@ -3930,7 +4160,7 @@ load_job_cache(const char *filename) /* I - job.cache filename */ */ cupsdLogMessage(CUPSD_LOG_ERROR, - "[Job %d] Unknown MIME type %s/%s for file %d!", + "[Job %d] Unknown MIME type %s/%s for file %d.", job->id, super, type, number + 1); snprintf(jobfile, sizeof(jobfile), "%s/d%05d-%03d", RequestRoot, @@ -3948,7 +4178,7 @@ load_job_cache(const char *filename) /* I - job.cache filename */ } } else - cupsdLogMessage(CUPSD_LOG_ERROR, "Unknown %s directive on line %d!", + cupsdLogMessage(CUPSD_LOG_ERROR, "Unknown %s directive on line %d.", line, linenum); } @@ -4048,7 +4278,7 @@ load_request_root(void) if ((job = calloc(sizeof(cupsd_job_t), 1)) == NULL) { - cupsdLogMessage(CUPSD_LOG_ERROR, "Ran out of memory for jobs!"); + cupsdLogMessage(CUPSD_LOG_ERROR, "Ran out of memory for jobs."); cupsDirClose(dir); return; } @@ -4087,6 +4317,8 @@ load_request_root(void) else unload_job(job); } + else + free(job); } cupsDirClose(dir); @@ -4094,6 +4326,67 @@ load_request_root(void) /* + * 'remove_job_files()' - Remove the document files for a job. + */ + +static void +remove_job_files(cupsd_job_t *job) /* I - Job */ +{ + int i; /* Looping var */ + char filename[1024]; /* Document filename */ + + + if (job->num_files <= 0) + return; + + for (i = 1; i <= job->num_files; i ++) + { + snprintf(filename, sizeof(filename), "%s/d%05d-%03d", RequestRoot, + job->id, i); + if (Classification) + cupsdRemoveFile(filename); + else + unlink(filename); + } + + free(job->filetypes); + free(job->compressions); + + job->file_time = 0; + job->num_files = 0; + job->filetypes = NULL; + job->compressions = NULL; + + LastEvent |= CUPSD_EVENT_PRINTER_STATE_CHANGED; +} + + +/* + * 'remove_job_history()' - Remove the control file for a job. + */ + +static void +remove_job_history(cupsd_job_t *job) /* I - Job */ +{ + char filename[1024]; /* Control filename */ + + + /* + * Remove the job info file... + */ + + snprintf(filename, sizeof(filename), "%s/c%05d", RequestRoot, + job->id); + if (Classification) + cupsdRemoveFile(filename); + else + unlink(filename); + + LastEvent |= CUPSD_EVENT_PRINTER_STATE_CHANGED; +} + + +/* * 'set_time()' - Set one of the "time-at-xyz" attributes. */ @@ -4102,12 +4395,39 @@ set_time(cupsd_job_t *job, /* I - Job to update */ const char *name) /* I - Name of attribute */ { ipp_attribute_t *attr; /* Time attribute */ + time_t curtime; /* Current time */ + curtime = time(NULL); + + cupsdLogJob(job, CUPSD_LOG_DEBUG, "%s=%ld", name, (long)curtime); + if ((attr = ippFindAttribute(job->attrs, name, IPP_TAG_ZERO)) != NULL) { attr->value_tag = IPP_TAG_INTEGER; - attr->values[0].integer = time(NULL); + attr->values[0].integer = curtime; + } + + if (!strcmp(name, "time-at-completed")) + { + if (JobHistory < INT_MAX && attr) + job->history_time = attr->values[0].integer + JobHistory; + else + job->history_time = INT_MAX; + + if (job->history_time < JobHistoryUpdate || !JobHistoryUpdate) + JobHistoryUpdate = job->history_time; + + if (JobFiles < INT_MAX && attr) + job->file_time = attr->values[0].integer + JobFiles; + else + job->file_time = INT_MAX; + + if (job->file_time < JobHistoryUpdate || !JobHistoryUpdate) + JobHistoryUpdate = job->file_time; + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "set_time: JobHistoryUpdate=%ld", + (long)JobHistoryUpdate); } } @@ -4129,6 +4449,7 @@ start_job(cupsd_job_t *job, /* I - Job ID */ if (job->num_files == 0) { + ippSetString(job->attrs, &job->reasons, 0, "aborted-by-system"); cupsdSetJobState(job, IPP_JOB_ABORTED, CUPSD_JOB_DEFAULT, "Aborting job because it has no files."); return; @@ -4148,6 +4469,7 @@ start_job(cupsd_job_t *job, /* I - Job ID */ if (job->printer_message) cupsdSetString(&(job->printer_message->values[0].string.text), ""); + ippSetString(job->attrs, &job->reasons, 0, "job-printing"); cupsdSetJobState(job, IPP_JOB_PROCESSING, CUPSD_JOB_DEFAULT, NULL); cupsdSetPrinterState(printer, IPP_PRINTER_PROCESSING, 0); cupsdSetPrinterReasons(printer, "-cups-remote-pending," @@ -4160,10 +4482,17 @@ start_job(cupsd_job_t *job, /* I - Job ID */ job->cost = 0; job->current_file = 0; + job->file_time = 0; + job->history_time = 0; job->progress = 0; job->printer = printer; printer->job = job; + if (MaxJobTime > 0) + job->cancel_time = time(NULL) + MaxJobTime; + else + job->cancel_time = 0; + /* * Setup the last exit status and security profiles... */ @@ -4327,6 +4656,7 @@ unload_job(cupsd_job_t *job) /* I - Job */ job->attrs = NULL; job->state = NULL; + job->reasons = NULL; job->sheets = NULL; job->job_sheets = NULL; job->printer_message = NULL; @@ -4420,9 +4750,25 @@ update_job(cupsd_job_t *job) /* I - Job to check */ cupsdStopPrinter(job->printer, 1); return; } - else if (cupsdSetPrinterReasons(job->printer, message)) + else if (message[0] && cupsdSetPrinterReasons(job->printer, message)) + { event |= CUPSD_EVENT_PRINTER_STATE; + if (MaxJobTime > 0 && strstr(message, "connecting-to-device") != NULL) + { + /* + * Reset cancel time after connecting to the device... + */ + + for (i = 0; i < job->printer->num_reasons; i ++) + if (!strcmp(job->printer->reasons[i], "connecting-to-device")) + break; + + if (i >= job->printer->num_reasons) + job->cancel_time = time(NULL) + MaxJobTime; + } + } + update_job_attrs(job, 0); } else if (loglevel == CUPSD_LOG_ATTR) @@ -4446,10 +4792,7 @@ update_job(cupsd_job_t *job) /* I - Job to check */ cupsdSetAuthInfoRequired(job->printer, attr, NULL); cupsdSetPrinterAttrs(job->printer); - if (job->printer->type & CUPS_PRINTER_DISCOVERED) - cupsdMarkDirty(CUPSD_DIRTY_REMOTE); - else - cupsdMarkDirty(CUPSD_DIRTY_PRINTERS); + cupsdMarkDirty(CUPSD_DIRTY_PRINTERS); } if ((attr = cupsGetOption("job-media-progress", num_attrs, @@ -4546,18 +4889,10 @@ update_job(cupsd_job_t *job) /* I - Job to check */ * Set attribute(s)... */ - int num_keywords; /* Number of keywords */ - cups_option_t *keywords; /* Keywords */ - - cupsdLogJob(job, CUPSD_LOG_DEBUG, "PPD: %s", message); - num_keywords = cupsParseOptions(message, 0, &keywords); - - if (cupsdUpdatePrinterPPD(job->printer, num_keywords, keywords)) - cupsdSetPrinterAttrs(job->printer); - - cupsFreeOptions(num_keywords, keywords); + job->num_keywords = cupsParseOptions(message, job->num_keywords, + &job->keywords); } else { @@ -4580,7 +4915,8 @@ update_job(cupsd_job_t *job) /* I - Job to check */ else ptr = message; - cupsdLogJob(job, loglevel, "%s", ptr); + if (*ptr) + cupsdLogJob(job, loglevel, "%s", ptr); if (loglevel < CUPSD_LOG_DEBUG && strcmp(job->printer->state_message, ptr)) @@ -4708,11 +5044,21 @@ update_job_attrs(cupsd_job_t *job, /* I - Job to update */ if (job->state_value != IPP_JOB_PROCESSING && job->status_level == CUPSD_LOG_INFO) + { cupsdSetString(&(job->printer_message->values[0].string.text), ""); + + job->dirty = 1; + cupsdMarkDirty(CUPSD_DIRTY_JOBS); + } else if (job->printer->state_message[0] && do_message) + { cupsdSetString(&(job->printer_message->values[0].string.text), job->printer->state_message); + job->dirty = 1; + cupsdMarkDirty(CUPSD_DIRTY_JOBS); + } + /* * ... and the printer-state-reasons value... */ @@ -4768,9 +5114,12 @@ update_job_attrs(cupsd_job_t *job, /* I - Job to update */ for (i = 0; i < num_reasons; i ++) job->printer_reasons->values[i].string.text = _cupsStrAlloc(reasons[i]); + + job->dirty = 1; + cupsdMarkDirty(CUPSD_DIRTY_JOBS); } /* - * End of "$Id: job.c 10420 2012-04-20 03:01:06Z mike $". + * End of "$Id: job.c 11173 2013-07-23 12:31:34Z msweet $". */ diff --git a/scheduler/job.h b/scheduler/job.h index 130326f..6fb5ab8 100644 --- a/scheduler/job.h +++ b/scheduler/job.h @@ -1,5 +1,5 @@ /* - * "$Id: job.h 9778 2011-05-18 02:27:11Z mike $" + * "$Id: job.h 11173 2013-07-23 12:31:34Z msweet $" * * Print job definitions for the CUPS scheduler. * @@ -46,9 +46,13 @@ struct cupsd_job_s /**** Job request ****/ int *compressions; /* Compression status of each file */ ipp_attribute_t *sheets; /* job-media-sheets-completed */ time_t access_time, /* Last access time */ - kill_time, /* When to send SIGKILL */ - hold_until; /* Hold expiration date/time */ + cancel_time, /* When to cancel/send SIGTERM */ + file_time, /* Job file retain time */ + history_time, /* Job history retain time */ + hold_until, /* Hold expiration date/time */ + kill_time; /* When to send SIGKILL */ ipp_attribute_t *state; /* Job state */ + ipp_attribute_t *reasons; /* Job state reasons */ ipp_attribute_t *job_sheets; /* Job sheets (NULL if none) */ ipp_attribute_t *printer_message, /* job-printer-state-message */ @@ -76,6 +80,8 @@ struct cupsd_job_s /**** Job request ****/ void *profile; /* Security profile */ cups_array_t *history; /* Debug log history */ int progress; /* Printing progress */ + int num_keywords; /* Number of PPD keywords */ + cups_option_t *keywords; /* PPD keywords */ }; typedef struct cupsd_joblog_s /**** Job log message ****/ @@ -89,18 +95,24 @@ typedef struct cupsd_joblog_s /**** Job log message ****/ * Globals... */ -VAR int JobHistory VALUE(1); +VAR int JobHistory VALUE(INT_MAX); /* Preserve job history? */ -VAR int JobFiles VALUE(0); +VAR int JobFiles VALUE(86400); /* Preserve job files? */ +VAR time_t JobHistoryUpdate VALUE(0); + /* Time for next job history update */ VAR int MaxJobs VALUE(0), /* Max number of jobs */ MaxActiveJobs VALUE(0), /* Max number of active jobs */ + MaxHoldTime VALUE(0), + /* Max time for indefinite hold */ MaxJobsPerUser VALUE(0), /* Max jobs per user */ - MaxJobsPerPrinter VALUE(0); + MaxJobsPerPrinter VALUE(0), /* Max jobs per printer */ + MaxJobTime VALUE(3 * 60 * 60); + /* Max time for a job */ VAR int JobAutoPurge VALUE(0); /* Automatically purge jobs */ VAR cups_array_t *Jobs VALUE(NULL), @@ -149,16 +161,15 @@ extern void cupsdSetJobState(cupsd_job_t *job, ipp_jstate_t newstate, cupsd_jobaction_t action, const char *message, ...) -#ifdef __GNUC__ -__attribute__ ((__format__ (__printf__, 4, 5))) -#endif /* __GNUC__ */ -; + __attribute__((__format__(__printf__, + 4, 5))); extern void cupsdStopAllJobs(cupsd_jobaction_t action, int kill_delay); extern int cupsdTimeoutJob(cupsd_job_t *job); extern void cupsdUnloadCompletedJobs(void); +extern void cupsdUpdateJobs(void); /* - * End of "$Id: job.h 9778 2011-05-18 02:27:11Z mike $". + * End of "$Id: job.h 11173 2013-07-23 12:31:34Z msweet $". */ diff --git a/scheduler/listen.c b/scheduler/listen.c index ce7a26d..a4c19c0 100644 --- a/scheduler/listen.c +++ b/scheduler/listen.c @@ -1,5 +1,5 @@ /* - * "$Id: listen.c 9691 2011-04-15 23:38:13Z mike $" + * "$Id: listen.c 11173 2013-07-23 12:31:34Z msweet $" * * Server listening routines for the CUPS scheduler. * @@ -427,5 +427,5 @@ cupsdStopListening(void) /* - * End of "$Id: listen.c 9691 2011-04-15 23:38:13Z mike $". + * End of "$Id: listen.c 11173 2013-07-23 12:31:34Z msweet $". */ diff --git a/scheduler/log.c b/scheduler/log.c index 11d180e..d739b58 100644 --- a/scheduler/log.c +++ b/scheduler/log.c @@ -1,5 +1,5 @@ /* - * "$Id: log.c 9949 2011-08-31 04:58:33Z mike $" + * "$Id: log.c 11173 2013-07-23 12:31:34Z msweet $" * * Log file routines for the CUPS scheduler. * @@ -41,6 +41,22 @@ static int log_linesize = 0; /* Size of line for output file */ static char *log_line = NULL; /* Line for output file */ +#ifdef HAVE_VSYSLOG +static const int syslevels[] = /* SYSLOG levels... */ + { + 0, + LOG_EMERG, + LOG_ALERT, + LOG_CRIT, + LOG_ERR, + LOG_WARNING, + LOG_NOTICE, + LOG_INFO, + LOG_DEBUG, + LOG_DEBUG + }; +#endif /* HAVE_VSYSLOG */ + /* * Local functions... @@ -379,7 +395,23 @@ cupsdLogGSSMessage( minor_status_string = GSS_C_EMPTY_BUFFER; /* Minor status message */ int ret; /* Return value */ + char buffer[8192]; /* Buffer for vsnprintf */ + + + if (strchr(message, '%')) + { + /* + * Format the message string... + */ + va_list ap; /* Pointer to arguments */ + + va_start(ap, message); + vsnprintf(buffer, sizeof(buffer), message, ap); + va_end(ap); + + message = buffer; + } msg_ctx = 0; err_major_status = gss_display_status(&err_minor_status, @@ -414,7 +446,7 @@ cupsdLogJob(cupsd_job_t *job, /* I - Job */ const char *message, /* I - Printf-style message string */ ...) /* I - Additional arguments as needed */ { - va_list ap; /* Argument pointer */ + va_list ap, ap2; /* Argument pointers */ char jobmsg[1024]; /* Format string for job message */ int status; /* Formatting status */ @@ -435,19 +467,27 @@ cupsdLogJob(cupsd_job_t *job, /* I - Job */ * Format and write the log message... */ - snprintf(jobmsg, sizeof(jobmsg), "[Job %d] %s", job->id, message); + if (job) + snprintf(jobmsg, sizeof(jobmsg), "[Job %d] %s", job->id, message); + else + strlcpy(jobmsg, message, sizeof(jobmsg)); + + va_start(ap, message); do { - va_start(ap, message); - status = format_log_line(jobmsg, ap); - va_end(ap); + va_copy(ap2, ap); + status = format_log_line(jobmsg, ap2); + va_end(ap2); } while (status == 0); + va_end(ap); + if (status > 0) { - if ((level > LogLevel || + if (job && + (level > LogLevel || (level == CUPSD_LOG_INFO && LogLevel < CUPSD_LOG_DEBUG)) && LogDebugHistory > 0) { @@ -508,7 +548,7 @@ cupsdLogMessage(int level, /* I - Log level */ const char *message, /* I - printf-style message string */ ...) /* I - Additional args as needed */ { - va_list ap; /* Argument pointer */ + va_list ap, ap2; /* Argument pointers */ int status; /* Formatting status */ @@ -519,8 +559,12 @@ cupsdLogMessage(int level, /* I - Log level */ if ((TestConfigFile || !ErrorLog) && level <= CUPSD_LOG_WARN) { va_start(ap, message); +#ifdef HAVE_VSYSLOG + vsyslog(LOG_LPR | syslevels[level], message, ap); +#else vfprintf(stderr, message, ap); putc('\n', stderr); +#endif /* HAVE_VSYSLOG */ va_end(ap); return (1); @@ -533,14 +577,18 @@ cupsdLogMessage(int level, /* I - Log level */ * Format and write the log message... */ + va_start(ap, message); + do { - va_start(ap, message); - status = format_log_line(message, ap); - va_end(ap); + va_copy(ap2, ap); + status = format_log_line(message, ap2); + va_end(ap2); } while (status == 0); + va_end(ap); + if (status > 0) return (cupsdWriteErrorLog(level, log_line)); else @@ -956,21 +1004,6 @@ cupsdWriteErrorLog(int level, /* I - Log level */ 'D', 'd' }; -#ifdef HAVE_VSYSLOG - static const int syslevels[] = /* SYSLOG levels... */ - { - 0, - LOG_EMERG, - LOG_ALERT, - LOG_CRIT, - LOG_ERR, - LOG_WARNING, - LOG_NOTICE, - LOG_INFO, - LOG_DEBUG, - LOG_DEBUG - }; -#endif /* HAVE_VSYSLOG */ #ifdef HAVE_VSYSLOG @@ -1070,5 +1103,5 @@ format_log_line(const char *message, /* I - Printf-style format string */ /* - * End of "$Id: log.c 9949 2011-08-31 04:58:33Z mike $". + * End of "$Id: log.c 11173 2013-07-23 12:31:34Z msweet $". */ diff --git a/scheduler/main.c b/scheduler/main.c index c50ce9d..11eae52 100644 --- a/scheduler/main.c +++ b/scheduler/main.c @@ -1,9 +1,9 @@ /* - * "$Id: main.c 9783 2011-05-18 20:44:16Z mike $" + * "$Id: main.c 11173 2013-07-23 12:31:34Z msweet $" * * Main loop for the CUPS scheduler. * - * Copyright 2007-2011 by Apple Inc. + * Copyright 2007-2012 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -65,10 +65,15 @@ #if defined(HAVE_MALLOC_H) && defined(HAVE_MALLINFO) # include <malloc.h> #endif /* HAVE_MALLOC_H && HAVE_MALLINFO */ + #ifdef HAVE_NOTIFY_H # include <notify.h> #endif /* HAVE_NOTIFY_H */ +#ifdef HAVE_SYS_PARAM_H +# include <sys/param.h> +#endif /* HAVE_SYS_PARAM_H */ + /* * Local functions... @@ -84,7 +89,7 @@ static void sigchld_handler(int sig); static void sighup_handler(int sig); static void sigterm_handler(int sig); static long select_timeout(int fds); -static void usage(int status); +static void usage(int status) __attribute__((noreturn)); /* @@ -120,7 +125,6 @@ main(int argc, /* I - Number of command-line args */ cupsd_listener_t *lis; /* Current listener */ time_t current_time, /* Current time */ activity, /* Client activity timer */ - browse_time, /* Next browse send time */ senddoc_time, /* Send-Document time */ expire_time, /* Subscription expire time */ report_time, /* Malloc/client/job report time */ @@ -208,7 +212,6 @@ main(int argc, /* I - Number of command-line args */ char *current; /* Current directory */ - /* * Allocate a buffer for the current working directory to * reduce run-time stack usage; this approximates the @@ -272,6 +275,29 @@ main(int argc, /* I - Number of command-line args */ UseProfiles = 0; break; + case 's' : /* Set cups-files.conf location */ + i ++; + if (i >= argc) + { + _cupsLangPuts(stderr, _("cupsd: Expected cups-files.conf " + "filename after \"-s\" option.")); + usage(1); + } + + if (argv[i][0] != '/') + { + /* + * Relative filename not allowed... + */ + + _cupsLangPuts(stderr, _("cupsd: Relative cups-files.conf " + "filename not allowed.")); + usage(1); + } + + cupsdSetString(&CupsFilesFile, argv[i]); + break; + #ifdef __APPLE__ case 'S' : /* Disable system management functions */ fputs("cupsd: -S (disable system management) for internal " @@ -299,7 +325,39 @@ main(int argc, /* I - Number of command-line args */ } if (!ConfigurationFile) + { cupsdSetString(&ConfigurationFile, CUPS_SERVERROOT "/cupsd.conf"); + cupsdSetString(&CupsFilesFile, CUPS_SERVERROOT "/cups-files.conf"); + } + + if (!CupsFilesFile) + { + char *filename, /* Copy of cupsd.conf filename */ + *slash; /* Final slash in cupsd.conf filename */ + size_t len; /* Size of buffer */ + + len = strlen(ConfigurationFile) + 15; + if ((filename = malloc(len)) == NULL) + { + _cupsLangPrintf(stderr, + _("cupsd: Unable to get path to " + "cups-files.conf file.")); + return (1); + } + + strlcpy(filename, ConfigurationFile, len); + if ((slash = strrchr(filename, '/')) == NULL) + { + _cupsLangPrintf(stderr, + _("cupsd: Unable to get path to " + "cups-files.conf file.")); + return (1); + } + + strlcpy(slash, "/cups-files.conf", len - (slash - filename)); + cupsdSetString(&CupsFilesFile, filename); + free(filename); + } /* * If the user hasn't specified "-f", run in the background... @@ -366,15 +424,15 @@ main(int argc, /* I - Number of command-line args */ } } -#ifdef __OpenBSD__ +#if defined(__OpenBSD__) && OpenBSD < 201211 /* * Call _thread_sys_closefrom() so the child process doesn't reset the * parent's file descriptors to be blocking. This is a workaround for a - * limitation of userland libpthread on OpenBSD. + * limitation of userland libpthread on older versions of OpenBSD. */ _thread_sys_closefrom(0); -#endif /* __OpenBSD__ */ +#endif /* __OpenBSD__ && OpenBSD < 201211 */ /* * Since CoreFoundation and DBUS both create fork-unsafe data on execution of @@ -484,17 +542,11 @@ main(int argc, /* I - Number of command-line args */ */ if (!cupsdReadConfiguration()) - { - if (TestConfigFile) - printf("%s contains errors\n", ConfigurationFile); - else - syslog(LOG_LPR, "Unable to read configuration file \'%s\' - exiting!", - ConfigurationFile); return (1); - } else if (TestConfigFile) { - printf("%s is OK\n", ConfigurationFile); + printf("\"%s\" is OK.\n", CupsFilesFile); + printf("\"%s\" is OK.\n", ConfigurationFile); return (0); } @@ -650,7 +702,6 @@ main(int argc, /* I - Number of command-line args */ */ current_time = time(NULL); - browse_time = current_time; event_time = current_time; expire_time = current_time; fds = 1; @@ -766,11 +817,9 @@ main(int argc, /* I - Number of command-line args */ * inactivity... */ - if (timeout == 86400 && Launchd && LaunchdTimeout && !NumPolled && + if (timeout == 86400 && Launchd && LaunchdTimeout && !cupsArrayCount(ActiveJobs) && - (!Browsing || - (!BrowseRemoteProtocols && - (!BrowseLocalProtocols || !cupsArrayCount(Printers))))) + (!Browsing || !BrowseLocalProtocols || !cupsArrayCount(Printers))) { timeout = LaunchdTimeout; launchd_idle_exit = 1; @@ -785,9 +834,9 @@ main(int argc, /* I - Number of command-line args */ * Got an error from select! */ -#ifdef HAVE_DNSSD +#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) cupsd_printer_t *p; /* Current printer */ -#endif /* HAVE_DNSSD */ +#endif /* HAVE_DNSSD || HAVE_AVAHI */ if (errno == EINTR) /* Just interrupted by a signal */ @@ -812,8 +861,6 @@ main(int argc, /* I - Number of command-line args */ i ++, lis = (cupsd_listener_t *)cupsArrayNext(Listeners)) cupsdLogMessage(CUPSD_LOG_EMERG, "Listeners[%d] = %d", i, lis->fd); - cupsdLogMessage(CUPSD_LOG_EMERG, "BrowseSocket = %d", BrowseSocket); - cupsdLogMessage(CUPSD_LOG_EMERG, "CGIPipes[0] = %d", CGIPipes[0]); #ifdef __APPLE__ @@ -830,13 +877,13 @@ main(int argc, /* I - Number of command-line args */ job->print_pipes[0], job->print_pipes[1], job->back_pipes[0], job->back_pipes[1]); -#ifdef HAVE_DNSSD +#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); p; p = (cupsd_printer_t *)cupsArrayNext(Printers)) cupsdLogMessage(CUPSD_LOG_EMERG, "printer[%s] reg_name=\"%s\"", p->name, p->reg_name ? p->reg_name : "(null)"); -#endif /* HAVE_DNSSD */ +#endif /* HAVE_DNSSD || HAVE_AVAHI */ break; } @@ -914,31 +961,6 @@ main(int argc, /* I - Number of command-line args */ expire_time = current_time; } - /* - * Update the browse list as needed... - */ - - if (Browsing) - { -#ifdef HAVE_LIBSLP - if ((BrowseRemoteProtocols & BROWSE_SLP) && - BrowseSLPRefresh <= current_time) - cupsdUpdateSLPBrowse(); -#endif /* HAVE_LIBSLP */ - -#ifdef HAVE_LDAP - if ((BrowseRemoteProtocols & BROWSE_LDAP) && - BrowseLDAPRefresh <= current_time) - cupsdUpdateLDAPBrowse(); -#endif /* HAVE_LDAP */ - } - - if (Browsing && current_time > browse_time) - { - cupsdSendBrowseList(); - browse_time = current_time; - } - #ifndef HAVE_AUTHORIZATION_H /* * Update the root certificate once every 5 minutes if we have client @@ -953,7 +975,7 @@ main(int argc, /* I - Number of command-line args */ */ cupsdDeleteCert(0); - cupsdAddCert(0, "root", NULL); + cupsdAddCert(0, "root", cupsdDefaultAuthType()); } #endif /* !HAVE_AUTHORIZATION_H */ @@ -998,11 +1020,17 @@ main(int argc, /* I - Number of command-line args */ if ((current_time - senddoc_time) >= 10) { cupsdCheckJobs(); - cupsdCleanJobs(); senddoc_time = current_time; } /* + * Clean job history... + */ + + if (JobHistoryUpdate && current_time >= JobHistoryUpdate) + cupsdCleanJobs(); + + /* * Log statistics at most once a minute when in debug mode... */ @@ -1031,8 +1059,6 @@ main(int argc, /* I - Number of command-line args */ cupsArrayCount(ActiveJobs)); cupsdLogMessage(CUPSD_LOG_DEBUG, "Report: printers=%d", cupsArrayCount(Printers)); - cupsdLogMessage(CUPSD_LOG_DEBUG, "Report: printers-implicit=%d", - cupsArrayCount(ImplicitPrinters)); string_count = _cupsStrStatistics(&alloc_bytes, &total_bytes); cupsdLogMessage(CUPSD_LOG_DEBUG, @@ -1141,23 +1167,6 @@ main(int argc, /* I - Number of command-line args */ cupsdStopSystemMonitor(); #endif /* __APPLE__ */ -#ifdef HAVE_GSSAPI - /* - * Free the scheduler's Kerberos context... - */ - -# ifdef __APPLE__ - /* - * If the weak-linked GSSAPI/Kerberos library is not present, don't try - * to use it... - */ - - if (krb5_init_context != NULL) -# endif /* __APPLE__ */ - if (KerberosContext) - krb5_free_context(KerberosContext); -#endif /* HAVE_GSSAPI */ - #ifdef __sgi /* * Remove the fake IRIX lpsched lock file, but only if the existing @@ -1317,7 +1326,7 @@ cupsdSetStringf(char **s, /* O - New string */ const char *f, /* I - Printf-style format string */ ...) /* I - Additional args as needed */ { - char v[4096]; /* Formatting string value */ + char v[65536 + 64]; /* Formatting string value */ va_list ap; /* Argument pointer */ char *olds; /* Old string */ @@ -1512,10 +1521,8 @@ launchd_checkout(void) * shared printers to advertise... */ - if (cupsArrayCount(ActiveJobs) || NumPolled || - (Browsing && - (BrowseRemoteProtocols || - (BrowseLocalProtocols && cupsArrayCount(Printers))))) + if (cupsArrayCount(ActiveJobs) || + (Browsing && BrowseLocalProtocols && cupsArrayCount(Printers))) { cupsdLogMessage(CUPSD_LOG_DEBUG, "Creating launchd keepalive file \"" CUPS_KEEPALIVE @@ -1564,6 +1571,7 @@ process_children(void) cupsd_job_t *job; /* Current job */ int i; /* Looping var */ char name[1024]; /* Process name */ + const char *type; /* Type of program */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "process_children()"); @@ -1603,7 +1611,12 @@ process_children(void) * Handle completed job filters... */ - if (job_id > 0 && (job = cupsdFindJob(job_id)) != NULL) + if (job_id > 0) + job = cupsdFindJob(job_id); + else + job = NULL; + + if (job) { for (i = 0; job->filters[i]; i ++) if (job->filters[i] == pid) @@ -1616,12 +1629,18 @@ process_children(void) */ if (job->filters[i]) + { job->filters[i] = -pid; + type = "Filter"; + } else + { job->backend = -pid; + type = "Backend"; + } if (status && status != SIGTERM && status != SIGKILL && - status != SIGPIPE && job->status >= 0) + status != SIGPIPE) { /* * An error occurred; save the exit status so we know to stop @@ -1629,22 +1648,35 @@ process_children(void) * * A negative status indicates that the backend failed and the * printer needs to be stopped. + * + * In order to preserve the most serious status, we always log + * when a process dies due to a signal (e.g. SIGABRT, SIGSEGV, + * and SIGBUS) and prefer to log the backend exit status over a + * filter's. */ - if (job->filters[i]) - job->status = status; /* Filter failed */ - else - job->status = -status; /* Backend failed */ + int old_status = abs(job->status); + + if (WIFSIGNALED(status) || /* This process crashed, or */ + !job->status || /* No process had a status, or */ + (!job->filters[i] && WIFEXITED(old_status))) + { /* Backend and filter didn't crash */ + if (job->filters[i]) + job->status = status; /* Filter failed */ + else + job->status = -status; /* Backend failed */ + } if (job->state_value == IPP_JOB_PROCESSING && - job->status_level > CUPSD_LOG_ERROR) + job->status_level > CUPSD_LOG_ERROR && + (job->filters[i] || !WIFEXITED(status))) { char message[1024]; /* New printer-state-message */ job->status_level = CUPSD_LOG_ERROR; - snprintf(message, sizeof(message), "%s failed", name); + snprintf(message, sizeof(message), "%s failed", type); if (job->printer) { @@ -1714,15 +1746,15 @@ process_children(void) if (status == SIGTERM || status == SIGKILL) { - cupsdLogMessage(CUPSD_LOG_DEBUG, - "PID %d (%s) was terminated normally with signal %d.", - pid, name, status); + cupsdLogJob(job, CUPSD_LOG_DEBUG, + "PID %d (%s) was terminated normally with signal %d.", pid, + name, status); } else if (status == SIGPIPE) { - cupsdLogMessage(CUPSD_LOG_DEBUG, - "PID %d (%s) did not catch or ignore signal %d.", - pid, name, status); + cupsdLogJob(job, CUPSD_LOG_DEBUG, + "PID %d (%s) did not catch or ignore signal %d.", pid, name, + status); } else if (status) { @@ -1731,26 +1763,25 @@ process_children(void) int code = WEXITSTATUS(status); /* Exit code */ if (code > 100) - cupsdLogMessage(CUPSD_LOG_DEBUG, - "PID %d (%s) stopped with status %d (%s)", pid, name, - code, strerror(code - 100)); + cupsdLogJob(job, CUPSD_LOG_DEBUG, + "PID %d (%s) stopped with status %d (%s)", pid, name, + code, strerror(code - 100)); else - cupsdLogMessage(CUPSD_LOG_DEBUG, - "PID %d (%s) stopped with status %d.", pid, name, - code); + cupsdLogJob(job, CUPSD_LOG_DEBUG, + "PID %d (%s) stopped with status %d.", pid, name, code); } else - cupsdLogMessage(CUPSD_LOG_ERROR, "PID %d (%s) crashed on signal %d.", - pid, name, WTERMSIG(status)); + cupsdLogJob(job, CUPSD_LOG_DEBUG, "PID %d (%s) crashed on signal %d.", + pid, name, WTERMSIG(status)); if (LogLevel < CUPSD_LOG_DEBUG) - cupsdLogMessage(CUPSD_LOG_INFO, - "Hint: Try setting the LogLevel to \"debug\" to find " - "out more."); + cupsdLogJob(job, CUPSD_LOG_INFO, + "Hint: Try setting the LogLevel to \"debug\" to find out " + "more."); } else - cupsdLogMessage(CUPSD_LOG_DEBUG, "PID %d (%s) exited with no errors.", - pid, name); + cupsdLogJob(job, CUPSD_LOG_DEBUG, "PID %d (%s) exited with no errors.", + pid, name); } /* @@ -1773,12 +1804,14 @@ select_timeout(int fds) /* I - Number of descriptors returned */ long timeout; /* Timeout for select */ time_t now; /* Current time */ cupsd_client_t *con; /* Client information */ - cupsd_printer_t *p; /* Printer information */ cupsd_job_t *job; /* Job information */ cupsd_subscription_t *sub; /* Subscription information */ const char *why; /* Debugging aid */ + cupsdLogMessage(CUPSD_LOG_DEBUG2, "select_timeout: JobHistoryUpdate=%ld", + (long)JobHistoryUpdate); + /* * Check to see if any of the clients have pending data to be * processed; if so, the timeout should be 0... @@ -1848,54 +1881,6 @@ select_timeout(int fds) /* I - Number of descriptors returned */ } /* - * Update the browse list as needed... - */ - - if (Browsing && BrowseLocalProtocols) - { -#ifdef HAVE_LIBSLP - if ((BrowseLocalProtocols & BROWSE_SLP) && (BrowseSLPRefresh < timeout)) - { - timeout = BrowseSLPRefresh; - why = "update SLP browsing"; - } -#endif /* HAVE_LIBSLP */ - -#ifdef HAVE_LDAP - if ((BrowseLocalProtocols & BROWSE_LDAP) && (BrowseLDAPRefresh < timeout)) - { - timeout = BrowseLDAPRefresh; - why = "update LDAP browsing"; - } -#endif /* HAVE_LDAP */ - - if ((BrowseLocalProtocols & BROWSE_CUPS) && NumBrowsers) - { - for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); - p; - p = (cupsd_printer_t *)cupsArrayNext(Printers)) - { - if (p->type & CUPS_PRINTER_REMOTE) - { - if ((p->browse_time + BrowseTimeout) < timeout) - { - timeout = p->browse_time + BrowseTimeout; - why = "browse timeout a printer"; - } - } - else if (p->shared && !(p->type & CUPS_PRINTER_IMPLICIT)) - { - if (BrowseInterval && (p->browse_time + BrowseInterval) < timeout) - { - timeout = p->browse_time + BrowseInterval; - why = "send browse update"; - } - } - } - } - } - - /* * Write out changes to configuration and state files... */ @@ -1906,13 +1891,25 @@ select_timeout(int fds) /* I - Number of descriptors returned */ } /* - * Check for any active jobs... + * Check for any job activity... */ + if (JobHistoryUpdate && timeout > JobHistoryUpdate) + { + timeout = JobHistoryUpdate; + why = "update job history"; + } + for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs); job; job = (cupsd_job_t *)cupsArrayNext(ActiveJobs)) { + if (job->cancel_time && job->cancel_time < timeout) + { + timeout = job->cancel_time; + why = "cancel stuck jobs"; + } + if (job->kill_time && job->kill_time < timeout) { timeout = job->kill_time; @@ -1924,7 +1921,8 @@ select_timeout(int fds) /* I - Number of descriptors returned */ timeout = job->hold_until; why = "release held jobs"; } - else if (job->state_value == IPP_JOB_PENDING && timeout > (now + 10)) + + if (job->state_value == IPP_JOB_PENDING && timeout > (now + 10)) { timeout = now + 10; why = "start pending jobs"; @@ -1958,11 +1956,9 @@ select_timeout(int fds) /* I - Number of descriptors returned */ } /* - * Adjust from absolute to relative time. If p->browse_time above - * was 0 then we can end up with a negative value here, so check. - * We add 1 second to the timeout since events occur after the - * timeout expires, and limit the timeout to 86400 seconds (1 day) - * to avoid select() timeout limits present on some operating + * Adjust from absolute to relative time. We add 1 second to the timeout since + * events occur after the timeout expires, and limit the timeout to 86400 + * seconds (1 day) to avoid select() timeout limits present on some operating * systems... */ @@ -2056,8 +2052,7 @@ usage(int status) /* O - Exit status */ _cupsLangPuts(fp, _("Usage: cupsd [options]")); _cupsLangPuts(fp, _("Options:")); - _cupsLangPuts(fp, _(" -c config-file Load alternate configuration " - "file.")); + _cupsLangPuts(fp, _(" -c cupsd.conf Set cupsd.conf file to use.")); _cupsLangPuts(fp, _(" -f Run in the foreground.")); _cupsLangPuts(fp, _(" -F Run in the foreground but " "detach from console.")); @@ -2071,5 +2066,5 @@ usage(int status) /* O - Exit status */ /* - * End of "$Id: main.c 9783 2011-05-18 20:44:16Z mike $". + * End of "$Id: main.c 11173 2013-07-23 12:31:34Z msweet $". */ diff --git a/scheduler/mime-private.h b/scheduler/mime-private.h index 5891253..f984548 100644 --- a/scheduler/mime-private.h +++ b/scheduler/mime-private.h @@ -1,5 +1,5 @@ /* - * "$Id: mime-private.h 9750 2011-05-06 22:53:53Z mike $" + * "$Id: mime-private.h 11173 2013-07-23 12:31:34Z msweet $" * * Private MIME type/conversion database definitions for CUPS. * @@ -32,10 +32,7 @@ extern "C" { */ extern void _mimeError(mime_t *mime, const char *format, ...) -#ifdef __GNUC__ -__attribute__ ((__format__ (__printf__, 2, 3))) -#endif /* __GNUC__ */ -; + __attribute__ ((__format__ (__printf__, 2, 3))); # ifdef __cplusplus @@ -44,5 +41,5 @@ __attribute__ ((__format__ (__printf__, 2, 3))) #endif /* !_CUPS_MIME_PRIVATE_H_ */ /* - * End of "$Id: mime-private.h 9750 2011-05-06 22:53:53Z mike $". + * End of "$Id: mime-private.h 11173 2013-07-23 12:31:34Z msweet $". */ diff --git a/scheduler/mime.c b/scheduler/mime.c index fd7c12a..412c9e0 100644 --- a/scheduler/mime.c +++ b/scheduler/mime.c @@ -1,5 +1,5 @@ /* - * "$Id: mime.c 9750 2011-05-06 22:53:53Z mike $" + * "$Id: mime.c 11173 2013-07-23 12:31:34Z msweet $" * * MIME database file routines for CUPS. * @@ -956,5 +956,5 @@ mime_load_types(mime_t *mime, /* I - MIME database */ /* - * End of "$Id: mime.c 9750 2011-05-06 22:53:53Z mike $". + * End of "$Id: mime.c 11173 2013-07-23 12:31:34Z msweet $". */ diff --git a/scheduler/mime.h b/scheduler/mime.h index c9e2147..51d7a29 100644 --- a/scheduler/mime.h +++ b/scheduler/mime.h @@ -1,5 +1,5 @@ /* - * "$Id: mime.h 9750 2011-05-06 22:53:53Z mike $" + * "$Id: mime.h 11173 2013-07-23 12:31:34Z msweet $" * * MIME type/conversion database definitions for CUPS. * @@ -158,5 +158,5 @@ extern void mimeSetErrorCallback(mime_t *mime, mime_error_cb_t cb, #endif /* !_CUPS_MIME_H_ */ /* - * End of "$Id: mime.h 9750 2011-05-06 22:53:53Z mike $". + * End of "$Id: mime.h 11173 2013-07-23 12:31:34Z msweet $". */ diff --git a/scheduler/network.c b/scheduler/network.c index 921ed17..07b5265 100644 --- a/scheduler/network.c +++ b/scheduler/network.c @@ -1,5 +1,5 @@ /* - * "$Id: network.c 10379 2012-03-23 22:16:22Z mike $" + * "$Id: network.c 11173 2013-07-23 12:31:34Z msweet $" * * Network interface functions for the CUPS scheduler. * @@ -296,5 +296,5 @@ compare_netif(cupsd_netif_t *a, /* I - First network interface */ /* - * End of "$Id: network.c 10379 2012-03-23 22:16:22Z mike $". + * End of "$Id: network.c 11173 2013-07-23 12:31:34Z msweet $". */ diff --git a/scheduler/network.h b/scheduler/network.h index f16a06b..0570975 100644 --- a/scheduler/network.h +++ b/scheduler/network.h @@ -1,5 +1,5 @@ /* - * "$Id: network.h 9350 2010-11-04 23:23:25Z mike $" + * "$Id: network.h 11173 2013-07-23 12:31:34Z msweet $" * * Network interface definitions for the CUPS scheduler. * @@ -48,5 +48,5 @@ extern void cupsdNetIFUpdate(void); /* - * End of "$Id: network.h 9350 2010-11-04 23:23:25Z mike $". + * End of "$Id: network.h 11173 2013-07-23 12:31:34Z msweet $". */ diff --git a/scheduler/policy.c b/scheduler/policy.c index fb29ce0..75b5983 100644 --- a/scheduler/policy.c +++ b/scheduler/policy.c @@ -1,5 +1,5 @@ /* - * "$Id: policy.c 9793 2011-05-20 03:49:49Z mike $" + * "$Id: policy.c 11173 2013-07-23 12:31:34Z msweet $" * * Policy routines for the CUPS scheduler. * @@ -513,5 +513,5 @@ hash_op(cupsd_location_t *op) /* I - Operation */ /* - * End of "$Id: policy.c 9793 2011-05-20 03:49:49Z mike $". + * End of "$Id: policy.c 11173 2013-07-23 12:31:34Z msweet $". */ diff --git a/scheduler/policy.h b/scheduler/policy.h index f718777..df17a11 100644 --- a/scheduler/policy.h +++ b/scheduler/policy.h @@ -1,5 +1,5 @@ /* - * "$Id: policy.h 9352 2010-11-06 04:55:26Z mike $" + * "$Id: policy.h 11173 2013-07-23 12:31:34Z msweet $" * * Policy definitions for the CUPS scheduler. * @@ -59,5 +59,5 @@ extern cups_array_t *cupsdGetPrivateAttrs(cupsd_policy_t *p, /* - * End of "$Id: policy.h 9352 2010-11-06 04:55:26Z mike $". + * End of "$Id: policy.h 11173 2013-07-23 12:31:34Z msweet $". */ diff --git a/scheduler/printers.c b/scheduler/printers.c index 1220db6..48c4a82 100644 --- a/scheduler/printers.c +++ b/scheduler/printers.c @@ -1,5 +1,5 @@ /* - * "$Id: printers.c 10295 2012-02-15 23:21:06Z mike $" + * "$Id: printers.c 11173 2013-07-23 12:31:34Z msweet $" * * Printer routines for the CUPS scheduler. * @@ -168,9 +168,6 @@ cupsdAddPrinter(const char *name) /* I - Name of printer */ "cupsdAddPrinter: Adding %s to Printers", p->name); cupsArrayAdd(Printers, p); - if (!ImplicitPrinters) - ImplicitPrinters = cupsArrayNew(compare_printers, NULL); - /* * Return the new printer... */ @@ -643,8 +640,7 @@ cupsdCreateCommonData(void) /* operations-supported */ ippAddIntegers(CommonData, IPP_TAG_PRINTER, IPP_TAG_ENUM, - "operations-supported", - sizeof(ops) / sizeof(ops[0]) + JobFiles - 1, ops); + "operations-supported", sizeof(ops) / sizeof(ops[0]), ops); /* orientation-requested-supported */ ippAddIntegers(CommonData, IPP_TAG_PRINTER, IPP_TAG_ENUM, @@ -752,16 +748,6 @@ cupsdDeletePrinter( "Job stopped."); /* - * If this printer is the next for browsing, point to the next one... - */ - - if (p == BrowseNext) - { - cupsArrayFind(Printers, p); - BrowseNext = (cupsd_printer_t *)cupsArrayNext(Printers); - } - - /* * Remove the printer from the list... */ @@ -769,14 +755,6 @@ cupsdDeletePrinter( "cupsdDeletePrinter: Removing %s from Printers", p->name); cupsArrayRemove(Printers, p); - if (p->type & CUPS_PRINTER_IMPLICIT) - { - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "cupsdDeletePrinter: Removing %s from ImplicitPrinters", - p->name); - cupsArrayRemove(ImplicitPrinters, p); - } - /* * Remove the dummy interface/icon/option files under IRIX... */ @@ -807,43 +785,19 @@ cupsdDeletePrinter( */ if (p == DefaultPrinter) - { DefaultPrinter = NULL; - if (UseNetworkDefault) - { - /* - * Find the first network default printer and use it... - */ - - cupsd_printer_t *dp; /* New default printer */ - - - for (dp = (cupsd_printer_t *)cupsArrayFirst(Printers); - dp; - dp = (cupsd_printer_t *)cupsArrayNext(Printers)) - if (dp != p && (dp->type & CUPS_PRINTER_DEFAULT)) - { - DefaultPrinter = dp; - break; - } - } - } - /* * Remove this printer from any classes... */ - if (!(p->type & CUPS_PRINTER_IMPLICIT)) - { - changed = cupsdDeletePrinterFromClasses(p); + changed = cupsdDeletePrinterFromClasses(p); - /* - * Deregister from any browse protocols... - */ + /* + * Deregister from any browse protocols... + */ - cupsdDeregisterPrinter(p, 1); - } + cupsdDeregisterPrinter(p, 1); /* * Free all memory used by the printer... @@ -883,15 +837,13 @@ cupsdDeletePrinter( cupsdClearString(&p->alert); cupsdClearString(&p->alert_description); -#ifdef HAVE_DNSSD +#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) cupsdClearString(&p->pdl); -#endif /* HAVE_DNSSD */ + cupsdClearString(&p->reg_name); +#endif /* HAVE_DNSSD || HAVE_AVAHI */ cupsArrayDelete(p->filetypes); - if (p->browse_attrs) - free(p->browse_attrs); - cupsFreeOptions(p->num_options, p->options); free(p); @@ -1396,14 +1348,6 @@ cupsdRenamePrinter( "cupsdRenamePrinter: Removing %s from Printers", p->name); cupsArrayRemove(Printers, p); - if (p->type & CUPS_PRINTER_IMPLICIT) - { - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "cupsdRenamePrinter: Removing %s from ImplicitPrinters", - p->name); - cupsArrayRemove(ImplicitPrinters, p); - } - /* * Rename the printer type... */ @@ -1436,14 +1380,6 @@ cupsdRenamePrinter( cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdRenamePrinter: Adding %s to Printers", p->name); cupsArrayAdd(Printers, p); - - if (p->type & CUPS_PRINTER_IMPLICIT) - { - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "cupsdRenamePrinter: Adding %s to ImplicitPrinters", - p->name); - cupsArrayAdd(ImplicitPrinters, p); - } } @@ -1501,12 +1437,10 @@ cupsdSaveAllPrinters(void) printer = (cupsd_printer_t *)cupsArrayNext(Printers)) { /* - * Skip remote destinations and printer classes... + * Skip printer classes... */ - if ((printer->type & CUPS_PRINTER_DISCOVERED) || - (printer->type & CUPS_PRINTER_CLASS) || - (printer->type & CUPS_PRINTER_IMPLICIT)) + if (printer->type & CUPS_PRINTER_CLASS) continue; /* @@ -2138,27 +2072,14 @@ cupsdSetPrinterAttr( void cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */ { - int i, /* Looping var */ - length; /* Length of browse attributes */ + int i; /* Looping var */ char resource[HTTP_MAX_URI]; /* Resource portion of URI */ - int num_air; /* Number of auth-info-required values */ - const char * const *air; /* auth-info-required values */ cupsd_location_t *auth; /* Pointer to authentication element */ const char *auth_supported; /* Authentication supported */ ipp_t *oldattrs; /* Old printer attributes */ ipp_attribute_t *attr; /* Attribute data */ - cups_option_t *option; /* Current printer option */ char *name, /* Current user/group name */ *filter; /* Current filter */ - static const char * const air_none[] = - { /* No authentication */ - "none" - }; - static const char * const air_userpass[] = - { /* Basic/Digest authentication */ - "username", - "password" - }; DEBUG_printf(("cupsdSetPrinterAttrs: entering name = %s, type = %x\n", p->name, @@ -2182,20 +2103,6 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */ */ auth_supported = "requesting-user-name"; - num_air = 1; - air = air_none; - - if (p->num_auth_info_required > 0 && strcmp(p->auth_info_required[0], "none")) - { - num_air = p->num_auth_info_required; - air = p->auth_info_required; - } - else if ((p->type & CUPS_PRINTER_AUTHENTICATED) && - (p->type & CUPS_PRINTER_DISCOVERED)) - { - num_air = 2; - air = air_userpass; - } if (p->type & CUPS_PRINTER_CLASS) snprintf(resource, sizeof(resource), "/classes/%s", p->name); @@ -2212,7 +2119,7 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */ if ((auth_type = auth->type) == CUPSD_AUTH_DEFAULT) - auth_type = DefaultAuthType; + auth_type = cupsdDefaultAuthType(); if (auth_type == CUPSD_AUTH_BASIC || auth_type == CUPSD_AUTH_BASICDIGEST) auth_supported = "basic"; @@ -2223,15 +2130,12 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */ auth_supported = "negotiate"; #endif /* HAVE_GSSAPI */ - if (!(p->type & CUPS_PRINTER_DISCOVERED)) - { - if (auth_type != CUPSD_AUTH_NONE) - p->type |= CUPS_PRINTER_AUTHENTICATED; - else - p->type &= ~CUPS_PRINTER_AUTHENTICATED; - } + if (auth_type != CUPSD_AUTH_NONE) + p->type |= CUPS_PRINTER_AUTHENTICATED; + else + p->type &= ~CUPS_PRINTER_AUTHENTICATED; } - else if (!(p->type & CUPS_PRINTER_DISCOVERED)) + else p->type &= ~CUPS_PRINTER_AUTHENTICATED; /* @@ -2277,10 +2181,12 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */ "job-k-limit", p->k_limit); ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "job-page-limit", p->page_limit); - ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, - "auth-info-required", num_air, NULL, air); + if (p->num_auth_info_required > 0 && strcmp(p->auth_info_required[0], "none")) + ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + "auth-info-required", p->num_auth_info_required, NULL, + p->auth_info_required); - if (cupsArrayCount(Banners) > 0 && !(p->type & CUPS_PRINTER_DISCOVERED)) + if (cupsArrayCount(Banners) > 0) { /* * Setup the job-sheets-default attribute... @@ -2301,164 +2207,117 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */ p->raw = 0; p->remote = 0; - if (p->type & CUPS_PRINTER_DISCOVERED) + /* + * Assign additional attributes depending on whether this is a printer + * or class... + */ + + if (p->type & CUPS_PRINTER_CLASS) { + p->raw = 1; + p->type &= ~CUPS_PRINTER_OPTIONS; + /* - * Tell the client this is a remote printer of some type... + * Add class-specific attributes... */ - if (strchr(p->uri, '?')) + ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, + "printer-make-and-model", NULL, "Local Printer Class"); + ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", NULL, + "file:///dev/null"); + + if (p->num_printers > 0) { /* - * Strip trailing "?options" from URI... + * Add a list of member names; URIs are added in copy_printer_attrs... */ - char *ptr; /* Pointer into URI */ + attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME, + "member-names", p->num_printers, NULL, NULL); + p->type |= CUPS_PRINTER_OPTIONS; - strlcpy(resource, p->uri, sizeof(resource)); - if ((ptr = strchr(resource, '?')) != NULL) - *ptr = '\0'; + for (i = 0; i < p->num_printers; i ++) + { + if (attr != NULL) + attr->values[i].string.text = _cupsStrRetain(p->printers[i]->name); - ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, - "printer-uri-supported", NULL, resource); + p->type &= ~CUPS_PRINTER_OPTIONS | p->printers[i]->type; + } } - else - ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, - "printer-uri-supported", NULL, p->uri); - - ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-more-info", - NULL, p->uri); - - if (p->make_model) - ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, - "printer-make-and-model", NULL, p->make_model); - - ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", NULL, - p->uri); - - p->raw = 1; - p->remote = 1; } else { /* - * Assign additional attributes depending on whether this is a printer - * or class... + * Add printer-specific attributes... */ - if (p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT)) - { - p->raw = 1; - p->type &= ~CUPS_PRINTER_OPTIONS; - - /* - * Add class-specific attributes... - */ - - if ((p->type & CUPS_PRINTER_IMPLICIT) && p->num_printers > 0 && - p->printers[0]->make_model) - ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, - "printer-make-and-model", NULL, p->printers[0]->make_model); - else - ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, - "printer-make-and-model", NULL, "Local Printer Class"); + ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", NULL, + p->sanitized_device_uri); - ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", NULL, - "file:///dev/null"); + /* + * Assign additional attributes from the PPD file (if any)... + */ - if (p->num_printers > 0) - { - /* - * Add a list of member names; URIs are added in copy_printer_attrs... - */ + load_ppd(p); - attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME, - "member-names", p->num_printers, NULL, NULL); - p->type |= CUPS_PRINTER_OPTIONS; + /* + * Add filters for printer... + */ - for (i = 0; i < p->num_printers; i ++) - { - if (attr != NULL) - attr->values[i].string.text = _cupsStrRetain(p->printers[i]->name); + cupsdSetPrinterReasons(p, "-cups-missing-filter-warning," + "cups-insecure-filter-warning"); - p->type &= ~CUPS_PRINTER_OPTIONS | p->printers[i]->type; - } - } + if (p->pc && p->pc->filters) + { + for (filter = (char *)cupsArrayFirst(p->pc->filters); + filter; + filter = (char *)cupsArrayNext(p->pc->filters)) + add_printer_filter(p, p->filetype, filter); } - else + else if (!(p->type & CUPS_PRINTER_REMOTE)) { - /* - * Add printer-specific attributes... - */ + char interface[1024]; /* Interface script */ - ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", NULL, - p->sanitized_device_uri); - /* - * Assign additional attributes from the PPD file (if any)... - */ - - load_ppd(p); - - /* - * Add filters for printer... - */ - - cupsdSetPrinterReasons(p, "-cups-missing-filter-warning," - "cups-insecure-filter-warning"); - - if (p->pc && p->pc->filters) + snprintf(interface, sizeof(interface), "%s/interfaces/%s", ServerRoot, + p->name); + if (!access(interface, X_OK)) { - for (filter = (char *)cupsArrayFirst(p->pc->filters); - filter; - filter = (char *)cupsArrayNext(p->pc->filters)) - add_printer_filter(p, p->filetype, filter); + /* + * Yes, we have a System V style interface script; use it! + */ + + snprintf(interface, sizeof(interface), "*/* 0 %s/interfaces/%s", + ServerRoot, p->name); + add_printer_filter(p, p->filetype, interface); } - else if (!(p->type & CUPS_PRINTER_REMOTE)) + else { - char interface[1024]; /* Interface script */ - - - snprintf(interface, sizeof(interface), "%s/interfaces/%s", ServerRoot, - p->name); - if (!access(interface, X_OK)) - { - /* - * Yes, we have a System V style interface script; use it! - */ - - snprintf(interface, sizeof(interface), "*/* 0 %s/interfaces/%s", - ServerRoot, p->name); - add_printer_filter(p, p->filetype, interface); - } - else - { - /* - * Add a filter from application/vnd.cups-raw to printer/name to - * handle "raw" printing by users. - */ + /* + * Add a filter from application/vnd.cups-raw to printer/name to + * handle "raw" printing by users. + */ - add_printer_filter(p, p->filetype, "application/vnd.cups-raw 0 -"); + add_printer_filter(p, p->filetype, "application/vnd.cups-raw 0 -"); - /* - * Add a PostScript filter, since this is still possibly PS printer. - */ + /* + * Add a PostScript filter, since this is still possibly PS printer. + */ - add_printer_filter(p, p->filetype, - "application/vnd.cups-postscript 0 -"); - } + add_printer_filter(p, p->filetype, + "application/vnd.cups-postscript 0 -"); } + } - if (p->pc && p->pc->prefilters) - { - if (!p->prefiltertype) - p->prefiltertype = mimeAddType(MimeDatabase, "prefilter", p->name); + if (p->pc && p->pc->prefilters) + { + if (!p->prefiltertype) + p->prefiltertype = mimeAddType(MimeDatabase, "prefilter", p->name); - for (filter = (char *)cupsArrayFirst(p->pc->prefilters); - filter; - filter = (char *)cupsArrayNext(p->pc->prefilters)) - add_printer_filter(p, p->prefiltertype, filter); - } + for (filter = (char *)cupsArrayFirst(p->pc->prefilters); + filter; + filter = (char *)cupsArrayNext(p->pc->prefilters)) + add_printer_filter(p, p->prefiltertype, filter); } } @@ -2558,98 +2417,8 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */ * Force sharing off for remote queues... */ - if (p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)) + if (p->type & CUPS_PRINTER_REMOTE) p->shared = 0; - else - { - /* - * Copy the printer options into a browse attributes string we can re-use. - */ - - const char *valptr; /* Pointer into value */ - char *attrptr; /* Pointer into attribute string */ - - - /* - * Free the old browse attributes as needed... - */ - - if (p->browse_attrs) - free(p->browse_attrs); - - /* - * Compute the length of all attributes + job-sheets, lease-duration, - * and BrowseLocalOptions. - */ - - for (length = 1, i = p->num_options, option = p->options; - i > 0; - i --, option ++) - { - length += strlen(option->name) + 2; - - if (option->value) - { - for (valptr = option->value; *valptr; valptr ++) - if (strchr(" \"\'\\", *valptr)) - length += 2; - else - length ++; - } - } - - length += 13 + strlen(p->job_sheets[0]) + strlen(p->job_sheets[1]); - length += 32; - if (BrowseLocalOptions) - length += 12 + strlen(BrowseLocalOptions); - - /* - * Allocate the new string... - */ - - if ((p->browse_attrs = calloc(1, length)) == NULL) - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to allocate %d bytes for browse data!", - length); - else - { - /* - * Got the allocated string, now copy the options and attributes over... - */ - - sprintf(p->browse_attrs, "job-sheets=%s,%s lease-duration=%d", - p->job_sheets[0], p->job_sheets[1], BrowseTimeout); - attrptr = p->browse_attrs + strlen(p->browse_attrs); - - if (BrowseLocalOptions) - { - sprintf(attrptr, " ipp-options=%s", BrowseLocalOptions); - attrptr += strlen(attrptr); - } - - for (i = p->num_options, option = p->options; - i > 0; - i --, option ++) - { - *attrptr++ = ' '; - strcpy(attrptr, option->name); - attrptr += strlen(attrptr); - - if (option->value) - { - *attrptr++ = '='; - - for (valptr = option->value; *valptr; valptr ++) - { - if (strchr(" \"\'\\", *valptr)) - *attrptr++ = '\\'; - - *attrptr++ = *valptr; - } - } - } - } - } /* * Populate the document-format-supported attribute... @@ -2832,6 +2601,7 @@ cupsdSetPrinterState( ipp_pstate_t s, /* I - New state */ int update) /* I - Update printers.conf? */ { + cupsd_job_t *job; /* Current job */ ipp_pstate_t old_state; /* Old printer state */ static const char * const printer_states[] = { /* State strings */ @@ -2842,13 +2612,6 @@ cupsdSetPrinterState( /* - * Can't set status of remote printers... - */ - - if (p->type & CUPS_PRINTER_DISCOVERED) - return; - - /* * Set the new state... */ @@ -2867,9 +2630,7 @@ cupsdSetPrinterState( * Let the browse code know this needs to be updated... */ - BrowseNext = p; - p->state_time = time(NULL); - p->browse_time = 0; + p->state_time = time(NULL); #ifdef __sgi write_irix_state(p); @@ -2885,6 +2646,17 @@ cupsdSetPrinterState( else cupsdSetPrinterReasons(p, "-paused"); + if (old_state != s) + { + for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs); + job; + job = (cupsd_job_t *)cupsArrayNext(ActiveJobs)) + if (job->reasons && job->state_value == IPP_JOB_PENDING && + !_cups_strcasecmp(job->dest, p->name)) + ippSetString(job->attrs, &job->reasons, 0, + s == IPP_PRINTER_STOPPED ? "printer-stopped" : "none"); + } + /* * Clear the message for the queue when going to processing... */ @@ -3068,22 +2840,6 @@ cupsdUpdatePrinters(void) p = (cupsd_printer_t *)cupsArrayNext(Printers)) { /* - * Remove remote printers if we are no longer browsing... - */ - - if (!Browsing && - (p->type & (CUPS_PRINTER_IMPLICIT | CUPS_PRINTER_DISCOVERED))) - { - if (p->type & CUPS_PRINTER_IMPLICIT) - cupsArrayRemove(ImplicitPrinters, p); - - cupsArraySave(Printers); - cupsdDeletePrinter(p, 0); - cupsArrayRestore(Printers); - continue; - } - - /* * Update the operation policy pointer... */ @@ -3091,11 +2847,10 @@ cupsdUpdatePrinters(void) p->op_policy_ptr = DefaultPolicyPtr; /* - * Update printer attributes as needed... + * Update printer attributes... */ - if (!(p->type & CUPS_PRINTER_DISCOVERED)) - cupsdSetPrinterAttrs(p); + cupsdSetPrinterAttrs(p); } } @@ -3188,8 +2943,7 @@ cupsdValidateDest( *printer = p; if (dtype) - *dtype = p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT | - CUPS_PRINTER_REMOTE | CUPS_PRINTER_DISCOVERED); + *dtype = p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_REMOTE); return (p->name); } @@ -3247,8 +3001,7 @@ cupsdValidateDest( *printer = p; if (dtype) - *dtype = p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT | - CUPS_PRINTER_REMOTE | CUPS_PRINTER_DISCOVERED); + *dtype = p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_REMOTE); return (p->name); } @@ -3797,7 +3550,7 @@ add_printer_formats(cupsd_printer_t *p) /* I - Printer */ attr->values[i].string.text = _cupsStrAlloc(mimetype); } -#ifdef HAVE_DNSSD +#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) { char pdl[1024]; /* Buffer to build pdl list */ mime_filter_t *filter; /* MIME filter looping var */ @@ -3853,7 +3606,7 @@ add_printer_formats(cupsd_printer_t *p) /* I - Printer */ cupsdSetString(&p->pdl, pdl); } -#endif /* HAVE_DNSSD */ +#endif /* HAVE_DNSSD || HAVE_AVAHI */ } @@ -3931,9 +3684,7 @@ delete_printer_filters( static void dirty_printer(cupsd_printer_t *p) /* I - Printer */ { - if (p->type & CUPS_PRINTER_DISCOVERED) - cupsdMarkDirty(CUPSD_DIRTY_REMOTE); - else if (p->type & CUPS_PRINTER_CLASS) + if (p->type & CUPS_PRINTER_CLASS) cupsdMarkDirty(CUPSD_DIRTY_CLASSES); else cupsdMarkDirty(CUPSD_DIRTY_PRINTERS); @@ -3973,7 +3724,7 @@ load_ppd(cupsd_printer_t *p) /* I - Printer */ _pwg_map_t *pwgsource, /* Current PWG source */ *pwgtype; /* Current PWG type */ ipp_attribute_t *attr; /* Attribute data */ - ipp_value_t *val; /* Attribute value */ + _ipp_value_t *val; /* Attribute value */ int num_finishings, /* Number of finishings */ finishings[5]; /* finishings-supported values */ int num_qualities, /* Number of print-quality values */ @@ -4044,7 +3795,7 @@ load_ppd(cupsd_printer_t *p) /* I - Printer */ p->ppd_attrs = ippNew(); - if ((ppd = ppdOpenFile(ppd_name)) != NULL) + if ((ppd = _ppdOpenFile(ppd_name, _PPD_LOCALIZATION_NONE)) != NULL) { /* * Add make/model and other various attributes... @@ -4233,6 +3984,41 @@ load_ppd(cupsd_printer_t *p) /* I - Printer */ } /* + * media-size-supported + */ + + num_media = p->pc->num_sizes; + if (p->pc->custom_min_keyword) + num_media ++; + + if ((attr = ippAddCollections(p->ppd_attrs, IPP_TAG_PRINTER, + "media-size-supported", num_media, + NULL)) != NULL) + { + val = attr->values; + + for (i = p->pc->num_sizes, pwgsize = p->pc->sizes; + i > 0; + i --, pwgsize ++, val ++) + { + val->collection = ippNew(); + ippAddInteger(val->collection, IPP_TAG_PRINTER, IPP_TAG_INTEGER, + "x-dimension", pwgsize->width); + ippAddInteger(val->collection, IPP_TAG_PRINTER, IPP_TAG_INTEGER, + "y-dimension", pwgsize->length); + } + + if (p->pc->custom_min_keyword) + { + val->collection = ippNew(); + ippAddRange(val->collection, IPP_TAG_PRINTER, "x-dimension", + p->pc->custom_min_width, p->pc->custom_max_width); + ippAddRange(val->collection, IPP_TAG_PRINTER, "y-dimension", + p->pc->custom_min_length, p->pc->custom_max_length); + } + } + + /* * media-source-supported */ @@ -5021,12 +4807,13 @@ load_ppd(cupsd_printer_t *p) /* I - Printer */ "printer-make-and-model", NULL, "Local System V Printer"); } - else if (!strncmp(p->device_uri, "ipp://", 6) && - (strstr(p->device_uri, "/printers/") != NULL || - strstr(p->device_uri, "/classes/") != NULL || - (strstr(p->device_uri, "._ipp.") != NULL && - !strcmp(p->device_uri + strlen(p->device_uri) - 5, - "/cups")))) + else if (((!strncmp(p->device_uri, "ipp://", 6) || + !strncmp(p->device_uri, "ipps://", 7)) && + (strstr(p->device_uri, "/printers/") != NULL || + strstr(p->device_uri, "/classes/") != NULL)) || + ((strstr(p->device_uri, "._ipp.") != NULL || + strstr(p->device_uri, "._ipps.") != NULL) && + !strcmp(p->device_uri + strlen(p->device_uri) - 5, "/cups"))) { /* * Tell the client this is really a hard-wired remote printer. @@ -5145,6 +4932,8 @@ log_ipp_conformance( message = "Printer does not support REQUIRED Validate-Job operation."; else if (!strcmp(reason, "missing-get-printer-attributes")) message = "Printer does not support REQUIRED Get-Printer-Attributes operation."; + else if (!strcmp(reason, "missing-send-document")) + message = "Printer supports Create-Job but not Send-Document operation."; else if (!strcmp(reason, "missing-job-history")) message = "Printer does not provide REQUIRED job history."; else if (!strcmp(reason, "missing-job-id")) @@ -5528,5 +5317,5 @@ write_xml_string(cups_file_t *fp, /* I - File to write to */ /* - * End of "$Id: printers.c 10295 2012-02-15 23:21:06Z mike $". + * End of "$Id: printers.c 11173 2013-07-23 12:31:34Z msweet $". */ diff --git a/scheduler/printers.h b/scheduler/printers.h index 5a551a4..ad89d70 100644 --- a/scheduler/printers.h +++ b/scheduler/printers.h @@ -1,9 +1,9 @@ /* - * "$Id: printers.h 9621 2011-03-18 18:42:46Z mike $" + * "$Id: printers.h 11173 2013-07-23 12:31:34Z msweet $" * * Printer definitions for the CUPS scheduler. * - * Copyright 2007-2011 by Apple Inc. + * Copyright 2007-2012 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -15,6 +15,11 @@ #ifdef HAVE_DNSSD # include <dns_sd.h> +#elif defined(HAVE_AVAHI) +# include <avahi-client/client.h> +# include <avahi-client/publish.h> +# include <avahi-common/error.h> +# include <avahi-common/thread-watch.h> #endif /* HAVE_DNSSD */ #include <cups/pwg-private.h> @@ -33,6 +38,20 @@ typedef struct /* + * DNS-SD types to make the code cleaner/clearer... + */ + +#ifdef HAVE_DNSSD +typedef DNSServiceRef cupsd_srv_t; /* Service reference */ +typedef TXTRecordRef cupsd_txt_t; /* TXT record */ + +#elif defined(HAVE_AVAHI) +typedef AvahiEntryGroup *cupsd_srv_t; /* Service reference */ +typedef AvahiStringList *cupsd_txt_t; /* TXT record */ +#endif /* HAVE_DNSSD */ + + +/* * Printer/class information structure... */ @@ -61,9 +80,6 @@ struct cupsd_printer_s time_t state_time; /* Time at this state */ char *job_sheets[2]; /* Banners/job sheets */ cups_ptype_t type; /* Printer type (color, small, etc.) */ - char *browse_attrs; /* Attributes sent with browse data */ - time_t browse_expire; /* Expiration time for printer */ - time_t browse_time; /* Last time update was sent/received */ char *device_uri; /* Device URI */ char *sanitized_device_uri; /* Sanitized device URI */ char *port_monitor; /* Port monitor */ @@ -95,16 +111,17 @@ struct cupsd_printer_s time_t marker_time; /* Last time marker attributes were updated */ _ppd_cache_t *pc; /* PPD cache and mapping data */ -#ifdef HAVE_DNSSD +#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) char *reg_name, /* Name used for service registration */ - *pdl, /* pdl value for TXT record */ - *ipp_txt, /* IPP TXT record contents */ - *printer_txt; /* LPD TXT record contents */ - int ipp_len, /* IPP TXT record length */ - printer_len; /* LPD TXT record length */ - DNSServiceRef ipp_ref, /* Reference for _ipp._tcp,_cups */ - printer_ref; /* Reference for _printer._tcp */ -#endif /* HAVE_DNSSD */ + *pdl; /* pdl value for TXT record */ + cupsd_srv_t ipp_srv; /* IPP service(s) */ +# ifdef HAVE_DNSSD +# ifdef HAVE_SSL + cupsd_srv_t ipps_srv; /* IPPS service(s) */ +# endif /* HAVE_SSL */ + cupsd_srv_t printer_srv; /* LPD service */ +# endif /* HAVE_DNSSD */ +#endif /* HAVE_DNSSD || HAVE_AVAHI */ }; @@ -116,10 +133,8 @@ VAR ipp_t *CommonData VALUE(NULL); /* Common printer object attrs */ VAR cups_array_t *CommonDefaults VALUE(NULL); /* Common -default option names */ -VAR cups_array_t *Printers VALUE(NULL), +VAR cups_array_t *Printers VALUE(NULL); /* Printer list */ - *ImplicitPrinters VALUE(NULL); - /* Implicit class printers */ VAR cupsd_printer_t *DefaultPrinter VALUE(NULL); /* Default printer */ VAR char *DefaultPolicy VALUE(NULL); @@ -157,7 +172,8 @@ extern int cupsdSetPrinterReasons(cupsd_printer_t *p, const char *s); extern void cupsdSetPrinterState(cupsd_printer_t *p, ipp_pstate_t s, int update); -#define cupsdStartPrinter(p,u) cupsdSetPrinterState((p), IPP_PRINTER_IDLE, (u)) +#define cupsdStartPrinter(p,u) cupsdSetPrinterState((p), \ + IPP_PRINTER_IDLE, (u)) extern void cupsdStopPrinter(cupsd_printer_t *p, int update); extern int cupsdUpdatePrinterPPD(cupsd_printer_t *p, int num_keywords, @@ -173,5 +189,5 @@ extern void cupsdWritePrintcap(void); /* - * End of "$Id: printers.h 9621 2011-03-18 18:42:46Z mike $". + * End of "$Id: printers.h 11173 2013-07-23 12:31:34Z msweet $". */ diff --git a/scheduler/process.c b/scheduler/process.c index c1ca526..a706ac2 100644 --- a/scheduler/process.c +++ b/scheduler/process.c @@ -1,9 +1,9 @@ /* - * "$Id: process.c 9790 2011-05-19 22:40:03Z mike $" + * "$Id: process.c 11173 2013-07-23 12:31:34Z msweet $" * * Process management routines for the CUPS scheduler. * - * Copyright 2007-2011 by Apple Inc. + * Copyright 2007-2012 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -365,8 +365,8 @@ cupsdStartProcess( if (envp) { /* - * Add special voodoo magic for Mac OS X - this allows Mac OS X - * programs to access their bundle resources properly... + * Add special voodoo magic for OS X - this allows OS X programs to access + * their bundle resources properly... */ if ((linkbytes = readlink(command, linkpath, sizeof(linkpath) - 1)) > 0) @@ -577,7 +577,7 @@ cupsdStartProcess( { if (!process_array) process_array = cupsArrayNew((cups_array_func_t)compare_procs, NULL); - + if (process_array) { if ((proc = calloc(1, sizeof(cupsd_proc_t) + strlen(command))) != NULL) @@ -652,5 +652,5 @@ cupsd_requote(char *dst, /* I - Destination buffer */ /* - * End of "$Id: process.c 9790 2011-05-19 22:40:03Z mike $". + * End of "$Id: process.c 11173 2013-07-23 12:31:34Z msweet $". */ diff --git a/scheduler/quotas.c b/scheduler/quotas.c index 5051756..3ebfd8d 100644 --- a/scheduler/quotas.c +++ b/scheduler/quotas.c @@ -1,5 +1,5 @@ /* - * "$Id: quotas.c 9793 2011-05-20 03:49:49Z mike $" + * "$Id: quotas.c 11173 2013-07-23 12:31:34Z msweet $" * * Quota routines for the CUPS scheduler. * @@ -240,5 +240,5 @@ compare_quotas(const cupsd_quota_t *q1, /* I - First quota record */ /* - * End of "$Id: quotas.c 9793 2011-05-20 03:49:49Z mike $". + * End of "$Id: quotas.c 11173 2013-07-23 12:31:34Z msweet $". */ diff --git a/scheduler/select.c b/scheduler/select.c index 99a2325..e2f40d8 100644 --- a/scheduler/select.c +++ b/scheduler/select.c @@ -1,5 +1,5 @@ /* - * "$Id: select.c 9350 2010-11-04 23:23:25Z mike $" + * "$Id: select.c 11173 2013-07-23 12:31:34Z msweet $" * * Select abstraction functions for the CUPS scheduler. * @@ -33,12 +33,12 @@ #ifdef HAVE_EPOLL # include <sys/epoll.h> -# include <sys/poll.h> +# include <poll.h> #elif defined(HAVE_KQUEUE) # include <sys/event.h> # include <sys/time.h> #elif defined(HAVE_POLL) -# include <sys/poll.h> +# include <poll.h> #elif defined(__hpux) # include <sys/time.h> #else @@ -947,5 +947,5 @@ find_fd(int fd) /* I - File descriptor */ /* - * End of "$Id: select.c 9350 2010-11-04 23:23:25Z mike $". + * End of "$Id: select.c 11173 2013-07-23 12:31:34Z msweet $". */ diff --git a/scheduler/server.c b/scheduler/server.c index ace9cc9..7e511c4 100644 --- a/scheduler/server.c +++ b/scheduler/server.c @@ -1,9 +1,9 @@ /* - * "$Id: server.c 9632 2011-03-21 02:12:14Z mike $" + * "$Id: server.c 11173 2013-07-23 12:31:34Z msweet $" * * Server start/stop routines for the CUPS scheduler. * - * Copyright 2007-2010 by Apple Inc. + * Copyright 2007-2012 by Apple Inc. * Copyright 1997-2006 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -45,6 +45,12 @@ void cupsdStartServer(void) { /* + * Start color management (as needed)... + */ + + cupsdStartColor(); + + /* * Create the default security profile... */ @@ -56,7 +62,6 @@ cupsdStartServer(void) cupsdStartListening(); cupsdStartBrowsing(); - cupsdStartPolling(); /* * Create a pipe for CGI processes... @@ -95,12 +100,17 @@ cupsdStopServer(void) return; /* - * Close all network clients and stop all jobs... + * Stop color management (as needed)... + */ + + cupsdStopColor(); + + /* + * Close all network clients... */ cupsdCloseAllClients(); cupsdStopListening(); - cupsdStopPolling(); cupsdStopBrowsing(); cupsdStopAllNotifiers(); cupsdDeleteAllCerts(); @@ -126,16 +136,6 @@ cupsdStopServer(void) CGIPipes[1] = -1; } -#ifdef HAVE_NOTIFY_POST - /* - * Send one last notification as the server shuts down. - */ - - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "notify_post(\"com.apple.printerListChange\") last"); - notify_post("com.apple.printerListChange"); -#endif /* HAVE_NOTIFY_POST */ - /* * Close all log files... */ @@ -180,5 +180,5 @@ cupsdStopServer(void) /* - * End of "$Id: server.c 9632 2011-03-21 02:12:14Z mike $". + * End of "$Id: server.c 11173 2013-07-23 12:31:34Z msweet $". */ diff --git a/scheduler/statbuf.c b/scheduler/statbuf.c index cb75877..7f99149 100644 --- a/scheduler/statbuf.c +++ b/scheduler/statbuf.c @@ -1,5 +1,5 @@ /* - * "$Id: statbuf.c 9350 2010-11-04 23:23:25Z mike $" + * "$Id: statbuf.c 11173 2013-07-23 12:31:34Z msweet $" * * Status buffer routines for the CUPS scheduler. * @@ -326,5 +326,5 @@ cupsdStatBufUpdate( /* - * End of "$Id: statbuf.c 9350 2010-11-04 23:23:25Z mike $". + * End of "$Id: statbuf.c 11173 2013-07-23 12:31:34Z msweet $". */ diff --git a/scheduler/statbuf.h b/scheduler/statbuf.h index acb793d..91564d0 100644 --- a/scheduler/statbuf.h +++ b/scheduler/statbuf.h @@ -1,5 +1,5 @@ /* - * "$Id: statbuf.h 9350 2010-11-04 23:23:25Z mike $" + * "$Id: statbuf.h 11173 2013-07-23 12:31:34Z msweet $" * * Status buffer definitions for the CUPS scheduler. * @@ -45,5 +45,5 @@ extern char *cupsdStatBufUpdate(cupsd_statbuf_t *sb, int *loglevel, /* - * End of "$Id: statbuf.h 9350 2010-11-04 23:23:25Z mike $". + * End of "$Id: statbuf.h 11173 2013-07-23 12:31:34Z msweet $". */ diff --git a/scheduler/subscriptions.c b/scheduler/subscriptions.c index e1e8219..0b9c452 100644 --- a/scheduler/subscriptions.c +++ b/scheduler/subscriptions.c @@ -1,5 +1,5 @@ /* - * "$Id: subscriptions.c 10262 2012-02-12 05:48:09Z mike $" + * "$Id: subscriptions.c 11173 2013-07-23 12:31:34Z msweet $" * * Subscription routines for the CUPS scheduler. * @@ -1638,5 +1638,5 @@ cupsd_update_notifier(void) /* - * End of "$Id: subscriptions.c 10262 2012-02-12 05:48:09Z mike $". + * End of "$Id: subscriptions.c 11173 2013-07-23 12:31:34Z msweet $". */ diff --git a/scheduler/subscriptions.h b/scheduler/subscriptions.h index 20d59b7..1a786ae 100644 --- a/scheduler/subscriptions.h +++ b/scheduler/subscriptions.h @@ -1,5 +1,5 @@ /* - * "$Id: subscriptions.h 9350 2010-11-04 23:23:25Z mike $" + * "$Id: subscriptions.h 11173 2013-07-23 12:31:34Z msweet $" * * Subscription definitions for the CUPS scheduler. * @@ -162,5 +162,5 @@ extern void cupsdStopAllNotifiers(void); /* - * End of "$Id: subscriptions.h 9350 2010-11-04 23:23:25Z mike $". + * End of "$Id: subscriptions.h 11173 2013-07-23 12:31:34Z msweet $". */ diff --git a/scheduler/sysman.c b/scheduler/sysman.c index bd7052b..d5f82c1 100644 --- a/scheduler/sysman.c +++ b/scheduler/sysman.c @@ -1,9 +1,9 @@ /* - * "$Id: sysman.c 10273 2012-02-13 20:30:23Z mike $" + * "$Id: sysman.c 11173 2013-07-23 12:31:34Z msweet $" * * System management functions for the CUPS scheduler. * - * Copyright 2007-2012 by Apple Inc. + * Copyright 2007-2011 by Apple Inc. * Copyright 2006 by Easy Software Products. * * These coded instructions, statements, and computer programs are the @@ -87,9 +87,6 @@ cupsdCleanDirty(void) if (DirtyFiles & CUPSD_DIRTY_CLASSES) cupsdSaveAllClasses(); - if (DirtyFiles & CUPSD_DIRTY_REMOTE) - cupsdSaveRemoteCache(); - if (DirtyFiles & CUPSD_DIRTY_PRINTCAP) cupsdWritePrintcap(); @@ -123,10 +120,9 @@ cupsdCleanDirty(void) void cupsdMarkDirty(int what) /* I - What file(s) are dirty? */ { - cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdMarkDirty(%c%c%c%c%c%c)", + cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdMarkDirty(%c%c%c%c%c)", (what & CUPSD_DIRTY_PRINTERS) ? 'P' : '-', (what & CUPSD_DIRTY_CLASSES) ? 'C' : '-', - (what & CUPSD_DIRTY_REMOTE) ? 'R' : '-', (what & CUPSD_DIRTY_PRINTCAP) ? 'p' : '-', (what & CUPSD_DIRTY_JOBS) ? 'J' : '-', (what & CUPSD_DIRTY_SUBSCRIPTIONS) ? 'S' : '-'); @@ -865,20 +861,9 @@ sysUpdate(void) p; p = (cupsd_printer_t *)cupsArrayNext(Printers)) { - if (p->type & CUPS_PRINTER_DISCOVERED) - { - cupsdLogMessage(CUPSD_LOG_DEBUG, - "Deleting remote destination \"%s\"", p->name); - cupsArraySave(Printers); - cupsdDeletePrinter(p, 0); - cupsArrayRestore(Printers); - } - else - { - cupsdLogMessage(CUPSD_LOG_DEBUG, - "Deregistering local printer \"%s\"", p->name); - cupsdDeregisterPrinter(p, 0); - } + cupsdLogMessage(CUPSD_LOG_DEBUG, + "Deregistering local printer \"%s\"", p->name); + cupsdDeregisterPrinter(p, 0); } cupsdCleanDirty(); @@ -965,23 +950,8 @@ sysUpdate(void) if (sysevent.event & SYSEVENT_NETCHANGED) { if (!Sleeping) - { cupsdLogMessage(CUPSD_LOG_DEBUG, "System network configuration changed"); - - /* - * Resetting browse_time before calling cupsdSendBrowseList causes - * browse packets to be sent for local shared printers. - */ - - for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); - p; - p = (cupsd_printer_t *)cupsArrayNext(Printers)) - p->browse_time = 0; - - cupsdSendBrowseList(); - cupsdRestartPolling(); - } else cupsdLogMessage(CUPSD_LOG_DEBUG, "System network configuration changed; " @@ -1004,11 +974,13 @@ sysUpdate(void) p = (cupsd_printer_t *)cupsArrayNext(Printers)) cupsdDeregisterPrinter(p, 1); +# if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) /* * Update the computer name and BTMM domain list... */ cupsdUpdateDNSSDName(); +# endif /* HAVE_DNSSD || HAVE_AVAHI */ /* * Now re-register them... @@ -1017,10 +989,7 @@ sysUpdate(void) for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); p; p = (cupsd_printer_t *)cupsArrayNext(Printers)) - { - p->browse_time = 0; cupsdRegisterPrinter(p); - } } else cupsdLogMessage(CUPSD_LOG_DEBUG, @@ -1033,5 +1002,5 @@ sysUpdate(void) /* - * End of "$Id: sysman.c 10273 2012-02-13 20:30:23Z mike $". + * End of "$Id: sysman.c 11173 2013-07-23 12:31:34Z msweet $". */ diff --git a/scheduler/sysman.h b/scheduler/sysman.h index b47655f..d603178 100644 --- a/scheduler/sysman.h +++ b/scheduler/sysman.h @@ -1,9 +1,9 @@ /* - * "$Id: sysman.h 9350 2010-11-04 23:23:25Z mike $" + * "$Id: sysman.h 11173 2013-07-23 12:31:34Z msweet $" * * System management definitions for the CUPS scheduler. * - * Copyright 2007-2010 by Apple Inc. + * Copyright 2007-2011 by Apple Inc. * Copyright 2006 by Easy Software Products. * * These coded instructions, statements, and computer programs are the @@ -20,10 +20,10 @@ #define CUPSD_DIRTY_NONE 0 /* Nothing is dirty */ #define CUPSD_DIRTY_PRINTERS 1 /* printers.conf is dirty */ #define CUPSD_DIRTY_CLASSES 2 /* classes.conf is dirty */ -#define CUPSD_DIRTY_REMOTE 4 /* remote.cache is dirty */ -#define CUPSD_DIRTY_PRINTCAP 8 /* printcap is dirty */ -#define CUPSD_DIRTY_JOBS 16 /* jobs.cache or "c" file(s) are dirty */ -#define CUPSD_DIRTY_SUBSCRIPTIONS 32 /* subscriptions.conf is dirty */ +#define CUPSD_DIRTY_PRINTCAP 4 /* printcap is dirty */ +#define CUPSD_DIRTY_JOBS 8 /* jobs.cache or "c" file(s) are dirty */ +#define CUPSD_DIRTY_SUBSCRIPTIONS 16 /* subscriptions.conf is dirty */ + /* * Globals... @@ -60,5 +60,5 @@ extern void cupsdStopSystemMonitor(void); /* - * End of "$Id: sysman.h 9350 2010-11-04 23:23:25Z mike $". + * End of "$Id: sysman.h 11173 2013-07-23 12:31:34Z msweet $". */ diff --git a/scheduler/testdirsvc.c b/scheduler/testdirsvc.c deleted file mode 100644 index 3ffaf3b..0000000 --- a/scheduler/testdirsvc.c +++ /dev/null @@ -1,324 +0,0 @@ -/* - * "$Id: testdirsvc.c 9691 2011-04-15 23:38:13Z mike $" - * - * Browsing test program for CUPS. - * - * Copyright 2007-2011 by Apple Inc. - * Copyright 1997-2007 by Easy Software Products, all rights reserved. - * - * These coded instructions, statements, and computer programs are the - * property of Apple Inc. and are protected by Federal copyright - * law. Distribution and use rights are outlined in the file "LICENSE.txt" - * which should have been included with this file. If this file is - * file is missing or damaged, see the license at "http://www.cups.org/". - * - * Contents: - * - * main() - Simulate one or more remote printers. - * usage() - Show program usage... - */ - -/* - * Include necessary headers... - */ - -#include <cups/cups.h> -#include <cups/string-private.h> - - -/* - * Local functions... - */ - -static void usage(void); - - -/* - * 'main()' - Simulate one or more remote printers. - */ - -int /* O - Exit status */ -main(int argc, /* I - Number of command-line arguments */ - char *argv[]) /* I - Command-line arguments */ -{ - int i, /* Looping var */ - printer, /* Current printer */ - num_printers, /* Number of printers */ - pclass, /* Current printer class */ - num_pclasses, /* Number of printer classes */ - server, /* Current server */ - num_servers, /* Number of servers */ - count, /* Number of printers sent this cycle */ - interval, /* Browse Interval */ - lease, /* Browse lease-duration */ - continuous, /* Run continuously? */ - port, /* Browse port */ - sock, /* Browse socket */ - val, /* Socket option value */ - seconds, /* Seconds until next cycle */ - verbose; /* Verbose output? */ - const char *options; /* Options for URIs */ - time_t curtime; /* Current UNIX time */ - struct tm *curdate; /* Current date and time */ - struct sockaddr_in addr; /* Broadcast address */ - char packet[1540]; /* Data packet */ - static const char * const names[26] = /* Printer names */ - { - "alpha", - "bravo", - "charlie", - "delta", - "echo", - "foxtrot", - "golf", - "hotel", - "india", - "juliet", - "kilo", - "lima", - "mike", - "november", - "oscar", - "papa", - "quebec", - "romeo", - "sierra", - "tango", - "uniform", - "victor", - "wiskey", - "x-ray", - "yankee", - "zulu" - }; - - - /* - * Process command-line arguments... - */ - - num_printers = 10; - num_pclasses = 5; - num_servers = 1; - interval = 30; - lease = 60; - port = 0; - verbose = 0; - continuous = 0; - options = NULL; - - for (i = 1; i < argc; i ++) - { - if (!strcmp(argv[i], "-c")) - continuous = 1; - else if (!strcmp(argv[i], "-i")) - { - i ++; - if (i < argc) - interval = atoi(argv[i]); - else - usage(); - - continuous = 1; - } - else if (!strcmp(argv[i], "-l")) - { - i ++; - if (i < argc) - lease = atoi(argv[i]); - else - usage(); - } - else if (!strcmp(argv[i], "-o")) - { - i ++; - if (i < argc) - options = argv[i]; - else - usage(); - } - else if (!strcmp(argv[i], "-C")) - { - i ++; - if (i < argc) - num_pclasses = atoi(argv[i]); - else - usage(); - } - else if (!strcmp(argv[i], "-p")) - { - i ++; - if (i < argc) - num_printers = atoi(argv[i]); - else - usage(); - } - else if (!strcmp(argv[i], "-s")) - { - i ++; - if (i < argc) - num_servers = atoi(argv[i]); - else - usage(); - } - else if (!strcmp(argv[i], "-v")) - verbose = 1; - else if (isdigit(argv[i][0] & 255)) - { - port = atoi(argv[i]); - } - else - usage(); - } - - if ((num_printers <= 0 && num_pclasses <= 0) || num_servers <= 0 || - interval <= 0 || lease < 1 || port <= 0) - usage(); - - /* - * Open a broadcast socket... - */ - - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) - { - perror("Unable to open broadcast socket"); - return (1); - } - - /* - * Set the "broadcast" flag... - */ - - val = 1; - if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &val, sizeof(val))) - { - perror("Unable to put socket in broadcast mode"); - - close(sock); - return (1); - } - - /* - * Broadcast to 127.0.0.1 (localhost) - */ - - memset(&addr, 0, sizeof(addr)); - addr.sin_addr.s_addr = htonl(0x7f000001); - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - - /* - * Send virtual printers continuously until we are stopped. - */ - - for (;;) - { - /* - * Start a new cycle of N printers... - */ - - printf("Sending %d printers from %d servers...\n", num_printers, - num_servers); - - count = num_servers * (num_printers + num_pclasses) / interval + 1; - curtime = time(NULL); - curdate = localtime(&curtime); - seconds = interval; - - for (i = 0, printer = 0; printer < num_printers; printer ++) - { - for (server = 0; server < num_servers; server ++, i ++) - { - if (i == count) - { - seconds --; - i = 0; - sleep(1); - curtime = time(NULL); - curdate = localtime(&curtime); - } - - snprintf(packet, sizeof(packet), - "%x %x ipp://testserver-%d/printers/%s-%d \"Server Room %d\" " - "\"Test Printer %d\" \"Acme Blazer 2000\"%s%s " - "lease-duration=%d\n", - CUPS_PRINTER_REMOTE, IPP_PRINTER_IDLE, server + 1, - names[printer % 26], printer / 26 + 1, server + 1, - printer + 1, options ? " ipp-options=" : "", - options ? options : "", lease); - - if (verbose) - printf("[%02d:%02d:%02d] %s", curdate->tm_hour, curdate->tm_min, - curdate->tm_sec, packet); - - if (sendto(sock, packet, strlen(packet), 0, - (struct sockaddr *)&addr, sizeof(addr)) < 0) - perror("Unabled to send packet"); - } - } - - - for (i = 0, pclass = 0; pclass < num_pclasses; pclass ++) - { - for (server = 0; server < num_servers; server ++, i ++) - { - if (i == count) - { - seconds --; - i = 0; - sleep(1); - curtime = time(NULL); - curdate = localtime(&curtime); - } - - snprintf(packet, sizeof(packet), - "%x %x ipp://testserver-%d/classes/class-%s-%d \"Server Room %d\" " - "\"Test Class %d\" \"Acme Blazer 2000\"%s%s " - "lease-duration=%d\n", - CUPS_PRINTER_REMOTE | CUPS_PRINTER_CLASS, IPP_PRINTER_IDLE, - server + 1, names[pclass % 26], pclass / 26 + 1, server + 1, - pclass + 1, options ? " ipp-options=" : "", - options ? options : "", lease); - - if (verbose) - printf("[%02d:%02d:%02d] %s", curdate->tm_hour, curdate->tm_min, - curdate->tm_sec, packet); - - if (sendto(sock, packet, strlen(packet), 0, - (struct sockaddr *)&addr, sizeof(addr)) < 0) - perror("Unabled to send packet"); - } - } - - if (!continuous) - break; - - /* - * Sleep for any remaining time... - */ - - if (seconds > 0) - sleep(seconds); - } - - return (0); -} - - -/* - * 'usage()' - Show program usage... - */ - -static void -usage(void) -{ - puts("Usage: testdirsvc [-c] [-i interval] [-l lease-duration] " - "[-o ipp-options] [-p printers] " - "[-C classes] [-s servers] [-v] port"); - exit(0); -} - - -/* - * End of "$Id: testdirsvc.c 9691 2011-04-15 23:38:13Z mike $". - */ diff --git a/scheduler/testlpd.c b/scheduler/testlpd.c index a7302ca..3ff483e 100644 --- a/scheduler/testlpd.c +++ b/scheduler/testlpd.c @@ -1,5 +1,5 @@ /* - * "$Id: testlpd.c 9042 2010-03-24 00:45:34Z mike $" + * "$Id: testlpd.c 11173 2013-07-23 12:31:34Z msweet $" * * cups-lpd test program for CUPS. * @@ -47,7 +47,7 @@ static int print_waiting(int outfd, int infd, char *dest); static int remove_job(int outfd, int infd, char *dest, char **args); static int status_long(int outfd, int infd, char *dest, char **args); static int status_short(int outfd, int infd, char *dest, char **args); -static void usage(void); +static void usage(void) __attribute__((noreturn)); /* @@ -546,5 +546,5 @@ usage(void) /* - * End of "$Id: testlpd.c 9042 2010-03-24 00:45:34Z mike $". + * End of "$Id: testlpd.c 11173 2013-07-23 12:31:34Z msweet $". */ diff --git a/scheduler/testmime.c b/scheduler/testmime.c index de49544..5a71ea9 100644 --- a/scheduler/testmime.c +++ b/scheduler/testmime.c @@ -1,9 +1,9 @@ /* - * "$Id: testmime.c 9862 2011-08-03 02:44:09Z mike $" + * "$Id: testmime.c 11173 2013-07-23 12:31:34Z msweet $" * * MIME test program for CUPS. * - * Copyright 2007-2011 by Apple Inc. + * Copyright 2007-2013 by Apple Inc. * Copyright 1997-2006 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -132,7 +132,7 @@ main(int argc, /* I - Number of command-line args */ } else { - sscanf(argv[i], "%15[^/]/%31s", super, type); + sscanf(argv[i], "%15[^/]/%255s", super, type); dst = mimeType(mime, super, type); filters = mimeFilter2(mime, src, srcinfo.st_size, dst, &cost); @@ -527,5 +527,5 @@ type_dir(mime_t *mime, /* I - MIME database */ /* - * End of "$Id: testmime.c 9862 2011-08-03 02:44:09Z mike $". + * End of "$Id: testmime.c 11173 2013-07-23 12:31:34Z msweet $". */ diff --git a/scheduler/testspeed.c b/scheduler/testspeed.c index 1fe0a33..425f471 100644 --- a/scheduler/testspeed.c +++ b/scheduler/testspeed.c @@ -1,5 +1,5 @@ /* - * "$Id: testspeed.c 9042 2010-03-24 00:45:34Z mike $" + * "$Id: testspeed.c 11173 2013-07-23 12:31:34Z msweet $" * * Scheduler speed test for CUPS. * @@ -40,7 +40,7 @@ static int do_test(const char *server, int port, http_encryption_t encryption, int requests, int verbose); -static void usage(void); +static void usage(void) __attribute__((noreturn)); /* @@ -361,5 +361,5 @@ usage(void) /* - * End of "$Id: testspeed.c 9042 2010-03-24 00:45:34Z mike $". + * End of "$Id: testspeed.c 11173 2013-07-23 12:31:34Z msweet $". */ diff --git a/scheduler/testsub.c b/scheduler/testsub.c index bff8e8b..66801af 100644 --- a/scheduler/testsub.c +++ b/scheduler/testsub.c @@ -1,9 +1,9 @@ /* - * "$Id: testsub.c 9042 2010-03-24 00:45:34Z mike $" + * "$Id: testsub.c 11173 2013-07-23 12:31:34Z msweet $" * * Scheduler notification tester for CUPS. * - * Copyright 2007-2010 by Apple Inc. + * Copyright 2007-2012 by Apple Inc. * Copyright 2006-2007 by Easy Software Products. * * These coded instructions, statements, and computer programs are the @@ -28,6 +28,7 @@ #include <cups/debug-private.h> #include <cups/string-private.h> #include <signal.h> +#include <cups/ipp-private.h> /* TODO: Update so we don't need this */ /* @@ -43,7 +44,7 @@ static int terminate = 0; static void print_attributes(ipp_t *ipp, int indent); static void sigterm_handler(int sig); -static void usage(void); +static void usage(void) __attribute__((noreturn)); /* @@ -302,7 +303,7 @@ print_attributes(ipp_t *ipp, /* I - IPP request */ int i; /* Looping var */ ipp_tag_t group; /* Current group */ ipp_attribute_t *attr; /* Current attribute */ - ipp_value_t *val; /* Current value */ + _ipp_value_t *val; /* Current value */ static const char * const tags[] = /* Value/group tag strings */ { "reserved-00", @@ -452,7 +453,7 @@ print_attributes(ipp_t *ipp, /* I - IPP request */ case IPP_TAG_RESOLUTION : for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++) printf(" %dx%d%s", val->resolution.xres, val->resolution.yres, - val->resolution.units == IPP_RES_PER_INCH ? "dpi" : "dpc"); + val->resolution.units == IPP_RES_PER_INCH ? "dpi" : "dpcm"); putchar('\n'); break; @@ -518,5 +519,5 @@ usage(void) /* - * End of "$Id: testsub.c 9042 2010-03-24 00:45:34Z mike $". + * End of "$Id: testsub.c 11173 2013-07-23 12:31:34Z msweet $". */ diff --git a/scheduler/tls-darwin.c b/scheduler/tls-darwin.c new file mode 100644 index 0000000..bb6998b --- /dev/null +++ b/scheduler/tls-darwin.c @@ -0,0 +1,570 @@ +/* + * "$Id: tls-darwin.c 11173 2013-07-23 12:31:34Z msweet $" + * + * TLS support code for the CUPS scheduler on OS X. + * + * Copyright 2007-2012 by Apple Inc. + * Copyright 1997-2007 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Apple Inc. and are protected by Federal copyright + * law. Distribution and use rights are outlined in the file "LICENSE.txt" + * which should have been included with this file. If this file is + * file is missing or damaged, see the license at "http://www.cups.org/". + * + * Contents: + * + * cupsdEndTLS() - Shutdown a secure session with the client. + * cupsdStartTLS() - Start a secure session with the client. + * copy_cdsa_certificate() - Copy a SSL/TLS certificate from the System + * keychain. + * make_certificate() - Make a self-signed SSL/TLS certificate. + */ + + +/* + * Local functions... + */ + +static CFArrayRef copy_cdsa_certificate(cupsd_client_t *con); +static int make_certificate(cupsd_client_t *con); + + +/* + * 'cupsdEndTLS()' - Shutdown a secure session with the client. + */ + +int /* O - 1 on success, 0 on error */ +cupsdEndTLS(cupsd_client_t *con) /* I - Client connection */ +{ + while (SSLClose(con->http.tls) == errSSLWouldBlock) + usleep(1000); + + SSLDisposeContext(con->http.tls); + con->http.tls = NULL; + + if (con->http.tls_credentials) + CFRelease(con->http.tls_credentials); + + return (1); +} + + +/* + * 'cupsdStartTLS()' - Start a secure session with the client. + */ + +int /* O - 1 on success, 0 on error */ +cupsdStartTLS(cupsd_client_t *con) /* I - Client connection */ +{ + OSStatus error = 0; /* Error code */ + CFArrayRef peerCerts; /* Peer certificates */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG, "[Client %d] Encrypting connection.", + con->http.fd); + + con->http.tls_credentials = copy_cdsa_certificate(con); + + if (!con->http.tls_credentials) + { + /* + * No keychain (yet), make a self-signed certificate... + */ + + if (make_certificate(con)) + con->http.tls_credentials = copy_cdsa_certificate(con); + } + + if (!con->http.tls_credentials) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Could not find signing key in keychain \"%s\"", + ServerCertificate); + error = errSSLBadConfiguration; + } + + if (!error) + error = SSLNewContext(true, &con->http.tls); + + if (!error) + error = SSLSetIOFuncs(con->http.tls, _httpReadCDSA, _httpWriteCDSA); + + if (!error) + error = SSLSetConnection(con->http.tls, HTTP(con)); + + if (!error) + error = SSLSetAllowsExpiredCerts(con->http.tls, true); + + if (!error) + error = SSLSetAllowsAnyRoot(con->http.tls, true); + + if (!error) + error = SSLSetCertificate(con->http.tls, con->http.tls_credentials); + + if (!error) + { + /* + * Perform SSL/TLS handshake + */ + + while ((error = SSLHandshake(con->http.tls)) == errSSLWouldBlock) + usleep(1000); + } + + if (error) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to encrypt connection from %s - %s (%d)", + con->http.hostname, cssmErrorString(error), (int)error); + + con->http.error = error; + con->http.status = HTTP_ERROR; + + if (con->http.tls) + { + SSLDisposeContext(con->http.tls); + con->http.tls = NULL; + } + + if (con->http.tls_credentials) + { + CFRelease(con->http.tls_credentials); + con->http.tls_credentials = NULL; + } + + return (0); + } + + cupsdLogMessage(CUPSD_LOG_DEBUG, "Connection from %s now encrypted.", + con->http.hostname); + + if (!SSLCopyPeerCertificates(con->http.tls, &peerCerts) && peerCerts) + { + cupsdLogMessage(CUPSD_LOG_DEBUG, "Received %d peer certificates!", + (int)CFArrayGetCount(peerCerts)); + CFRelease(peerCerts); + } + else + cupsdLogMessage(CUPSD_LOG_DEBUG, "Received NO peer certificates!"); + + return (1); +} + + +/* + * 'copy_cdsa_certificate()' - Copy a SSL/TLS certificate from the System + * keychain. + */ + +static CFArrayRef /* O - Array of certificates */ +copy_cdsa_certificate( + cupsd_client_t *con) /* I - Client connection */ +{ + OSStatus err; /* Error info */ + SecKeychainRef keychain = NULL;/* Keychain reference */ + SecIdentitySearchRef search = NULL; /* Search reference */ + SecIdentityRef identity = NULL;/* Identity */ + CFArrayRef certificates = NULL; + /* Certificate array */ +# if HAVE_SECPOLICYCREATESSL + SecPolicyRef policy = NULL; /* Policy ref */ + CFStringRef servername = NULL; + /* Server name */ + CFMutableDictionaryRef query = NULL; /* Query qualifiers */ + CFArrayRef list = NULL; /* Keychain list */ +# if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) + char localname[1024];/* Local hostname */ +# endif /* HAVE_DNSSD || HAVE_AVAHI */ +# elif defined(HAVE_SECIDENTITYSEARCHCREATEWITHPOLICY) + SecPolicyRef policy = NULL; /* Policy ref */ + SecPolicySearchRef policy_search = NULL; + /* Policy search ref */ + CSSM_DATA options; /* Policy options */ + CSSM_APPLE_TP_SSL_OPTIONS + ssl_options; /* SSL Option for hostname */ + char localname[1024];/* Local hostname */ +# endif /* HAVE_SECPOLICYCREATESSL */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG, + "copy_cdsa_certificate: Looking for certs for \"%s\"...", + con->servername); + + if ((err = SecKeychainOpen(ServerCertificate, &keychain))) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot open keychain \"%s\" - %s (%d)", + ServerCertificate, cssmErrorString(err), (int)err); + goto cleanup; + } + +# if HAVE_SECPOLICYCREATESSL + servername = CFStringCreateWithCString(kCFAllocatorDefault, con->servername, + kCFStringEncodingUTF8); + + policy = SecPolicyCreateSSL(1, servername); + + if (servername) + CFRelease(servername); + + if (!policy) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot create ssl policy reference"); + goto cleanup; + } + + if (!(query = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks))) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot create query dictionary"); + goto cleanup; + } + + list = CFArrayCreate(kCFAllocatorDefault, (const void **)&keychain, 1, + &kCFTypeArrayCallBacks); + + CFDictionaryAddValue(query, kSecClass, kSecClassIdentity); + CFDictionaryAddValue(query, kSecMatchPolicy, policy); + CFDictionaryAddValue(query, kSecReturnRef, kCFBooleanTrue); + CFDictionaryAddValue(query, kSecMatchLimit, kSecMatchLimitOne); + CFDictionaryAddValue(query, kSecMatchSearchList, list); + + CFRelease(list); + + err = SecItemCopyMatching(query, (CFTypeRef *)&identity); + +# if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) + if (err && DNSSDHostName) + { + /* + * Search for the connection server name failed; try the DNS-SD .local + * hostname instead... + */ + + snprintf(localname, sizeof(localname), "%s.local", DNSSDHostName); + + cupsdLogMessage(CUPSD_LOG_DEBUG, + "copy_cdsa_certificate: Looking for certs for \"%s\"...", + localname); + + servername = CFStringCreateWithCString(kCFAllocatorDefault, localname, + kCFStringEncodingUTF8); + + CFRelease(policy); + + policy = SecPolicyCreateSSL(1, servername); + + if (servername) + CFRelease(servername); + + if (!policy) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot create ssl policy reference"); + goto cleanup; + } + + CFDictionarySetValue(query, kSecMatchPolicy, policy); + + err = SecItemCopyMatching(query, (CFTypeRef *)&identity); + } +# endif /* HAVE_DNSSD || HAVE_AVAHI */ + + if (err) + { + cupsdLogMessage(CUPSD_LOG_DEBUG, + "Cannot find signing key in keychain \"%s\": %s (%d)", + ServerCertificate, cssmErrorString(err), (int)err); + goto cleanup; + } + +# elif defined(HAVE_SECIDENTITYSEARCHCREATEWITHPOLICY) + /* + * Use a policy to search for valid certificates whose common name matches the + * servername... + */ + + if (SecPolicySearchCreate(CSSM_CERT_X_509v3, &CSSMOID_APPLE_TP_SSL, + NULL, &policy_search)) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot create a policy search reference"); + goto cleanup; + } + + if (SecPolicySearchCopyNext(policy_search, &policy)) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Cannot find a policy to use for searching"); + goto cleanup; + } + + memset(&ssl_options, 0, sizeof(ssl_options)); + ssl_options.Version = CSSM_APPLE_TP_SSL_OPTS_VERSION; + ssl_options.ServerName = con->servername; + ssl_options.ServerNameLen = strlen(con->servername); + + options.Data = (uint8 *)&ssl_options; + options.Length = sizeof(ssl_options); + + if (SecPolicySetValue(policy, &options)) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Cannot set policy value to use for searching"); + goto cleanup; + } + + if ((err = SecIdentitySearchCreateWithPolicy(policy, NULL, CSSM_KEYUSE_SIGN, + keychain, FALSE, &search))) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Cannot create identity search reference: %s (%d)", + cssmErrorString(err), (int)err); + goto cleanup; + } + + err = SecIdentitySearchCopyNext(search, &identity); + +# if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) + if (err && DNSSDHostName) + { + /* + * Search for the connection server name failed; try the DNS-SD .local + * hostname instead... + */ + + snprintf(localname, sizeof(localname), "%s.local", DNSSDHostName); + + ssl_options.ServerName = localname; + ssl_options.ServerNameLen = strlen(localname); + + cupsdLogMessage(CUPSD_LOG_DEBUG, + "copy_cdsa_certificate: Looking for certs for \"%s\"...", + localname); + + if (SecPolicySetValue(policy, &options)) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Cannot set policy value to use for searching"); + goto cleanup; + } + + CFRelease(search); + search = NULL; + if ((err = SecIdentitySearchCreateWithPolicy(policy, NULL, CSSM_KEYUSE_SIGN, + keychain, FALSE, &search))) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Cannot create identity search reference: %s (%d)", + cssmErrorString(err), (int)err); + goto cleanup; + } + + err = SecIdentitySearchCopyNext(search, &identity); + + } +# endif /* HAVE_DNSSD || HAVE_AVAHI */ + + if (err) + { + cupsdLogMessage(CUPSD_LOG_DEBUG, + "Cannot find signing key in keychain \"%s\": %s (%d)", + ServerCertificate, cssmErrorString(err), (int)err); + goto cleanup; + } + +# else + /* + * Assume there is exactly one SecIdentity in the keychain... + */ + + if ((err = SecIdentitySearchCreate(keychain, CSSM_KEYUSE_SIGN, &search))) + { + cupsdLogMessage(CUPSD_LOG_DEBUG, + "Cannot create identity search reference (%d)", (int)err); + goto cleanup; + } + + if ((err = SecIdentitySearchCopyNext(search, &identity))) + { + cupsdLogMessage(CUPSD_LOG_DEBUG, + "Cannot find signing key in keychain \"%s\": %s (%d)", + ServerCertificate, cssmErrorString(err), (int)err); + goto cleanup; + } +# endif /* HAVE_SECPOLICYCREATESSL */ + + if (CFGetTypeID(identity) != SecIdentityGetTypeID()) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "SecIdentity CFTypeID failure!"); + goto cleanup; + } + + if ((certificates = CFArrayCreate(NULL, (const void **)&identity, + 1, &kCFTypeArrayCallBacks)) == NULL) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot create certificate array"); + goto cleanup; + } + + cleanup : + + if (keychain) + CFRelease(keychain); + if (search) + CFRelease(search); + if (identity) + CFRelease(identity); + +# if HAVE_SECPOLICYCREATESSL + if (policy) + CFRelease(policy); + if (query) + CFRelease(query); +# elif defined(HAVE_SECIDENTITYSEARCHCREATEWITHPOLICY) + if (policy) + CFRelease(policy); + if (policy_search) + CFRelease(policy_search); +# endif /* HAVE_SECPOLICYCREATESSL */ + + return (certificates); +} + + +/* + * 'make_certificate()' - Make a self-signed SSL/TLS certificate. + */ + +static int /* O - 1 on success, 0 on failure */ +make_certificate(cupsd_client_t *con) /* I - Client connection */ +{ + int pid, /* Process ID of command */ + status; /* Status of command */ + char command[1024], /* Command */ + *argv[4], /* Command-line arguments */ + *envp[MAX_ENV + 1], /* Environment variables */ + keychain[1024], /* Keychain argument */ + infofile[1024], /* Type-in information for cert */ +# if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) + localname[1024], /* Local hostname */ +# endif /* HAVE_DNSSD || HAVE_AVAHI */ + *servername; /* Name of server in cert */ + cups_file_t *fp; /* Seed/info file */ + int infofd; /* Info file descriptor */ + + +# if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) + if (con->servername && isdigit(con->servername[0] & 255) && DNSSDHostName) + { + snprintf(localname, sizeof(localname), "%s.local", DNSSDHostName); + servername = localname; + } + else +# endif /* HAVE_DNSSD || HAVE_AVAHI */ + servername = con->servername; + + /* + * Run the "certtool" command to generate a self-signed certificate... + */ + + if (!cupsFileFind("certtool", getenv("PATH"), 1, command, sizeof(command))) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "No SSL certificate and certtool command not found!"); + return (0); + } + + /* + * Create a file with the certificate information fields... + * + * Note: This assumes that the default questions are asked by the certtool + * command... + */ + + if ((fp = cupsTempFile2(infofile, sizeof(infofile))) == NULL) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to create certificate information file %s - %s", + infofile, strerror(errno)); + return (0); + } + + cupsFilePrintf(fp, + "%s\n" /* Enter key and certificate label */ + "r\n" /* Generate RSA key pair */ + "2048\n" /* Key size in bits */ + "y\n" /* OK (y = yes) */ + "b\n" /* Usage (b=signing/encryption) */ + "s\n" /* Sign with SHA1 */ + "y\n" /* OK (y = yes) */ + "%s\n" /* Common name */ + "\n" /* Country (default) */ + "\n" /* Organization (default) */ + "\n" /* Organizational unit (default) */ + "\n" /* State/Province (default) */ + "%s\n" /* Email address */ + "y\n", /* OK (y = yes) */ + servername, servername, ServerAdmin); + cupsFileClose(fp); + + cupsdLogMessage(CUPSD_LOG_INFO, + "Generating SSL server key and certificate..."); + + snprintf(keychain, sizeof(keychain), "k=%s", ServerCertificate); + + argv[0] = "certtool"; + argv[1] = "c"; + argv[2] = keychain; + argv[3] = NULL; + + cupsdLoadEnv(envp, MAX_ENV); + + infofd = open(infofile, O_RDONLY); + + if (!cupsdStartProcess(command, argv, envp, infofd, -1, -1, -1, -1, 1, NULL, + NULL, &pid)) + { + close(infofd); + unlink(infofile); + return (0); + } + + close(infofd); + unlink(infofile); + + while (waitpid(pid, &status, 0) < 0) + if (errno != EINTR) + { + status = 1; + break; + } + + cupsdFinishProcess(pid, command, sizeof(command), NULL); + + if (status) + { + if (WIFEXITED(status)) + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to create SSL server key and certificate - " + "the certtool command stopped with status %d!", + WEXITSTATUS(status)); + else + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to create SSL server key and certificate - " + "the certtool command crashed on signal %d!", + WTERMSIG(status)); + } + else + { + cupsdLogMessage(CUPSD_LOG_INFO, + "Created SSL server certificate file \"%s\"...", + ServerCertificate); + } + + return (!status); +} + + +/* + * End of "$Id: tls-darwin.c 11173 2013-07-23 12:31:34Z msweet $". + */ diff --git a/scheduler/tls-gnutls.c b/scheduler/tls-gnutls.c new file mode 100644 index 0000000..c2d7032 --- /dev/null +++ b/scheduler/tls-gnutls.c @@ -0,0 +1,292 @@ +/* + * "$Id: tls-gnutls.c 11173 2013-07-23 12:31:34Z msweet $" + * + * TLS support code for the CUPS scheduler using GNU TLS. + * + * Copyright 2007-2012 by Apple Inc. + * Copyright 1997-2007 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Apple Inc. and are protected by Federal copyright + * law. Distribution and use rights are outlined in the file "LICENSE.txt" + * which should have been included with this file. If this file is + * file is missing or damaged, see the license at "http://www.cups.org/". + * + * Contents: + * + * cupsdEndTLS() - Shutdown a secure session with the client. + * cupsdStartTLS() - Start a secure session with the client. + * make_certificate() - Make a self-signed SSL/TLS certificate. + */ + + +/* + * Local functions... + */ + +static int make_certificate(cupsd_client_t *con); + + +/* + * 'cupsdEndTLS()' - Shutdown a secure session with the client. + */ + +int /* O - 1 on success, 0 on error */ +cupsdEndTLS(cupsd_client_t *con) /* I - Client connection */ +{ + int error; /* Error code */ + gnutls_certificate_server_credentials *credentials; + /* TLS credentials */ + + + credentials = (gnutls_certificate_server_credentials *) + (con->http.tls_credentials); + + error = gnutls_bye(con->http.tls, GNUTLS_SHUT_WR); + switch (error) + { + case GNUTLS_E_SUCCESS: + cupsdLogMessage(CUPSD_LOG_DEBUG, + "SSL shutdown successful!"); + break; + default: + cupsdLogMessage(CUPSD_LOG_ERROR, + "SSL shutdown failed: %s", gnutls_strerror(error)); + break; + } + + gnutls_deinit(con->http.tls); + con->http.tls = NULL; + + gnutls_certificate_free_credentials(*credentials); + free(credentials); + + return (1); +} + + +/* + * 'cupsdStartTLS()' - Start a secure session with the client. + */ + +int /* O - 1 on success, 0 on error */ +cupsdStartTLS(cupsd_client_t *con) /* I - Client connection */ +{ + int status; /* Error code */ + gnutls_certificate_server_credentials *credentials; + /* TLS credentials */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG, "[Client %d] Encrypting connection.", + con->http.fd); + + /* + * Verify that we have a certificate... + */ + + if (access(ServerKey, 0) || access(ServerCertificate, 0)) + { + /* + * Nope, make a self-signed certificate... + */ + + if (!make_certificate(con)) + return (0); + } + + /* + * Create the SSL object and perform the SSL handshake... + */ + + credentials = (gnutls_certificate_server_credentials *) + malloc(sizeof(gnutls_certificate_server_credentials)); + if (credentials == NULL) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to encrypt connection from %s - %s", + con->http.hostname, strerror(errno)); + + return (0); + } + + gnutls_certificate_allocate_credentials(credentials); + gnutls_certificate_set_x509_key_file(*credentials, ServerCertificate, + ServerKey, GNUTLS_X509_FMT_PEM); + + gnutls_init(&con->http.tls, GNUTLS_SERVER); + gnutls_set_default_priority(con->http.tls); + + gnutls_credentials_set(con->http.tls, GNUTLS_CRD_CERTIFICATE, *credentials); + gnutls_transport_set_ptr(con->http.tls, (gnutls_transport_ptr)HTTP(con)); + gnutls_transport_set_pull_function(con->http.tls, _httpReadGNUTLS); + gnutls_transport_set_push_function(con->http.tls, _httpWriteGNUTLS); + + while ((status = gnutls_handshake(con->http.tls)) != GNUTLS_E_SUCCESS) + { + if (gnutls_error_is_fatal(status)) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to encrypt connection from %s - %s", + con->http.hostname, gnutls_strerror(status)); + + gnutls_deinit(con->http.tls); + gnutls_certificate_free_credentials(*credentials); + con->http.tls = NULL; + free(credentials); + return (0); + } + } + + cupsdLogMessage(CUPSD_LOG_DEBUG, "Connection from %s now encrypted.", + con->http.hostname); + + con->http.tls_credentials = credentials; + return (1); +} + + +/* + * 'make_certificate()' - Make a self-signed SSL/TLS certificate. + */ + +static int /* O - 1 on success, 0 on failure */ +make_certificate(cupsd_client_t *con) /* I - Client connection */ +{ + gnutls_x509_crt crt; /* Self-signed certificate */ + gnutls_x509_privkey key; /* Encryption key */ + cups_lang_t *language; /* Default language info */ + cups_file_t *fp; /* Key/cert file */ + unsigned char buffer[8192]; /* Buffer for x509 data */ + size_t bytes; /* Number of bytes of data */ + unsigned char serial[4]; /* Serial number buffer */ + time_t curtime; /* Current time */ + int result; /* Result of GNU TLS calls */ + + + /* + * Create the encryption key... + */ + + cupsdLogMessage(CUPSD_LOG_INFO, "Generating SSL server key..."); + + gnutls_x509_privkey_init(&key); + gnutls_x509_privkey_generate(key, GNUTLS_PK_RSA, 2048, 0); + + /* + * Save it... + */ + + bytes = sizeof(buffer); + + if ((result = gnutls_x509_privkey_export(key, GNUTLS_X509_FMT_PEM, + buffer, &bytes)) < 0) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to export SSL server key - %s", + gnutls_strerror(result)); + gnutls_x509_privkey_deinit(key); + return (0); + } + else if ((fp = cupsFileOpen(ServerKey, "w")) != NULL) + { + cupsFileWrite(fp, (char *)buffer, bytes); + cupsFileClose(fp); + + cupsdLogMessage(CUPSD_LOG_INFO, "Created SSL server key file \"%s\"...", + ServerKey); + } + else + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to create SSL server key file \"%s\" - %s", + ServerKey, strerror(errno)); + gnutls_x509_privkey_deinit(key); + return (0); + } + + /* + * Create the self-signed certificate... + */ + + cupsdLogMessage(CUPSD_LOG_INFO, "Generating self-signed SSL certificate..."); + + language = cupsLangDefault(); + curtime = time(NULL); + serial[0] = curtime >> 24; + serial[1] = curtime >> 16; + serial[2] = curtime >> 8; + serial[3] = curtime; + + gnutls_x509_crt_init(&crt); + if (strlen(language->language) == 5) + gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_COUNTRY_NAME, 0, + language->language + 3, 2); + else + gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_COUNTRY_NAME, 0, + "US", 2); + gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_COMMON_NAME, 0, + ServerName, strlen(ServerName)); + gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_ORGANIZATION_NAME, 0, + ServerName, strlen(ServerName)); + gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_ORGANIZATIONAL_UNIT_NAME, + 0, "Unknown", 7); + gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_STATE_OR_PROVINCE_NAME, 0, + "Unknown", 7); + gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_LOCALITY_NAME, 0, + "Unknown", 7); + gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_PKCS9_EMAIL, 0, + ServerAdmin, strlen(ServerAdmin)); + gnutls_x509_crt_set_key(crt, key); + gnutls_x509_crt_set_serial(crt, serial, sizeof(serial)); + gnutls_x509_crt_set_activation_time(crt, curtime); + gnutls_x509_crt_set_expiration_time(crt, curtime + 10 * 365 * 86400); + gnutls_x509_crt_set_ca_status(crt, 0); + gnutls_x509_crt_set_subject_alternative_name(crt, GNUTLS_SAN_DNSNAME, + ServerName); + gnutls_x509_crt_set_key_purpose_oid(crt, GNUTLS_KP_TLS_WWW_SERVER, 0); + gnutls_x509_crt_set_key_usage(crt, GNUTLS_KEY_KEY_ENCIPHERMENT); + gnutls_x509_crt_set_version(crt, 3); + + bytes = sizeof(buffer); + if (gnutls_x509_crt_get_key_id(crt, 0, buffer, &bytes) >= 0) + gnutls_x509_crt_set_subject_key_id(crt, buffer, bytes); + + gnutls_x509_crt_sign(crt, crt, key); + + /* + * Save it... + */ + + bytes = sizeof(buffer); + if ((result = gnutls_x509_crt_export(crt, GNUTLS_X509_FMT_PEM, + buffer, &bytes)) < 0) + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to export SSL server certificate - %s", + gnutls_strerror(result)); + else if ((fp = cupsFileOpen(ServerCertificate, "w")) != NULL) + { + cupsFileWrite(fp, (char *)buffer, bytes); + cupsFileClose(fp); + + cupsdLogMessage(CUPSD_LOG_INFO, + "Created SSL server certificate file \"%s\"...", + ServerCertificate); + } + else + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to create SSL server certificate file \"%s\" - %s", + ServerCertificate, strerror(errno)); + + /* + * Cleanup... + */ + + gnutls_x509_crt_deinit(crt); + gnutls_x509_privkey_deinit(key); + + return (1); +} + + +/* + * End of "$Id: tls-gnutls.c 11173 2013-07-23 12:31:34Z msweet $". + */ diff --git a/scheduler/tls-openssl.c b/scheduler/tls-openssl.c new file mode 100644 index 0000000..f123d28 --- /dev/null +++ b/scheduler/tls-openssl.c @@ -0,0 +1,353 @@ +/* + * "$Id: tls-openssl.c 11173 2013-07-23 12:31:34Z msweet $" + * + * TLS support code for the CUPS scheduler using OpenSSL. + * + * Copyright 2007-2012 by Apple Inc. + * Copyright 1997-2007 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Apple Inc. and are protected by Federal copyright + * law. Distribution and use rights are outlined in the file "LICENSE.txt" + * which should have been included with this file. If this file is + * file is missing or damaged, see the license at "http://www.cups.org/". + * + * Contents: + * + * cupsdEndTLS() - Shutdown a secure session with the client. + * cupsdStartTLS() - Start a secure session with the client. + * make_certificate() - Make a self-signed SSL/TLS certificate. + */ + + +/* + * Local functions... + */ + +static int make_certificate(cupsd_client_t *con); + + +/* + * 'cupsdEndTLS()' - Shutdown a secure session with the client. + */ + +int /* O - 1 on success, 0 on error */ +cupsdEndTLS(cupsd_client_t *con) /* I - Client connection */ +{ + SSL_CTX *context; /* Context for encryption */ + unsigned long error; /* Error code */ + int status; /* Return status */ + + + context = SSL_get_SSL_CTX(con->http.tls); + + switch (SSL_shutdown(con->http.tls)) + { + case 1 : + cupsdLogMessage(CUPSD_LOG_DEBUG, + "SSL shutdown successful!"); + status = 1; + break; + + case -1 : + cupsdLogMessage(CUPSD_LOG_ERROR, + "Fatal error during SSL shutdown!"); + + default : + while ((error = ERR_get_error()) != 0) + cupsdLogMessage(CUPSD_LOG_ERROR, "SSL shutdown failed: %s", + ERR_error_string(error, NULL)); + status = 0; + break; + } + + SSL_CTX_free(context); + SSL_free(con->http.tls); + con->http.tls = NULL; + + return (status); +} + + +/* + * 'cupsdStartTLS()' - Start a secure session with the client. + */ + +int /* O - 1 on success, 0 on error */ +cupsdStartTLS(cupsd_client_t *con) /* I - Client connection */ +{ + SSL_CTX *context; /* Context for encryption */ + BIO *bio; /* BIO data */ + unsigned long error; /* Error code */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG, "[Client %d] Encrypting connection.", + con->http.fd); + + /* + * Verify that we have a certificate... + */ + + if (access(ServerKey, 0) || access(ServerCertificate, 0)) + { + /* + * Nope, make a self-signed certificate... + */ + + if (!make_certificate(con)) + return (0); + } + + /* + * Create the SSL context and accept the connection... + */ + + context = SSL_CTX_new(SSLv23_server_method()); + + SSL_CTX_set_options(context, SSL_OP_NO_SSLv2); /* Only use SSLv3 or TLS */ + if (SSLOptions & CUPSD_SSL_NOEMPTY) + SSL_CTX_set_options(context, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS); + SSL_CTX_use_PrivateKey_file(context, ServerKey, SSL_FILETYPE_PEM); + SSL_CTX_use_certificate_chain_file(context, ServerCertificate); + + bio = BIO_new(_httpBIOMethods()); + BIO_ctrl(bio, BIO_C_SET_FILE_PTR, 0, (char *)HTTP(con)); + + con->http.tls = SSL_new(context); + SSL_set_bio(con->http.tls, bio, bio); + + if (SSL_accept(con->http.tls) != 1) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to encrypt connection from %s.", + con->http.hostname); + + while ((error = ERR_get_error()) != 0) + cupsdLogMessage(CUPSD_LOG_ERROR, "%s", ERR_error_string(error, NULL)); + + SSL_CTX_free(context); + SSL_free(con->http.tls); + con->http.tls = NULL; + return (0); + } + + cupsdLogMessage(CUPSD_LOG_DEBUG, "Connection from %s now encrypted.", + con->http.hostname); + + return (1); +} + + +/* + * 'make_certificate()' - Make a self-signed SSL/TLS certificate. + */ + +static int /* O - 1 on success, 0 on failure */ +make_certificate(cupsd_client_t *con) /* I - Client connection */ +{ +#ifdef HAVE_WAITPID + int pid, /* Process ID of command */ + status; /* Status of command */ + char command[1024], /* Command */ + *argv[12], /* Command-line arguments */ + *envp[MAX_ENV + 1], /* Environment variables */ + infofile[1024], /* Type-in information for cert */ + seedfile[1024]; /* Random number seed file */ + int envc, /* Number of environment variables */ + bytes; /* Bytes written */ + cups_file_t *fp; /* Seed/info file */ + int infofd; /* Info file descriptor */ + + + /* + * Run the "openssl" command to seed the random number generator and + * generate a self-signed certificate that is good for 10 years: + * + * openssl rand -rand seedfile 1 + * + * openssl req -new -x509 -keyout ServerKey \ + * -out ServerCertificate -days 3650 -nodes + * + * The seeding step is crucial in ensuring that the openssl command + * does not block on systems without sufficient entropy... + */ + + if (!cupsFileFind("openssl", getenv("PATH"), 1, command, sizeof(command))) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "No SSL certificate and openssl command not found!"); + return (0); + } + + if (access("/dev/urandom", 0)) + { + /* + * If the system doesn't provide /dev/urandom, then any random source + * will probably be blocking-style, so generate some random data to + * use as a seed for the certificate. Note that we have already + * seeded the random number generator in cupsdInitCerts()... + */ + + cupsdLogMessage(CUPSD_LOG_INFO, + "Seeding the random number generator..."); + + /* + * Write the seed file... + */ + + if ((fp = cupsTempFile2(seedfile, sizeof(seedfile))) == NULL) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create seed file %s - %s", + seedfile, strerror(errno)); + return (0); + } + + for (bytes = 0; bytes < 262144; bytes ++) + cupsFilePutChar(fp, CUPS_RAND()); + + cupsFileClose(fp); + + /* + * Run the openssl command to seed its random number generator... + */ + + argv[0] = "openssl"; + argv[1] = "rand"; + argv[2] = "-rand"; + argv[3] = seedfile; + argv[4] = "1"; + argv[5] = NULL; + + envc = cupsdLoadEnv(envp, MAX_ENV); + envp[envc] = NULL; + + if (!cupsdStartProcess(command, argv, envp, -1, -1, -1, -1, -1, 1, NULL, + NULL, &pid)) + { + unlink(seedfile); + return (0); + } + + while (waitpid(pid, &status, 0) < 0) + if (errno != EINTR) + { + status = 1; + break; + } + + cupsdFinishProcess(pid, command, sizeof(command), NULL); + + /* + * Remove the seed file, as it is no longer needed... + */ + + unlink(seedfile); + + if (status) + { + if (WIFEXITED(status)) + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to seed random number generator - " + "the openssl command stopped with status %d!", + WEXITSTATUS(status)); + else + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to seed random number generator - " + "the openssl command crashed on signal %d!", + WTERMSIG(status)); + + return (0); + } + } + + /* + * Create a file with the certificate information fields... + * + * Note: This assumes that the default questions are asked by the openssl + * command... + */ + + if ((fp = cupsTempFile2(infofile, sizeof(infofile))) == NULL) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to create certificate information file %s - %s", + infofile, strerror(errno)); + return (0); + } + + cupsFilePrintf(fp, ".\n.\n.\n%s\n.\n%s\n%s\n", + ServerName, ServerName, ServerAdmin); + cupsFileClose(fp); + + cupsdLogMessage(CUPSD_LOG_INFO, + "Generating SSL server key and certificate..."); + + argv[0] = "openssl"; + argv[1] = "req"; + argv[2] = "-new"; + argv[3] = "-x509"; + argv[4] = "-keyout"; + argv[5] = ServerKey; + argv[6] = "-out"; + argv[7] = ServerCertificate; + argv[8] = "-days"; + argv[9] = "3650"; + argv[10] = "-nodes"; + argv[11] = NULL; + + cupsdLoadEnv(envp, MAX_ENV); + + infofd = open(infofile, O_RDONLY); + + if (!cupsdStartProcess(command, argv, envp, infofd, -1, -1, -1, -1, 1, NULL, + NULL, &pid)) + { + close(infofd); + unlink(infofile); + return (0); + } + + close(infofd); + unlink(infofile); + + while (waitpid(pid, &status, 0) < 0) + if (errno != EINTR) + { + status = 1; + break; + } + + cupsdFinishProcess(pid, command, sizeof(command), NULL); + + if (status) + { + if (WIFEXITED(status)) + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to create SSL server key and certificate - " + "the openssl command stopped with status %d!", + WEXITSTATUS(status)); + else + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to create SSL server key and certificate - " + "the openssl command crashed on signal %d!", + WTERMSIG(status)); + } + else + { + cupsdLogMessage(CUPSD_LOG_INFO, "Created SSL server key file \"%s\"...", + ServerKey); + cupsdLogMessage(CUPSD_LOG_INFO, + "Created SSL server certificate file \"%s\"...", + ServerCertificate); + } + + return (!status); + +#else + return (0); +#endif /* HAVE_WAITPID */ +} + + +/* + * End of "$Id: tls-openssl.c 11173 2013-07-23 12:31:34Z msweet $". + */ diff --git a/scheduler/tls.c b/scheduler/tls.c new file mode 100644 index 0000000..bd18263 --- /dev/null +++ b/scheduler/tls.c @@ -0,0 +1,30 @@ +/* + * "$Id: tls.c 11173 2013-07-23 12:31:34Z msweet $" + * + * TLS support code for the CUPS scheduler. + * + * Copyright 2012 by Apple Inc. + * + * These coded instructions, statements, and computer programs are the + * property of Apple Inc. and are protected by Federal copyright + * law. Distribution and use rights are outlined in the file "LICENSE.txt" + * which should have been included with this file. If this file is + * file is missing or damaged, see the license at "http://www.cups.org/". + */ + +#include "cupsd.h" + +#ifdef HAVE_SSL +# ifdef HAVE_CDSASSL +# include "tls-darwin.c" +# elif defined(HAVE_GNUTLS) +# include "tls-gnutls.c" +# elif defined(HAVE_LIBSSL) +# include "tls-openssl.c" +# endif /* HAVE_CDSASSL */ +#endif /* HAVE_SSL */ + + +/* + * End of "$Id: tls.c 11173 2013-07-23 12:31:34Z msweet $". + */ diff --git a/scheduler/type.c b/scheduler/type.c index d2e32b2..bf014be 100644 --- a/scheduler/type.c +++ b/scheduler/type.c @@ -1,5 +1,5 @@ /* - * "$Id: type.c 9793 2011-05-20 03:49:49Z mike $" + * "$Id: type.c 11173 2013-07-23 12:31:34Z msweet $" * * MIME typing routines for CUPS. * @@ -1212,5 +1212,5 @@ mime_patmatch(const char *s, /* I - String to match against */ /* - * End of "$Id: type.c 9793 2011-05-20 03:49:49Z mike $". + * End of "$Id: type.c 11173 2013-07-23 12:31:34Z msweet $". */ diff --git a/scheduler/util.c b/scheduler/util.c index 9bc8077..74dd9ff 100644 --- a/scheduler/util.c +++ b/scheduler/util.c @@ -1,5 +1,5 @@ /* - * "$Id: util.c 9793 2011-05-20 03:49:49Z mike $" + * "$Id: util.c 11173 2013-07-23 12:31:34Z msweet $" * * Mini-daemon utility functions for CUPS. * @@ -170,7 +170,7 @@ cupsdCreateStringsArray(const char *s) /* I - Comma-delimited strings */ /* * 'cupsdExec()' - Run a program with the correct environment. * - * On Mac OS X, we need to update the CFProcessPath environment variable that + * On OS X, we need to update the CFProcessPath environment variable that * is passed in the environment so the child can access its bundled resources. */ @@ -187,7 +187,7 @@ cupsdExec(const char *command, /* I - Full path to program */ /* - * Some Mac OS X programs are bundled and need the CFProcessPath environment + * Some OS X programs are bundled and need the CFProcessPath environment * variable defined. If the command is a symlink, resolve the link and point * to the resolved location, otherwise, use the command path itself. */ @@ -467,5 +467,5 @@ cupsdSendIPPTrailer(void) /* - * End of "$Id: util.c 9793 2011-05-20 03:49:49Z mike $". + * End of "$Id: util.c 11173 2013-07-23 12:31:34Z msweet $". */ diff --git a/scheduler/util.h b/scheduler/util.h index 0080914..cf5ae0d 100644 --- a/scheduler/util.h +++ b/scheduler/util.h @@ -1,5 +1,5 @@ /* - * "$Id: util.h 9755 2011-05-09 22:53:31Z mike $" + * "$Id: util.h 11173 2013-07-23 12:31:34Z msweet $" * * Mini-daemon utility definitions for CUPS. * @@ -67,5 +67,5 @@ extern void cupsdSendIPPTrailer(void); #endif /* !_CUPSD_UTIL_H_ */ /* - * End of "$Id: util.h 9755 2011-05-09 22:53:31Z mike $". + * End of "$Id: util.h 11173 2013-07-23 12:31:34Z msweet $". */ |