From: zacheiss Date: Fri, 31 Oct 2008 19:32:59 +0000 (+0000) Subject: First stab at DCM for cups printing backend. X-Git-Url: http://andersk.mit.edu/gitweb/moira.git/commitdiff_plain/f50216d7fe87fc42b551517b7fae38e013f6c6af First stab at DCM for cups printing backend. --- diff --git a/gen/Makefile.in b/gen/Makefile.in index 8b399e57..8e3acb84 100644 --- a/gen/Makefile.in +++ b/gen/Makefile.in @@ -30,20 +30,21 @@ LIB_OBJS=util.o tar.o genacl.o LIB_CFILES=genacl.c LIB_TARGET=libdcm.a -OBJS= acl.o boot.o confluence.o dhcp.o directory.o events.o hesiod.o \ - hosts.o lpcaccess.o mailhub.o ndb.o network.o nfs.o pobox.o \ - postoffice.o print.o winad.o www.o zephyr.o +OBJS= acl.o boot.o confluence.o cups-print.o dhcp.o directory.o events.o \ + hesiod.o hosts.o lpcaccess.o mailhub.o ndb.o network.o nfs.o pobox.o \ + postoffice.o print.o warehouse-lists.o winad.o www.o zephyr.o -CFILES= acl.c boot.c confluence.c dhcp.c directory.c events.c hesiod.c \ - hosts.c lpcaccess.c mailhub.c ndb.c network.c nfs.c pobox.c \ - postoffice.c print.c winad.c www.c zephyr.c +CFILES= acl.c boot.c confluence.c cups-print.c dhcp.c directory.c events.c \ + hesiod.c hosts.c lpcaccess.c mailhub.c ndb.c network.c nfs.c pobox.c \ + postoffice.c print.c warehouse-lists.c winad.c www.c zephyr.c -TARGET= acl.gen boot.gen confluence.gen dhcp.gen directory.gen events.gen \ - hesiod.gen hosts.gen lpcaccess.gen mailhub.gen ndb.gen network.gen \ - nfs.gen pobox.gen postoffice.gen print.gen winad.gen www.gen zephyr.gen +TARGET= acl.gen boot.gen confluence.gen cups-print.gen dhcp.gen directory.gen \ + events.gen hesiod.gen hosts.gen lpcaccess.gen mailhub.gen ndb.gen \ + network.gen nfs.gen pobox.gen postoffice.gen print.gen \ + warehouse-lists.gen winad.gen www.gen zephyr.gen SCRIPTS=access.gen access.sh acl.sh aliases.sh boot.sh ca.gen calendar.gen \ - dhcp.sh events.sh hesiod.sh ip-billing.gen \ + cups-print.sh dhcp.sh events.sh hesiod.sh ip-billing.gen \ ip-billing.sh ldap.gen longjobs.gen longjobs.sh mailhosts.gen \ mailhub.sh mailman.gen mailman.sh nagios-colo.gen nagios-colo.sh \ nagios-printers.gen nagios-printers.sh nagios-wsh.gen nagios-wsh.sh \ @@ -140,3 +141,9 @@ winad.gen: winad.o libdcm.a $(MR_LIBDEP) lpcaccess.gen: lpcaccess.o libdcm.a $(MR_LIBDEP) $(CC) -o $@ $(LDFLAGS) lpcaccess.o libdcm.a $(SQL_LIBS) $(LIBS) + +warehouse-lists.gen: warehouse-lists.o libdcm.a $(MR_LIBDEP) + $(CC) -o $@ $(LDFLAGS) warehouse-lists.o libdcm.a $(SQL_LIBS) $(LIBS) + +cups-print.gen: cups-print.o libdcm.a $(MR_LIBDEP) + $(CC) -o $@ $(LDFLAGS) cups-print.o libdcm.a $(SQL_LIBS) $(LIBS) diff --git a/gen/cups-print.pc b/gen/cups-print.pc new file mode 100644 index 00000000..633c623c --- /dev/null +++ b/gen/cups-print.pc @@ -0,0 +1,484 @@ +/* $Id$ + * + * This generates printcaps and other files for Athena print servers + * + * Copyright (C) 1992-1998 by the Massachusetts Institute of Technology. + * For copying and distribution information, please see the file + * . + */ + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include "util.h" + + + +EXEC SQL INCLUDE sqlca; + +RCSID("$Header$"); + +char *whoami = "cups-print.gen"; +char *db = "moira/moira"; + +/* OMG, I hate this, but it's cleaner, I guess? */ + +const char *alterjob = ""; +const char *submitjob = ""; +const char *alterpntr = ""; +const char *lpcpntr = ""; +const char *canceljob = ""; +const char *catchall = ""; + +void do_host(char *host); +void sqlerr(void); +#ifndef MAX +#define MAX(a, b) ( (a) > (b) ? (a) : (b) ) +#endif + +int main(int argc, char **argv) +{ + EXEC SQL BEGIN DECLARE SECTION; + char name[MACHINE_NAME_SIZE]; + EXEC SQL END DECLARE SECTION; + + init_acls(); + + EXEC SQL CONNECT :db; + + EXEC SQL WHENEVER SQLERROR DO sqlerr(); + + EXEC SQL DECLARE csr_hosts CURSOR FOR + SELECT m.name FROM machine m, serverhosts sh + WHERE m.mach_id = sh.mach_id AND sh.service = 'CUPS' AND sh.enable = 1; + EXEC SQL OPEN csr_hosts; + while (1) + { + EXEC SQL FETCH csr_hosts INTO :name; + if (sqlca.sqlcode) + break; + + strtrim(name); + do_host(name); + } + EXEC SQL CLOSE csr_hosts; + + exit(MR_SUCCESS); +} + +void printer_user_list(FILE *out, char *type, int id, char *str) +{ + struct save_queue *sq; + struct imember *m; + + sq = get_acl(type, id, NULL); + while (sq_remove_data(sq, &m)) + { + if (m->type == 'U') + fprintf(out, "%s %s\n", str, m->name); + freeimember(m); + } + sq_destroy(sq); +} + + + +void do_host(char *host) +{ + EXEC SQL BEGIN DECLARE SECTION; + char rp[PRINTERS_RP_SIZE], name[PRINTERS_NAME_SIZE]; + char duplexname[PRINTERS_DUPLEXNAME_SIZE], location[PRINTERS_LOCATION_SIZE]; + char hwtype[PRINTERS_HWTYPE_SIZE], lowerhwtype[PRINTERS_HWTYPE_SIZE]; + char modtime[PRINTERS_MODTIME_SIZE], lmodtime[LIST_MODTIME_SIZE]; + char contact[PRINTERS_CONTACT_SIZE], hostname[MACHINE_NAME_SIZE]; + char cupshosts[MACHINE_NAME_SIZE], prtype [PRINTERS_TYPE_SIZE]; + char *spoolhost = host, *unixtime_fmt = UNIXTIME_FMT, *p; + char *lhost; + int ka, pc, ac, lpc_acl, top_lpc_acl, banner, rm; + EXEC SQL END DECLARE SECTION; + TARFILE *tf; + FILE *out; + char filename[MAXPATHLEN], *duptc; + time_t mtime, now = time(NULL); + + lhost = (char *) strdup (host); + for (p = lhost; *p; p++) + *p = tolower(*p); + + EXEC SQL SELECT mach_id INTO :rm FROM machine + WHERE name = :spoolhost; + + sprintf(filename, "%s/print/%s", DCM_DIR, host); + tf = tarfile_open(filename); + + /* printers.conf */ + out = tarfile_start(tf, "/etc/cups/printers.conf", 0644, 0, 0, + "root", "lp", now); + + EXEC SQL DECLARE csr_printers CURSOR FOR + SELECT pr.rp, pr.name, pr.duplexname, pr.hwtype, + m.name, pr.banner, pr.location, pr.contact, pr.ka, + pr.ac + FROM printers pr, machine m + WHERE pr.rm = :rm AND m.mach_id = pr.mach_id + AND pr.type != 'ALIAS'; + EXEC SQL OPEN csr_printers; + while (1) + { + EXEC SQL FETCH csr_printers INTO :rp, :name, :duplexname, + :hwtype, :hostname, :banner, :location, :contact, :ka, :ac; + if (sqlca.sqlcode) + break; + + strtrim(rp); + strtrim(name); + strtrim(duplexname); + strtrim(hwtype); + strtrim(hostname); + strtrim(location); + strtrim(contact); + strcpy(lowerhwtype, hwtype); + for (p = lowerhwtype; *p; p++) + *p = tolower(*p); + + fprintf(out, "\n",rp); + fprintf(out, "Info %s:%s\n", rp, hwtype); + /* Note the use of "beh" to keep the CUPS from disabling print queues + * should they not respond versus discarding the job. + * See the "beh" page for details. + * The 1/0/60 says "don't disable/try 20 times/try every 60s */ + if (!strncmp(hwtype, "HP", 2)) + fprintf(out, "DeviceURI beh:/1/20/60/socket://%s:9100\n", hostname); + else + fprintf(out, "DeviceURI beh:/1/20/60/socket://%s\n", hostname); + fprintf(out, "State Idle\n"); // Always with the Idle + fprintf(out, "StateTime %ld\n", (long)time(NULL)); + fprintf(out, "Accepting Yes\n"); + fprintf(out, "Shared Yes\n"); + fprintf(out, "QuotaPeriod 0\n"); + fprintf(out, "PageLimit 0\n"); + fprintf(out, "Klimit 0\n"); + fprintf(out, "Option sides one-sided\n"); + if (location[0]) + fprintf(out, "Location %s\n", location); + fprintf(out, "ErrorPolicy abort-job\n"); + if (! ka || ! lpc_acl) + fprintf(out, "OpPolicy default\n"); + else + fprintf(out, "OpPolicy %s-policy\n", rp); + + /* Access-control list. */ + if (ac) + { + if (ka) + fprintf(out, "AuthType Negotiate\n"); + else + fprintf(out, "AuthType Negotiate\n"); + printer_user_list(out, "LIST", ac, "AllowUser"); + } + + if (banner == PRN_BANNER_NONE) + fprintf(out, "JobSheets none none\n"); + else + fprintf(out, "JobSheets athena none\n"); + fprintf(out, "\n"); + + } + EXEC SQL CLOSE csr_printers; + tarfile_end(tf); + + + /* aliases are in classes.conf */ + out = tarfile_start(tf, "/etc/cups/classes.conf", 0644, 0, 0, + "root", "root", now); + EXEC SQL DECLARE csr_duplexqs CURSOR FOR + SELECT pr.rp, pr.name, pr.duplexname, pr.hwtype, + m.name, pr.banner, pr.location, pr.contact, pr.ka, + pr.type as prtype, pr.ac + FROM printers pr, machine m + WHERE pr.rm = :rm AND m.mach_id = pr.mach_id; + EXEC SQL OPEN csr_duplexqs; + while (1) + { + EXEC SQL FETCH csr_duplexqs INTO :rp, :name, :duplexname, + :hwtype, :hostname, :banner, :location, :contact, :ka, :prtype, :ac; + if (sqlca.sqlcode) + break; + + strtrim(hwtype); + strtrim(rp); + strtrim(location); + strtrim(contact); + strtrim(prtype); + + /* Define alias queues as classes to the regular queues for + * accounting reasons. Annoyingly, classes don't always inherit + * their printer definitions. + */ + if (!strcmp(prtype,"ALIAS")) + { + strtrim(name); + fprintf(out, "\n",name); + fprintf(out, "Info Alias Queue to %s:%s\n", rp, hwtype); + fprintf(out, "Printer %s\n", rp); + fprintf(out, "Option sides one-sided\n"); + fprintf(out, "State Idle\n"); // Always with the Idle + fprintf(out, "StateTime %ld\n", (long)time(NULL)); + fprintf(out, "Accepting Yes\n"); + fprintf(out, "Shared Yes\n"); + fprintf(out, "QuotaPeriod 0\n"); + fprintf(out, "PageLimit 0\n"); + if (location[0]) + fprintf(out, "Location %s\n", location); + fprintf(out, "ErrorPolicy abort-job\n"); + if (! ka || ! lpc_acl) + fprintf(out, "OpPolicy default\n"); + else + fprintf(out, "OpPolicy %s-policy\n", rp); + + /* Access-control list. */ + if (ac) + { + if (ka) + fprintf(out, "AuthType Negotiate\n"); + else + fprintf(out, "AuthType Negotiate\n"); + printer_user_list(out, "LIST", ac, "AllowUser"); + } + + if (banner == PRN_BANNER_NONE) + fprintf(out, "JobSheets none none\n"); + else + fprintf(out, "JobSheets athena none\n"); + fprintf(out, "\n"); + } + + /* Define duplex queues as aliases to the regular queues for + * accounting reasons. Annoyingly, classes don't always inherit + * their printer definitions. + */ + if (*duplexname) + { + strtrim(duplexname); + fprintf(out, "\n",duplexname); + if (!strcmp(prtype,"ALIAS")) + fprintf(out, "Info Duplex Alias Queue to %s:%s\n", rp, hwtype); + else + fprintf(out, "Info Duplex Queue for %s:%s\n", rp, hwtype); + fprintf(out, "Option sides two-sided-long-edge\n"); // duplex + fprintf(out, "Printer %s\n", rp); + fprintf(out, "State Idle\n"); // Always with the Idle + fprintf(out, "StateTime %ld\n", (long)time(NULL)); + fprintf(out, "Accepting Yes\n"); + fprintf(out, "Shared Yes\n"); + fprintf(out, "QuotaPeriod 0\n"); + fprintf(out, "PageLimit 0\n"); + if (location[0]) + fprintf(out, "Location %s\n", location); + fprintf(out, "ErrorPolicy abort-job\n"); + if (! ka || ! lpc_acl) + fprintf(out, "OpPolicy default\n"); + else + fprintf(out, "OpPolicy %s-policy\n", rp); + + /* Access-control list. */ + if (ac) + { + if (ka) + fprintf(out, "AuthType Negotiate\n"); + else + fprintf(out, "AuthType Negotiate\n"); + printer_user_list(out, "LIST", ac, "AllowUser"); + } + + if (banner == PRN_BANNER_NONE) + fprintf(out, "JobSheets none none\n"); + else if (banner == PRN_BANNER_LAST) + fprintf(out, "JobSheets athena none\n"); + fprintf(out, "\n"); + } + } + EXEC SQL CLOSE csr_duplexqs; + tarfile_end(tf); + + /* cups.conf */ + out = tarfile_start(tf, "/etc/cups/cupsd.conf", 0755, 1, 1, + "root", "lp", now); + + fprintf(out, "LogLevel info\n"); + fprintf(out, "SystemGroup sys root ops-group\n"); + fprintf(out, "Port 631\n"); + fprintf(out, "Listen /var/run/cups/cups.sock\n"); + fprintf(out, "Browsing On\n"); + fprintf(out, "BrowseOrder allow,deny\n"); + fprintf(out, "BrowseAllow all\n"); + fprintf(out, "BrowseAddress @LOCAL\n"); + fprintf(out, "DefaultAuthType Negotiate\n"); + fprintf(out, "ServerCertificate /etc/cups/ssl/%s-ipp-crt.pem\n", lhost); + fprintf(out, "ServerKey /etc/cups/ssl/%s-ipp-key.pem\n", lhost); + fprintf(out, "ServerName %s\n", lhost); + fprintf(out, "Krb5Keytab /etc/krb5-ipp.keytab\n"); + fprintf(out, "Browsing On\n"); + fprintf(out, "BrowseProtocols cups\n"); + + /* The other CUPS servers should be aware of the other hosts' + queues, so we'll let them browse each other. */ + + EXEC SQL DECLARE csr_cupshosts CURSOR FOR + SELECT m.name AS cupshosts FROM machine m, printservers ps + WHERE m.mach_id = ps.mach_id AND ps.kind = 'CUPS'; + EXEC SQL OPEN csr_cupshosts; + while (1) + { + EXEC SQL FETCH csr_cupshosts INTO :cupshosts; + if (sqlca.sqlcode) + break; + + strtrim(cupshosts); + + /* Don't poll yourself looking for answers! */ + if (strcmp(cupshosts,host)) + fprintf(out, "BrowsePoll %s\n", cupshosts); + } + EXEC SQL CLOSE csr_cupshosts; + fprintf(out, "Include cups.locations.conf\n"); + fprintf(out, "Include cups.policies.conf\n"); + + tarfile_end(tf); + + /* cups.policies.conf */ + out = tarfile_start(tf, "/etc/cups/cups.policies.conf", 0755, 1, 1, + "root", "lp", now); + fprintf(out, "# Printer-specific LPC and LPR ACLs\n"); + /* lpcaccess.top */ + EXEC SQL SELECT ps.lpc_acl INTO :top_lpc_acl + FROM printservers ps, machine m + WHERE m.name = :spoolhost AND m.mach_id = ps.mach_id; + if (!sqlca.sqlcode && lpc_acl) + { + fprintf (out, "\n"); + fprintf (out, "%s\n", alterjob); + fprintf (out, "AuthType Default\n"); + fprintf (out, "Require user @OWNER @SYSTEM\n"); + printer_user_list(out, "LIST", top_lpc_acl, "Require user"); + fprintf (out, "Order deny,allow\n"); + fprintf (out, "\n"); + fprintf (out, "%s\n", submitjob); + fprintf (out, "AuthType Default\n"); + fprintf (out, "Order deny,allow\n"); + fprintf (out, "\n"); + fprintf (out, "%s\n", alterpntr); + fprintf (out, "AuthType Default\n"); + fprintf (out, "Require user @SYSTEM\n"); + fprintf (out, "Order deny,allow\n"); + fprintf (out, "\n"); + fprintf (out, "%s\n", lpcpntr); + fprintf (out, "AuthType Default\n"); + fprintf (out, "Require user @SYSTEM\n"); + printer_user_list(out, "LIST", top_lpc_acl, "Require user"); + fprintf (out, "Order deny,allow\n"); + fprintf (out, "\n"); + fprintf (out, "%s\n", canceljob); + fprintf (out, "AuthType Default\n"); + fprintf (out, "Require user @OWNER @SYSTEM\n"); + printer_user_list(out, "LIST", top_lpc_acl, "Require user"); + fprintf (out, "Order deny,allow\n"); + fprintf (out, "\n"); + fprintf (out, "%s\n", catchall); + fprintf (out, "Order deny,allow\n"); + fprintf (out, "\n"); + fprintf (out, "\n"); + } + + /* restrict lists and lpcaccess policies. Sadly, we have to put the + top level for each new policy since CUPS doesn't have a way of + doing it otherwise (well, Unix groups, but not moira) */ + EXEC SQL DECLARE csr_lpc CURSOR FOR + SELECT UNIQUE rp, ka, ac, lpc_acl + FROM printers + WHERE rm = :rm AND ( ac != 0 OR lpc_acl != 0); + EXEC SQL OPEN csr_lpc; + while (1) + { + EXEC SQL FETCH csr_lpc INTO :name, :ka, :ac, :lpc_acl; + if (sqlca.sqlcode) + break; + + strtrim(name); + + fprintf (out, "\n", name); + fprintf (out, "%s\n", alterjob); + fprintf (out, "AuthType Default\n"); + fprintf (out, "Require user @OWNER @SYSTEM\n"); + printer_user_list(out, "LIST", lpc_acl, "Require user"); + fprintf (out, "Order deny,allow\n"); + fprintf (out, "\n"); + fprintf (out, "%s\n", submitjob); + /* If the printer is Kerberized? */ + if (ka) + fprintf (out, "AuthType Negotiate\n"); + else + fprintf (out, "AuthType None\n"); + /* Access-control list. */ + if (ac) + printer_user_list(out, "LIST", ac, "Require user"); + else if (ka) + fprintf (out, "Require valid-user\n"); + fprintf (out, "Order deny,allow\n"); + fprintf (out, "\n"); + fprintf (out, "%s\n", alterpntr); + fprintf (out, "AuthType Default\n"); + fprintf (out, "Require user @SYSTEM\n"); + fprintf (out, "Order deny,allow\n"); + fprintf (out, "\n"); + fprintf (out, "%s\n", lpcpntr); + fprintf (out, "AuthType Default\n"); + fprintf (out, "Require user @SYSTEM\n"); + /* printer-specific lpc access. */ + if (lpc_acl) + printer_user_list(out, "LIST", lpc_acl, "Require user"); + printer_user_list(out, "LIST", top_lpc_acl, "Require user"); + fprintf (out, "Order deny,allow\n"); + fprintf (out, "\n"); + fprintf (out, "%s\n", canceljob); + fprintf (out, "AuthType Default\n"); + fprintf (out, "Require user @OWNER @SYSTEM\n"); + printer_user_list(out, "LIST", lpc_acl, "Require user"); + printer_user_list(out, "LIST", top_lpc_acl, "Require user"); + fprintf (out, "Order deny,allow\n"); + fprintf (out, "\n"); + fprintf (out, "%s\n", catchall); + fprintf (out, "Order deny,allow\n"); + fprintf (out, "\n"); + fprintf (out, "\n"); + } + EXEC SQL CLOSE csr_lpc; + fprintf(out, "\n"); + tarfile_end(tf); + tarfile_close(tf); +} + +void sqlerr(void) +{ + db_error(sqlca.sqlcode); +} diff --git a/gen/cups-print.sh b/gen/cups-print.sh new file mode 100755 index 00000000..c8d6f6bd --- /dev/null +++ b/gen/cups-print.sh @@ -0,0 +1,42 @@ +#! /bin/sh +# $Id$ + +if [ -d /var/athena ] && [ -w /var/athena ]; then + exec >/var/athena/moira_update.log 2>&1 +else + exec >/tmp/moira_update.log 2>&1 +fi + +# The following exit codes are defined and MUST BE CONSISTENT with the +# error codes the library uses: +MR_MISSINGFILE=47836473 +MR_MKCRED=47836474 +MR_TARERR=47836476 + +PATH=/bin +TARFILE=/var/tmp/cups-print.out +CUPSLOCAL=/etc/cups + +# Alert if the tar file or other needed files do not exist +test -r $TARFILE || exit $MR_MISSINGFILE +test -d $CUPSLOCAL || exit $MR_MISSINGFILE + +# Unpack the tar file, getting only files that are newer than the +# on-disk copies (-u). +cd / +tar xf $TARFILE || exit $MR_TARERR + +# Now, make a stab at the PPD file. +/etc/cups/bin/gen-ppd.pl + +/etc/init.d/cupsys restart +if [ $? != 0 ]; then + exit $MR_MKCRED +fi + +# cleanup +test -f $TARFILE && rm -f $TARFILE +test -f $0 && rm -f $0 + +exit 0 +