3 * This generates printcaps and other files for Athena print servers
5 * Copyright (C) 1992-1998 by the Massachusetts Institute of Technology.
6 * For copying and distribution information, please see the file
10 #include <mit-copyright.h>
12 #include <moira_site.h>
15 #include <sys/types.h>
29 EXEC SQL INCLUDE sqlca;
33 char *whoami = "cups-print.gen";
34 char *db = "moira/moira";
36 const int krbvers = 5; /* use Kerberos 5 */
38 /* OMG, I hate this, but it's cleaner, I guess? */
40 const char *alterjob = "<Limit Hold-Job Release-Job\
41 Restart-Job Purge-Jobs Reprocess-Job Set-Job-Attributes\
42 Cancel-Current-Job Suspend-Current-Job Resume-Job CUPS-Move-Job>";
43 const char *submitjob = "<Limit Create-Job Print-Job Print-URI Send-Document\
44 Set-Job-Attributes Send-URI Create-Job-Subscription Renew-Subscription\
45 Cancel-Subscription Get-Notifications CUPS-Move-Job>";
46 const char *alterpntr = "<Limit CUPS-Add-Modify-Printer CUPS-Delete-Printer\
47 CUPS-Add-Modify-Class CUPS-Delete-Class CUPS-Set-Default>";
48 const char *lpcpntr = "<Limit Pause-Printer Resume-Printer Enable-Printer\
49 Disable-Printer Pause-Printer-After-Current-Job Hold-New-Jobs\
50 Release-Held-New-Jobs Deactivate-Printer Activate-Printer Restart-Printer\
51 Shutdown-Printer Startup-Printer Promote-Job Schedule-Job-After\
52 CUPS-Accept-Jobs CUPS-Reject-Jobs>";
53 const char *canceljob = "<Limit Cancel-Job CUPS-Authenticate-Job>";
54 const char *catchall = "<Limit All>";
55 const char *phost = "printers.MIT.EDU";
57 void do_host(char *host);
60 #define MAX(a, b) ( (a) > (b) ? (a) : (b) )
63 int main(int argc, char **argv)
65 EXEC SQL BEGIN DECLARE SECTION;
66 char name[MACHINE_NAME_SIZE];
67 EXEC SQL END DECLARE SECTION;
73 EXEC SQL WHENEVER SQLERROR DO sqlerr();
75 EXEC SQL DECLARE csr_hosts CURSOR FOR
76 SELECT m.name FROM machine m, serverhosts sh
77 WHERE m.mach_id = sh.mach_id AND sh.service = 'CUPS-PRINT' AND sh.enable = 1;
78 EXEC SQL OPEN csr_hosts;
81 EXEC SQL FETCH csr_hosts INTO :name;
88 EXEC SQL CLOSE csr_hosts;
93 void printer_user_list(FILE *out, char *type, int id, char *str)
95 struct save_queue *sq;
97 char kbuf[MAX_K_NAME_SZ];
100 sq = get_acl(type, id, NULL);
101 while (sq_remove_data(sq, &m))
103 if (m->type != 'S' && m->type != NULL) {
104 /* CUPS wants mmanley/root, not mmanley.root@ATHENA.MIT.EDU */
105 canon_krb(m, krbvers, kbuf, sizeof(kbuf));
107 /* now, take out all the @realm */
108 for (cp=kbuf; *cp; cp++) {
109 if (*cp == '@') *cp = '\0';
111 fprintf(out, "%s %s\n", str, kbuf);
120 void do_host(char *host)
122 EXEC SQL BEGIN DECLARE SECTION;
123 char rp[PRINTERS_RP_SIZE], name[PRINTERS_NAME_SIZE];
124 char duplexname[PRINTERS_DUPLEXNAME_SIZE], location[PRINTERS_LOCATION_SIZE];
125 char hwtype[PRINTERS_HWTYPE_SIZE], lowerhwtype[PRINTERS_HWTYPE_SIZE];
126 char modtime[PRINTERS_MODTIME_SIZE], lmodtime[LIST_MODTIME_SIZE];
127 char contact[PRINTERS_CONTACT_SIZE], hostname[MACHINE_NAME_SIZE];
128 char cupshosts[MACHINE_NAME_SIZE], prtype [PRINTERS_TYPE_SIZE];
129 char *spoolhost = host, *unixtime_fmt = UNIXTIME_FMT, *p;
131 int ka, pc, ac, lpc_acl, top_lpc_acl, banner, rm;
132 EXEC SQL END DECLARE SECTION;
135 char filename[MAXPATHLEN], *duptc;
136 time_t mtime, now = time(NULL);
138 lhost = (char *) strdup (host);
139 for (p = lhost; *p; p++)
142 EXEC SQL SELECT mach_id INTO :rm FROM machine
143 WHERE name = :spoolhost;
145 sprintf(filename, "%s/cups-print/%s", DCM_DIR, host);
146 tf = tarfile_open(filename);
148 /* printers.conf entries for locally run queues */
149 out = tarfile_start(tf, "/etc/cups/printers.conf", 0644, 0, 0,
152 EXEC SQL DECLARE csr_printers CURSOR FOR
153 SELECT pr.rp, pr.name, pr.duplexname, pr.hwtype,
154 m.name, pr.banner, pr.location, pr.contact, pr.ka,
156 FROM printers pr, machine m
157 WHERE pr.rm = :rm AND m.mach_id = pr.mach_id
158 AND pr.type != 'ALIAS';
159 EXEC SQL OPEN csr_printers;
162 EXEC SQL FETCH csr_printers INTO :rp, :name, :duplexname,
163 :hwtype, :hostname, :banner, :location, :contact, :ka, :ac, :lpc_acl;
174 strcpy(lowerhwtype, hwtype);
175 for (p = rp; *p; p++) /* Because uppercased printer names suck */
177 for (p = lowerhwtype; *p; p++)
180 fprintf(out, "<Printer %s>\n",rp);
181 fprintf(out, "Info %s:%s\n", rp, hwtype);
182 /* Note the use of "beh" to keep the CUPS from disabling print queues
183 * should they not respond versus discarding the job.
184 * See the "beh" page for details.
185 * The 1/0/60 says "don't disable/try 20 times/try every 60s */
186 if (!strncmp(hwtype, "HP", 2))
187 fprintf(out, "DeviceURI beh:/1/20/60/socket://%s:9100\n", hostname);
189 fprintf(out, "DeviceURI beh:/1/20/60/socket://%s\n", hostname);
190 fprintf(out, "State Idle\n"); // Always with the Idle
191 fprintf(out, "StateTime %ld\n", (long)time(NULL));
192 fprintf(out, "Accepting Yes\n");
193 fprintf(out, "Shared Yes\n");
194 fprintf(out, "QuotaPeriod 0\n");
195 fprintf(out, "PageLimit 0\n");
196 fprintf(out, "Klimit 0\n");
197 fprintf(out, "Option sides one-sided\n");
198 fprintf(out, "Filter application/vnd.cups-raw 0 -\n");
199 fprintf(out, "Filter application/vnd.cups-postscript 100 foomatic-rip\n");
200 fprintf(out, "Filter application/vnd.cups-pdf 0 foomatic-rip\n");
201 fprintf(out, "Filter application/vnd.apple-pdf 25 foomatic-rip\n");
202 fprintf(out, "Filter application/vnd.cups-command 0 commandtops\n");
204 fprintf(out, "Location %s\n", location);
205 fprintf(out, "ErrorPolicy abort-job\n");
207 fprintf(out, "OpPolicy %s-policy\n", rp);
209 fprintf(out, "OpPolicy default\n");
211 /* Access-control list. */
215 fprintf(out, "AuthType Negotiate\n");
217 fprintf(out, "AuthType Default\n");
218 printer_user_list(out, "LIST", ac, "AllowUser");
221 if (banner == PRN_BANNER_NONE)
222 fprintf(out, "JobSheets none none\n");
224 fprintf(out, "JobSheets athena none\n");
225 fprintf(out, "</Printer>\n");
228 EXEC SQL CLOSE csr_printers;
230 /* printers.conf entries for non-local CUPS queues */
231 EXEC SQL DECLARE csr_remote_printers CURSOR FOR
232 SELECT pr.rp, pr.name, pr.duplexname, pr.hwtype,
233 m.name, pr.banner, pr.location, pr.contact, pr.ka,
234 pr.ac, pr.lpc_acl, m.name as cupshosts
235 FROM printers pr, machine m, serverhosts sh
236 WHERE pr.rm = m.mach_id
237 AND pr.type != 'ALIAS' AND m.name <> :spoolhost AND
238 m.mach_id = sh.mach_id AND sh.service = 'CUPS-PRINT' AND
239 sh.enable = 1 AND m.mach_id = sh.mach_id;
241 EXEC SQL OPEN csr_remote_printers;
244 EXEC SQL FETCH csr_remote_printers INTO :rp, :name, :duplexname,
245 :hwtype, :hostname, :banner, :location, :contact, :ka, :ac, :lpc_acl, :cupshosts;
257 strcpy(lowerhwtype, hwtype);
258 for (p = rp; *p; p++) /* Because uppercased printer names suck */
260 for (p = lowerhwtype; *p; p++)
263 fprintf(out, "<Printer %s>\n",rp);
264 fprintf(out, "Info %s:%s\n", rp, hwtype);
265 fprintf(out, "DeviceURI ipp://%s:631/printers/%s\n", cupshosts, rp);
266 fprintf(out, "State Idle\n"); // Always with the Idle
267 fprintf(out, "StateTime %ld\n", (long)time(NULL));
268 fprintf(out, "Accepting Yes\n");
269 fprintf(out, "Shared Yes\n");
270 fprintf(out, "QuotaPeriod 0\n");
271 fprintf(out, "PageLimit 0\n");
272 fprintf(out, "Klimit 0\n");
273 fprintf(out, "Option sides one-sided\n");
274 fprintf(out, "Filter application/vnd.cups-raw 0 -\n");
275 fprintf(out, "Filter application/vnd.cups-postscript 100 foomatic-rip\n");
276 fprintf(out, "Filter application/vnd.cups-pdf 0 foomatic-rip\n");
277 fprintf(out, "Filter application/vnd.apple-pdf 25 foomatic-rip\n");
278 fprintf(out, "Filter application/vnd.cups-command 0 commandtops\n");
280 fprintf(out, "Location %s\n", location);
281 fprintf(out, "ErrorPolicy abort-job\n");
283 fprintf(out, "OpPolicy %s-policy\n", rp);
285 fprintf(out, "OpPolicy default\n");
287 /* Access-control list. */
291 fprintf(out, "AuthType Negotiate\n");
293 fprintf(out, "AuthType Default\n");
294 printer_user_list(out, "LIST", ac, "AllowUser");
297 if (banner == PRN_BANNER_NONE)
298 fprintf(out, "JobSheets none none\n");
300 fprintf(out, "JobSheets athena none\n");
301 fprintf(out, "</Printer>\n");
304 EXEC SQL CLOSE csr_remote_printers;
306 /* printers.conf entries for non-local LPRng queues */
307 EXEC SQL DECLARE csr_lprng_printers CURSOR FOR
308 SELECT pr.rp, pr.name, pr.duplexname, pr.hwtype,
309 m.name, pr.banner, pr.location, pr.contact, pr.ka,
310 pr.ac, pr.lpc_acl, m.name as cupshosts
311 FROM printers pr, machine m, serverhosts sh
312 WHERE pr.rm = m.mach_id
313 AND pr.type != 'ALIAS' AND m.name <> :spoolhost AND
314 m.mach_id = sh.mach_id AND sh.service = 'PRINT' AND
317 EXEC SQL OPEN csr_lprng_printers;
320 EXEC SQL FETCH csr_lprng_printers INTO :rp, :name, :duplexname,
321 :hwtype, :hostname, :banner, :location, :contact, :ka, :ac, :lpc_acl, :cupshosts;
333 strcpy(lowerhwtype, hwtype);
334 for (p = rp; *p; p++) /* Because uppercased printer names suck */
336 for (p = lowerhwtype; *p; p++)
339 fprintf(out, "<Printer %s>\n",rp);
340 fprintf(out, "Info %s:LPRng Queue on %s\n", rp, cupshosts);
341 fprintf(out, "DeviceURI lpd://%s/%s\n", cupshosts, rp);
342 fprintf(out, "State Idle\n"); // Always with the Idle
343 fprintf(out, "StateTime %ld\n", (long)time(NULL));
344 fprintf(out, "Accepting Yes\n");
345 fprintf(out, "Shared Yes\n");
346 fprintf(out, "QuotaPeriod 0\n");
347 fprintf(out, "PageLimit 0\n");
348 fprintf(out, "Klimit 0\n");
349 fprintf(out, "Option sides one-sided\n");
350 fprintf(out, "Filter application/vnd.cups-raw 0 -\n");
351 fprintf(out, "Filter application/vnd.cups-postscript 100 foomatic-rip\n");
352 fprintf(out, "Filter application/vnd.cups-pdf 0 foomatic-rip\n");
353 fprintf(out, "Filter application/vnd.apple-pdf 25 foomatic-rip\n");
354 fprintf(out, "Filter application/vnd.cups-command 0 commandtops\n");
356 fprintf(out, "Location %s\n", location);
357 fprintf(out, "ErrorPolicy abort-job\n");
358 fprintf(out, "OpPolicy default\n");
359 fprintf(out, "JobSheets none none\n");
360 fprintf(out, "</Printer>\n");
363 EXEC SQL CLOSE csr_lprng_printers;
367 /* aliases are in classes.conf */
368 out = tarfile_start(tf, "/etc/cups/classes.conf", 0644, 0, 0,
370 EXEC SQL DECLARE csr_duplexqs CURSOR FOR
371 SELECT pr.rp, pr.name, pr.duplexname, pr.hwtype,
372 m.name, pr.banner, pr.location, pr.contact, pr.ka,
373 pr.type as prtype, pr.ac
374 FROM printers pr, machine m, serverhosts sh
375 WHERE pr.rm = m.mach_id
376 AND m.mach_id = sh.mach_id AND sh.enable = 1
377 AND (sh.service = 'CUPS-PRINT' OR sh.service = 'PRINT');
378 EXEC SQL OPEN csr_duplexqs;
381 EXEC SQL FETCH csr_duplexqs INTO :rp, :name, :duplexname,
382 :hwtype, :hostname, :banner, :location, :contact, :ka, :prtype, :ac;
392 /* Define alias queues as classes to the regular queues for
393 * accounting reasons. Annoyingly, classes don't always inherit
394 * their printer definitions.
396 if (!strcmp(prtype,"ALIAS"))
399 fprintf(out, "<Class %s>\n",name);
400 fprintf(out, "Info Alias Queue to %s:%s\n", rp, hwtype);
401 fprintf(out, "Printer %s\n", rp);
402 fprintf(out, "Option sides one-sided\n");
403 fprintf(out, "State Idle\n"); // Always with the Idle
404 fprintf(out, "StateTime %ld\n", (long)time(NULL));
405 fprintf(out, "Accepting Yes\n");
406 fprintf(out, "Shared Yes\n");
407 fprintf(out, "QuotaPeriod 0\n");
408 fprintf(out, "PageLimit 0\n");
410 fprintf(out, "Location %s\n", location);
411 /* fprintf(out, "ErrorPolicy abort-job\n"); */
413 fprintf(out, "OpPolicy %s-policy\n", rp);
415 fprintf(out, "OpPolicy default\n");
417 /* Access-control list. */
421 fprintf(out, "AuthType Negotiate\n");
423 fprintf(out, "AuthType Default\n");
424 printer_user_list(out, "LIST", ac, "AllowUser");
427 if (banner == PRN_BANNER_NONE)
428 fprintf(out, "JobSheets none none\n");
430 fprintf(out, "JobSheets athena none\n");
431 fprintf(out, "</Class>\n");
434 /* Define duplex queues as aliases to the regular queues for
435 * accounting reasons. Annoyingly, classes don't always inherit
436 * their printer definitions.
441 fprintf(out, "<Class %s>\n",duplexname);
442 if (!strcmp(prtype,"ALIAS"))
443 fprintf(out, "Info Duplex Alias Queue to %s:%s\n", rp, hwtype);
445 fprintf(out, "Info Duplex Queue for %s:%s\n", rp, hwtype);
446 fprintf(out, "Option sides two-sided-long-edge\n"); // duplex
447 fprintf(out, "Printer %s\n", rp);
448 fprintf(out, "State Idle\n"); // Always with the Idle
449 fprintf(out, "StateTime %ld\n", (long)time(NULL));
450 fprintf(out, "Accepting Yes\n");
451 fprintf(out, "Shared Yes\n");
452 fprintf(out, "QuotaPeriod 0\n");
453 fprintf(out, "PageLimit 0\n");
455 fprintf(out, "Location %s\n", location);
456 fprintf(out, "ErrorPolicy abort-job\n");
458 fprintf(out, "OpPolicy %s-policy\n", rp);
460 fprintf(out, "OpPolicy default\n");
462 /* Access-control list. */
466 fprintf(out, "AuthType Negotiate\n");
468 fprintf(out, "AuthType Default\n");
469 printer_user_list(out, "LIST", ac, "AllowUser");
472 if (banner == PRN_BANNER_NONE)
473 fprintf(out, "JobSheets none none\n");
474 else if (banner == PRN_BANNER_LAST)
475 fprintf(out, "JobSheets athena none\n");
476 fprintf(out, "</Class>\n");
479 EXEC SQL CLOSE csr_duplexqs;
483 out = tarfile_start(tf, "/etc/cups/cupsd.conf", 0755, 1, 1,
486 fprintf(out, "LogLevel info\n");
487 fprintf(out, "SystemGroup sys root ops-group\n");
488 fprintf(out, "Port 631\n");
489 fprintf(out, "Listen /var/run/cups/cups.sock\n");
490 fprintf(out, "Browsing On\n");
491 fprintf(out, "BrowseOrder allow,deny\n");
492 fprintf(out, "BrowseAllow all\n");
493 fprintf(out, "BrowseAddress @LOCAL\n");
494 fprintf(out, "DefaultAuthType Negotiate\n");
495 fprintf(out, "ServerCertificate /etc/cups/ssl/%s-ipp-crt.pem\n", lhost);
496 fprintf(out, "ServerKey /etc/cups/ssl/%s-ipp-key.pem\n", lhost);
497 fprintf(out, "ServerName %s\n", lhost);
498 fprintf(out, "ServerAlias %s\n", phost);
499 fprintf(out, "Krb5Keytab /etc/krb5-ipp.keytab\n");
501 /* The other CUPS servers should be aware of the other hosts'
502 queues, so we'll let them browse each other. */
503 fprintf(out, "Include cups.local.conf\n");
504 fprintf(out, "Include cups.locations.conf\n");
505 fprintf(out, "Include cups.policies.conf\n");
508 /* cups.hosts.conf */
509 out = tarfile_start(tf, "/etc/cups/cups.hosts.conf", 0755, 1, 1,
511 EXEC SQL DECLARE csr_cupshosts CURSOR FOR
512 SELECT m.name AS cupshosts FROM machine m, printservers ps
513 WHERE m.mach_id = ps.mach_id AND ps.kind = 'CUPS';
514 EXEC SQL OPEN csr_cupshosts;
517 EXEC SQL FETCH csr_cupshosts INTO :cupshosts;
523 /* Don't poll yourself looking for answers! */
524 if (strcmp(cupshosts,host))
525 fprintf(out, "BrowsePoll %s\n", cupshosts);
527 EXEC SQL CLOSE csr_cupshosts;
531 /* cups.policies.conf */
532 out = tarfile_start(tf, "/etc/cups/cups.policies.conf", 0755, 1, 1,
534 fprintf(out, "# Printer-specific LPC and LPR ACLs\n");
536 EXEC SQL SELECT ps.lpc_acl INTO :top_lpc_acl
537 FROM printservers ps, machine m
538 WHERE m.name = :spoolhost AND m.mach_id = ps.mach_id;
539 if (!sqlca.sqlcode && lpc_acl)
541 fprintf (out, "<Policy default>\n");
542 fprintf (out, "%s\n", alterjob);
543 fprintf (out, "AuthType Default\n");
544 fprintf (out, "Require user @OWNER @SYSTEM\n");
545 printer_user_list(out, "LIST", top_lpc_acl, "Require user");
546 fprintf (out, "Order deny,allow\n");
547 fprintf (out, "</Limit>\n");
548 fprintf (out, "%s\n", submitjob);
549 fprintf (out, "AuthType None\n");
550 fprintf (out, "Order deny,allow\n");
551 fprintf (out, "Allow from all\n");
552 fprintf (out, "</Limit>\n");
553 fprintf (out, "%s\n", alterpntr);
554 fprintf (out, "AuthType Default\n");
555 fprintf (out, "Require user @SYSTEM\n");
556 fprintf (out, "Order deny,allow\n");
557 fprintf (out, "</Limit>\n");
558 fprintf (out, "%s\n", lpcpntr);
559 fprintf (out, "AuthType Default\n");
560 fprintf (out, "Require user @SYSTEM\n");
561 printer_user_list(out, "LIST", top_lpc_acl, "Require user");
562 fprintf (out, "Order deny,allow\n");
563 fprintf (out, "</Limit>\n");
564 fprintf (out, "%s\n", canceljob);
565 fprintf (out, "AuthType Default\n");
566 fprintf (out, "Require user @OWNER @SYSTEM\n");
567 printer_user_list(out, "LIST", top_lpc_acl, "Require user");
568 fprintf (out, "Order deny,allow\n");
569 fprintf (out, "Allow from all\n");
570 fprintf (out, "</Limit>\n");
571 fprintf (out, "%s\n", catchall);
572 fprintf (out, "AuthType None\n");
573 fprintf (out, "Order deny,allow\n");
574 fprintf (out, "Allow from all\n");
575 fprintf (out, "</Limit>\n");
576 fprintf (out, "</Policy>\n");
579 /* restrict lists and lpcaccess policies. Sadly, we have to put the
580 top level for each new policy since CUPS doesn't have a way of
581 doing it otherwise (well, Unix groups, but not moira) */
582 EXEC SQL DECLARE csr_lpc CURSOR FOR
583 SELECT UNIQUE rp, ka, ac, lpc_acl
585 WHERE (ac != 0 OR lpc_acl != 0) AND rm in (SELECT m.mach_id FROM machine m, serverhosts sh
586 WHERE m.mach_id = sh.mach_id AND sh.service = 'CUPS-PRINT' AND sh.enable = 1);
587 EXEC SQL OPEN csr_lpc;
590 EXEC SQL FETCH csr_lpc INTO :name, :ka, :ac, :lpc_acl;
596 fprintf (out, "<Policy %s-policy>\n", name);
597 fprintf (out, "%s\n", alterjob);
598 fprintf (out, "AuthType Default\n");
599 fprintf (out, "Require user @OWNER @SYSTEM\n");
600 printer_user_list(out, "LIST", lpc_acl, "Require user");
601 fprintf (out, "Order deny,allow\n");
602 fprintf (out, "Allow from all\n");
603 fprintf (out, "</Limit>\n");
604 fprintf (out, "%s\n", submitjob);
605 /* If the printer is Kerberized? */
607 fprintf (out, "AuthType Negotiate\n");
609 fprintf (out, "AuthType None\n");
610 /* Access-control list. */
612 printer_user_list(out, "LIST", ac, "Require user");
614 fprintf (out, "Require valid-user\n");
615 fprintf (out, "Order deny,allow\n");
616 fprintf (out, "Allow from all\n");
617 fprintf (out, "</Limit>\n");
618 fprintf (out, "%s\n", alterpntr);
619 fprintf (out, "AuthType Default\n");
620 fprintf (out, "Require user @SYSTEM\n");
621 fprintf (out, "Order deny,allow\n");
622 fprintf (out, "</Limit>\n");
623 fprintf (out, "%s\n", lpcpntr);
624 fprintf (out, "AuthType Default\n");
625 fprintf (out, "Require user @SYSTEM\n");
626 /* printer-specific lpc access. */
628 printer_user_list(out, "LIST", lpc_acl, "Require user");
629 printer_user_list(out, "LIST", top_lpc_acl, "Require user");
630 fprintf (out, "Order deny,allow\n");
631 fprintf (out, "</Limit>\n");
632 fprintf (out, "%s\n", canceljob);
633 fprintf (out, "AuthType Default\n");
634 fprintf (out, "Require user @OWNER @SYSTEM\n");
635 printer_user_list(out, "LIST", lpc_acl, "Require user");
636 printer_user_list(out, "LIST", top_lpc_acl, "Require user");
637 fprintf (out, "Order deny,allow\n");
638 fprintf (out, "Allow from all\n");
639 fprintf (out, "</Limit>\n");
640 fprintf (out, "%s\n", catchall);
641 fprintf (out, "AuthType None\n");
642 fprintf (out, "Order deny,allow\n");
643 fprintf (out, "Allow from all\n");
644 fprintf (out, "</Limit>\n");
645 fprintf (out, "</Policy>\n");
647 EXEC SQL CLOSE csr_lpc;
655 db_error(sqlca.sqlcode);