]> andersk Git - moira.git/blob - gen/cups-print.pc
First stab at DCM for cups printing backend.
[moira.git] / gen / cups-print.pc
1 /* $Id$
2  *
3  * This generates printcaps and other files for Athena print servers
4  *
5  * Copyright (C) 1992-1998 by the Massachusetts Institute of Technology.
6  * For copying and distribution information, please see the file
7  * <mit-copyright.h>.
8  */
9
10 #include <mit-copyright.h>
11 #include <moira.h>
12 #include <moira_site.h>
13
14 #include <sys/stat.h>
15 #include <sys/types.h>
16
17 #include <ctype.h>
18 #include <stdio.h>
19 #include <string.h>
20
21 #include <time.h>
22 #include <krb.h>
23 #include <krb5.h>
24
25 #include "util.h"
26
27
28
29 EXEC SQL INCLUDE sqlca;
30
31 RCSID("$Header$");
32
33 char *whoami = "cups-print.gen";
34 char *db = "moira/moira";
35
36 /* OMG, I hate this, but it's cleaner, I guess? */
37
38 const char *alterjob = "<Limit Send-Document Send-URI Hold-Job Release-Job\
39  Restart-Job Purge-Jobs Set-Job-Attributes Create-Job-Subscription\
40  Renew-Subscription Cancel-Subscription Get-Notifications Reprocess-Job\
41  Cancel-Current-Job Suspend-Current-Job Resume-Job CUPS-Move-Job>";
42 const char *submitjob = "<Limit Create-Job Print-Job Print-URI>";
43 const char *alterpntr = "<Limit CUPS-Add-Modify-Printer CUPS-Delete-Printer\
44  CUPS-Add-Modify-Class CUPS-Delete-Class CUPS-Set-Default>";
45 const char *lpcpntr = "<Limit Pause-Printer Resume-Printer Enable-Printer\
46  Disable-Printer Pause-Printer-After-Current-Job Hold-New-Jobs\
47  Release-Held-New-Jobs Deactivate-Printer Activate-Printer Restart-Printer\
48  Shutdown-Printer Startup-Printer Promote-Job Schedule-Job-After\
49  CUPS-Accept-Jobs CUPS-Reject-Jobs>";
50 const char *canceljob = "<Limit Cancel-Job CUPS-Authenticate-Job>";
51 const char *catchall = "<Limit All>";
52
53 void do_host(char *host);
54 void sqlerr(void);
55 #ifndef MAX
56 #define MAX(a, b) ( (a) > (b) ? (a) : (b) )
57 #endif
58
59 int main(int argc, char **argv)
60 {
61   EXEC SQL BEGIN DECLARE SECTION;
62   char name[MACHINE_NAME_SIZE];
63   EXEC SQL END DECLARE SECTION;
64
65   init_acls();
66
67   EXEC SQL CONNECT :db;
68
69   EXEC SQL WHENEVER SQLERROR DO sqlerr();
70
71   EXEC SQL DECLARE csr_hosts CURSOR FOR
72     SELECT m.name FROM machine m, serverhosts sh
73     WHERE m.mach_id = sh.mach_id AND sh.service = 'CUPS' AND sh.enable = 1;
74   EXEC SQL OPEN csr_hosts;
75   while (1)
76     {
77       EXEC SQL FETCH csr_hosts INTO :name;
78       if (sqlca.sqlcode)
79         break;
80
81       strtrim(name);
82       do_host(name);
83     }
84   EXEC SQL CLOSE csr_hosts;
85
86   exit(MR_SUCCESS);
87 }
88
89 void printer_user_list(FILE *out, char *type, int id, char *str)
90 {
91   struct save_queue *sq;
92   struct imember *m;
93
94   sq = get_acl(type, id, NULL);
95   while (sq_remove_data(sq, &m))
96     {
97       if (m->type == 'U')
98         fprintf(out, "%s %s\n", str, m->name);
99       freeimember(m);
100     }
101   sq_destroy(sq);
102 }
103
104
105
106 void do_host(char *host)
107 {
108   EXEC SQL BEGIN DECLARE SECTION;
109   char rp[PRINTERS_RP_SIZE], name[PRINTERS_NAME_SIZE];
110   char duplexname[PRINTERS_DUPLEXNAME_SIZE], location[PRINTERS_LOCATION_SIZE];
111   char hwtype[PRINTERS_HWTYPE_SIZE], lowerhwtype[PRINTERS_HWTYPE_SIZE];
112   char modtime[PRINTERS_MODTIME_SIZE], lmodtime[LIST_MODTIME_SIZE];
113   char contact[PRINTERS_CONTACT_SIZE], hostname[MACHINE_NAME_SIZE];
114   char cupshosts[MACHINE_NAME_SIZE], prtype [PRINTERS_TYPE_SIZE];
115   char *spoolhost = host, *unixtime_fmt = UNIXTIME_FMT, *p;
116   char *lhost;
117   int ka, pc, ac, lpc_acl, top_lpc_acl, banner, rm;
118   EXEC SQL END DECLARE SECTION;
119   TARFILE *tf;
120   FILE *out;
121   char filename[MAXPATHLEN], *duptc;
122   time_t mtime, now = time(NULL);
123
124   lhost = (char *) strdup (host);
125   for (p = lhost; *p; p++)
126      *p = tolower(*p);
127
128   EXEC SQL SELECT mach_id INTO :rm FROM machine
129     WHERE name = :spoolhost;
130
131   sprintf(filename, "%s/print/%s", DCM_DIR, host);
132   tf = tarfile_open(filename);
133
134   /* printers.conf */
135   out = tarfile_start(tf, "/etc/cups/printers.conf", 0644, 0, 0,
136                       "root", "lp", now);
137
138   EXEC SQL DECLARE csr_printers CURSOR FOR
139     SELECT pr.rp, pr.name, pr.duplexname, pr.hwtype,
140     m.name, pr.banner, pr.location, pr.contact, pr.ka,
141     pr.ac
142     FROM printers pr, machine m
143     WHERE pr.rm = :rm AND m.mach_id = pr.mach_id
144     AND pr.type != 'ALIAS';
145   EXEC SQL OPEN csr_printers;
146   while (1)
147     {
148       EXEC SQL FETCH csr_printers INTO :rp, :name, :duplexname,
149         :hwtype, :hostname, :banner, :location, :contact, :ka, :ac;
150       if (sqlca.sqlcode)
151         break;
152
153       strtrim(rp);
154       strtrim(name);
155       strtrim(duplexname);
156       strtrim(hwtype);
157       strtrim(hostname);
158       strtrim(location);
159       strtrim(contact);
160       strcpy(lowerhwtype, hwtype);
161       for (p = lowerhwtype; *p; p++)
162         *p = tolower(*p);
163
164       fprintf(out, "<Printer %s>\n",rp);
165       fprintf(out, "Info %s:%s\n", rp, hwtype);
166       /* Note the use of "beh" to keep the CUPS from disabling print queues
167        * should they not respond versus discarding the job.  
168        * See the "beh" page for details.  
169        * The 1/0/60 says "don't disable/try 20 times/try every 60s */
170       if (!strncmp(hwtype, "HP", 2)) 
171           fprintf(out, "DeviceURI beh:/1/20/60/socket://%s:9100\n", hostname);
172       else
173           fprintf(out, "DeviceURI beh:/1/20/60/socket://%s\n", hostname);
174       fprintf(out, "State Idle\n");     // Always with the Idle
175       fprintf(out, "StateTime %ld\n", (long)time(NULL));
176       fprintf(out, "Accepting Yes\n");
177       fprintf(out, "Shared Yes\n");
178       fprintf(out, "QuotaPeriod 0\n");
179       fprintf(out, "PageLimit 0\n");
180       fprintf(out, "Klimit 0\n");
181       fprintf(out, "Option sides one-sided\n");
182       if (location[0])
183         fprintf(out, "Location %s\n", location);
184       fprintf(out, "ErrorPolicy abort-job\n");
185       if (! ka || ! lpc_acl)
186         fprintf(out, "OpPolicy default\n");
187       else
188         fprintf(out, "OpPolicy %s-policy\n", rp);
189
190       /* Access-control list. */
191       if (ac)
192         {
193           if (ka)
194             fprintf(out, "AuthType Negotiate\n");
195           else
196             fprintf(out, "AuthType Negotiate\n");
197           printer_user_list(out, "LIST", ac, "AllowUser");
198         }
199
200       if (banner == PRN_BANNER_NONE)
201         fprintf(out, "JobSheets none none\n");
202       else 
203         fprintf(out, "JobSheets athena none\n");
204       fprintf(out, "</Printer>\n");
205
206     }
207   EXEC SQL CLOSE csr_printers;
208   tarfile_end(tf);
209
210
211   /* aliases are in classes.conf */
212   out = tarfile_start(tf, "/etc/cups/classes.conf", 0644, 0, 0,
213                       "root", "root", now);
214   EXEC SQL DECLARE csr_duplexqs CURSOR FOR
215     SELECT pr.rp, pr.name, pr.duplexname, pr.hwtype,
216     m.name, pr.banner, pr.location, pr.contact, pr.ka, 
217     pr.type as prtype, pr.ac
218     FROM printers pr, machine m
219     WHERE pr.rm = :rm AND m.mach_id = pr.mach_id;
220   EXEC SQL OPEN csr_duplexqs;
221   while (1)
222     {
223       EXEC SQL FETCH csr_duplexqs INTO :rp, :name, :duplexname,
224         :hwtype, :hostname, :banner, :location, :contact, :ka, :prtype, :ac;
225       if (sqlca.sqlcode)
226         break;
227
228       strtrim(hwtype);
229       strtrim(rp);
230       strtrim(location);
231       strtrim(contact);
232       strtrim(prtype);
233
234       /* Define alias queues as classes to the regular queues for
235        * accounting reasons.  Annoyingly, classes don't always inherit
236        * their printer definitions.
237       */
238       if (!strcmp(prtype,"ALIAS")) 
239         {
240           strtrim(name);
241           fprintf(out, "<Class %s>\n",name);
242           fprintf(out, "Info Alias Queue to %s:%s\n", rp, hwtype);
243           fprintf(out, "Printer %s\n", rp);
244           fprintf(out, "Option sides one-sided\n");
245           fprintf(out, "State Idle\n");     // Always with the Idle
246           fprintf(out, "StateTime %ld\n", (long)time(NULL));
247           fprintf(out, "Accepting Yes\n");
248           fprintf(out, "Shared Yes\n");
249           fprintf(out, "QuotaPeriod 0\n");
250           fprintf(out, "PageLimit 0\n");
251           if (location[0])
252             fprintf(out, "Location %s\n", location);
253           fprintf(out, "ErrorPolicy abort-job\n");
254           if (! ka || ! lpc_acl)
255             fprintf(out, "OpPolicy default\n");
256           else
257             fprintf(out, "OpPolicy %s-policy\n", rp);
258     
259           /* Access-control list. */
260           if (ac)
261             {
262               if (ka)
263                 fprintf(out, "AuthType Negotiate\n");
264               else
265                 fprintf(out, "AuthType Negotiate\n");
266               printer_user_list(out, "LIST", ac, "AllowUser");
267             }
268     
269           if (banner == PRN_BANNER_NONE)
270             fprintf(out, "JobSheets none none\n");
271           else 
272             fprintf(out, "JobSheets athena none\n");
273           fprintf(out, "</Class>\n");
274       }
275
276       /* Define duplex queues as aliases to the regular queues for
277        * accounting reasons.  Annoyingly, classes don't always inherit
278        * their printer definitions.
279       */
280       if (*duplexname)
281         {
282           strtrim(duplexname);
283           fprintf(out, "<Class %s>\n",duplexname);
284           if (!strcmp(prtype,"ALIAS")) 
285             fprintf(out, "Info Duplex Alias Queue to %s:%s\n", rp, hwtype);
286           else
287             fprintf(out, "Info Duplex Queue for %s:%s\n", rp, hwtype);
288           fprintf(out, "Option sides two-sided-long-edge\n");   // duplex
289           fprintf(out, "Printer %s\n", rp);
290           fprintf(out, "State Idle\n");     // Always with the Idle
291           fprintf(out, "StateTime %ld\n", (long)time(NULL));
292           fprintf(out, "Accepting Yes\n");
293           fprintf(out, "Shared Yes\n");
294           fprintf(out, "QuotaPeriod 0\n");
295           fprintf(out, "PageLimit 0\n");
296           if (location[0])
297             fprintf(out, "Location %s\n", location);
298           fprintf(out, "ErrorPolicy abort-job\n");
299           if (! ka || ! lpc_acl)
300             fprintf(out, "OpPolicy default\n");
301           else
302             fprintf(out, "OpPolicy %s-policy\n", rp);
303     
304           /* Access-control list. */
305           if (ac)
306             {
307               if (ka)
308                 fprintf(out, "AuthType Negotiate\n");
309               else
310                 fprintf(out, "AuthType Negotiate\n");
311               printer_user_list(out, "LIST", ac, "AllowUser");
312             }
313     
314           if (banner == PRN_BANNER_NONE)
315             fprintf(out, "JobSheets none none\n");
316           else if (banner == PRN_BANNER_LAST)
317             fprintf(out, "JobSheets athena none\n");
318           fprintf(out, "</Class>\n");
319         }
320     }
321   EXEC SQL CLOSE csr_duplexqs;
322   tarfile_end(tf);
323
324   /* cups.conf */
325   out = tarfile_start(tf, "/etc/cups/cupsd.conf", 0755, 1, 1,
326                       "root", "lp", now);
327
328   fprintf(out, "LogLevel info\n");
329   fprintf(out, "SystemGroup sys root ops-group\n");
330   fprintf(out, "Port 631\n");
331   fprintf(out, "Listen /var/run/cups/cups.sock\n");
332   fprintf(out, "Browsing On\n");
333   fprintf(out, "BrowseOrder allow,deny\n");
334   fprintf(out, "BrowseAllow all\n");
335   fprintf(out, "BrowseAddress @LOCAL\n");
336   fprintf(out, "DefaultAuthType Negotiate\n");
337   fprintf(out, "ServerCertificate /etc/cups/ssl/%s-ipp-crt.pem\n", lhost);
338   fprintf(out, "ServerKey /etc/cups/ssl/%s-ipp-key.pem\n", lhost);
339   fprintf(out, "ServerName %s\n", lhost);
340   fprintf(out, "Krb5Keytab /etc/krb5-ipp.keytab\n");
341   fprintf(out, "Browsing On\n");
342   fprintf(out, "BrowseProtocols cups\n");
343
344   /* The other CUPS servers should be aware of the other hosts'
345      queues, so we'll let them browse each other. */
346
347   EXEC SQL DECLARE csr_cupshosts CURSOR FOR
348     SELECT m.name AS cupshosts FROM machine m, printservers ps
349     WHERE m.mach_id = ps.mach_id AND ps.kind = 'CUPS';
350   EXEC SQL OPEN csr_cupshosts;
351   while (1)
352     {
353       EXEC SQL FETCH csr_cupshosts INTO :cupshosts;
354       if (sqlca.sqlcode)
355         break;
356
357       strtrim(cupshosts);
358
359       /* Don't poll yourself looking for answers! */
360       if (strcmp(cupshosts,host))
361          fprintf(out, "BrowsePoll %s\n", cupshosts);
362     }
363   EXEC SQL CLOSE csr_cupshosts;
364   fprintf(out, "Include cups.locations.conf\n");
365   fprintf(out, "Include cups.policies.conf\n");
366
367   tarfile_end(tf);
368
369   /* cups.policies.conf */
370   out = tarfile_start(tf, "/etc/cups/cups.policies.conf", 0755, 1, 1,
371                       "root", "lp", now);
372   fprintf(out, "# Printer-specific LPC and LPR ACLs\n");
373   /* lpcaccess.top */
374   EXEC SQL SELECT ps.lpc_acl INTO :top_lpc_acl
375     FROM printservers ps, machine m
376     WHERE m.name = :spoolhost AND m.mach_id = ps.mach_id;
377   if (!sqlca.sqlcode && lpc_acl)
378     {
379       fprintf (out, "<Policy default>\n");
380       fprintf (out, "%s\n", alterjob);
381       fprintf (out, "AuthType Default\n");
382       fprintf (out, "Require user @OWNER @SYSTEM\n");
383       printer_user_list(out, "LIST", top_lpc_acl, "Require user");
384       fprintf (out, "Order deny,allow\n");
385       fprintf (out, "</Limit>\n");
386       fprintf (out, "%s\n", submitjob);
387       fprintf (out, "AuthType Default\n");
388       fprintf (out, "Order deny,allow\n");
389       fprintf (out, "</Limit>\n");
390       fprintf (out, "%s\n", alterpntr);
391       fprintf (out, "AuthType Default\n");
392       fprintf (out, "Require user @SYSTEM\n");
393       fprintf (out, "Order deny,allow\n");
394       fprintf (out, "</Limit>\n");
395       fprintf (out, "%s\n", lpcpntr);
396       fprintf (out, "AuthType Default\n");
397       fprintf (out, "Require user @SYSTEM\n");
398       printer_user_list(out, "LIST", top_lpc_acl, "Require user");
399       fprintf (out, "Order deny,allow\n");
400       fprintf (out, "</Limit>\n");
401       fprintf (out, "%s\n", canceljob);
402       fprintf (out, "AuthType Default\n");
403       fprintf (out, "Require user @OWNER @SYSTEM\n");
404       printer_user_list(out, "LIST", top_lpc_acl, "Require user");
405       fprintf (out, "Order deny,allow\n");
406       fprintf (out, "</Limit>\n");
407       fprintf (out, "%s\n", catchall);
408       fprintf (out, "Order deny,allow\n");
409       fprintf (out, "</Limit>\n");
410       fprintf (out, "</Policy>\n");
411     }
412
413   /* restrict lists and lpcaccess policies.  Sadly, we have to put the
414      top level for each new policy since CUPS doesn't have a way of 
415      doing it otherwise (well, Unix groups, but not moira) */
416   EXEC SQL DECLARE csr_lpc CURSOR FOR
417     SELECT UNIQUE rp, ka, ac, lpc_acl
418     FROM printers
419     WHERE rm = :rm AND ( ac != 0 OR lpc_acl != 0);
420   EXEC SQL OPEN csr_lpc;
421   while (1)
422     {
423       EXEC SQL FETCH csr_lpc INTO :name, :ka, :ac, :lpc_acl;
424       if (sqlca.sqlcode)
425         break;
426
427       strtrim(name);
428
429       fprintf (out, "<Policy %s-policy>\n", name);
430       fprintf (out, "%s\n", alterjob);
431       fprintf (out, "AuthType Default\n");
432       fprintf (out, "Require user @OWNER @SYSTEM\n");
433       printer_user_list(out, "LIST", lpc_acl, "Require user");
434       fprintf (out, "Order deny,allow\n");
435       fprintf (out, "</Limit>\n");
436       fprintf (out, "%s\n", submitjob);
437       /* If the printer is Kerberized? */
438       if (ka)
439         fprintf (out, "AuthType Negotiate\n");
440       else
441         fprintf (out, "AuthType None\n");
442       /* Access-control list. */
443       if (ac)
444         printer_user_list(out, "LIST", ac, "Require user");
445       else if (ka)
446         fprintf (out, "Require valid-user\n");
447       fprintf (out, "Order deny,allow\n");
448       fprintf (out, "</Limit>\n");
449       fprintf (out, "%s\n", alterpntr);
450       fprintf (out, "AuthType Default\n");
451       fprintf (out, "Require user @SYSTEM\n");
452       fprintf (out, "Order deny,allow\n");
453       fprintf (out, "</Limit>\n");
454       fprintf (out, "%s\n", lpcpntr);
455       fprintf (out, "AuthType Default\n");
456       fprintf (out, "Require user @SYSTEM\n");
457       /* printer-specific lpc access. */
458       if (lpc_acl)
459           printer_user_list(out, "LIST", lpc_acl, "Require user");
460       printer_user_list(out, "LIST", top_lpc_acl, "Require user");
461       fprintf (out, "Order deny,allow\n");
462       fprintf (out, "</Limit>\n");
463       fprintf (out, "%s\n", canceljob);
464       fprintf (out, "AuthType Default\n");
465       fprintf (out, "Require user @OWNER @SYSTEM\n");
466       printer_user_list(out, "LIST", lpc_acl, "Require user");
467       printer_user_list(out, "LIST", top_lpc_acl, "Require user");
468       fprintf (out, "Order deny,allow\n");
469       fprintf (out, "</Limit>\n");
470       fprintf (out, "%s\n", catchall);
471       fprintf (out, "Order deny,allow\n");
472       fprintf (out, "</Limit>\n");
473       fprintf (out, "</Policy>\n");
474     }
475   EXEC SQL CLOSE csr_lpc;
476   fprintf(out, "\n");
477   tarfile_end(tf);
478   tarfile_close(tf);
479 }
480
481 void sqlerr(void)
482 {
483   db_error(sqlca.sqlcode);
484 }
This page took 0.082709 seconds and 5 git commands to generate.