1 /*
2 Copyright (C) 2016-2021, Dirk Krause
3 SPDX-License-Identifier: BSD-3-Clause
4 */
5 
6 /*
7 	WARNING: This file was generated by the dkct program (see
8 	http://dktools.sourceforge.net/ for details).
9 	Changes you make here will be lost if dkct is run again!
10 	You should modify the original source and run dkct on it.
11 	Original source: printqd.ctr
12 */
13 
14 
15 /**	@file	printqd.c	The printqd daemon.
16 
17 A print accounting and quota daemon for use with the LPRng print system.
18 */
19 
20 
21 
22 #include "dk4conf.h"
23 #include <libdk4base/dk4types.h>
24 
25 
26 
27 /* CORRECT NEXT LINE AFTER REPLACING PRINTQD */
28 #include <printqd/printqd.h>
29 
30 
31 
32 #if	(DK4_CHAR_SIZE == 1) \
33 &&	((DK4_HAVE_SIGACTION) || (DK4_HAVE_SIGSET)) \
34 &&	DK4_HAVE_GETPWNAM && DK4_HAVE_GETGRNAM \
35 &&	((DK4_HAVE_SETSID) || (DK4_HAVE_SETPGRP)) \
36 &&	((DK4_HAVE_PWD_H) && (DK4_HAVE_GRP_H)) \
37 &&	DK4_HAVE_UID_T && DK4_HAVE_GID_T && DK4_HAVE_MODE_T && (!DK4_ON_WINDOWS)
38 
39 
40 
41 #include <stdio.h>
42 
43 #if	DK4_HAVE_SYS_TYPES_H
44 #ifndef	SYS_TYPES_H_INCLUDED
45 #include <sys/types.h>
46 #define	SYS_TYPES_H_INCLUDED 1
47 #endif
48 #endif
49 
50 #if	DK4_HAVE_SYS_STAT_H
51 #ifndef	SYS_STAT_H_INCLUDED
52 #include <sys/stat.h>
53 #define	SYS_STAT_H_INCLUDED 1
54 #endif
55 #endif
56 
57 #if	DK4_HAVE_FCNTL_H
58 #ifndef	FCNTL_H_INCLUDED
59 #include <fcntl.h>
60 #define	FCNTL_H_INCLUDED 1
61 #endif
62 #endif
63 
64 #if	DK4_HAVE_ERRNO_H
65 #ifndef	ERRNO_H_INCLUDED
66 #include <errno.h>
67 #define	ERRNO_H_INCLUDED 1
68 #endif
69 #endif
70 
71 #if	DK4_HAVE_UNISTD_H
72 #ifndef	UNISTD_H_INCLUDED
73 #include <unistd.h>
74 #define	UNISTD_H_INCLUDED 1
75 #endif
76 #endif
77 
78 #if	DK4_HAVE_PWD_H
79 #ifndef	PWD_H_INCLUDED
80 #include <pwd.h>
81 #define	PWD_H_INCLUDED 1
82 #endif
83 #endif
84 
85 #if	DK4_HAVE_GRP_H
86 #ifndef	GRP_H_INCLUDED
87 #include <grp.h>
88 #define	GRP_H_INCLUDED 1
89 #endif
90 #endif
91 
92 #if	DK4_HAVE_SYSLOG_H
93 #ifndef	SYSLOG_H_INCLUDED
94 #include <syslog.h>
95 #define	SYSLOG_H_INCLUDED 1
96 #endif
97 #endif
98 
99 #if	DK4_HAVE_SYSEXITS_H
100 #ifndef	SYSEXITS_H_INCLUDED
101 #include <sysexits.h>
102 #define	SYSEXITS_H_INCLUDED 1
103 #endif
104 #endif
105 
106 #include <libdk4c/dk4opt.h>
107 #include <libdk4c/dk4dmt.h>
108 #include <libdk4c/dk4inst.h>
109 #include <libdk4c/dk4dmt.h>
110 #include <libdk4c/dk4sto.h>
111 #include <libdk4sock/dk4sock.h>
112 #include <libdk4base/dk4mem.h>
113 #include <libdk4base/dk4str8.h>
114 #include <libdk4maio8d/dk4mai8dii.h>
115 #include <libdk4maio8d/dk4mai8dsz.h>
116 #include <libdk4maio8d/dk4mai8dus.h>
117 #include <libdk4maio8d/dk4mai8ddu.h>
118 #include <libdk4maio8d/dk4mao8d.h>
119 #include <libdk4c/dk4fopc8.h>
120 #include <libdk4dbi/dk4dbi.h>
121 #include <libdk4dbi/dk4dbit8.h>
122 #include <libdk4c/dk4time.h>
123 #include <libdk4c/dk4time08.h>
124 #include <libdk4c/dk4mkdh8.h>
125 #include <libdk4c/dk4delfile08.h>
126 #include <libdk4base/dk4unused.h>
127 
128 
129 
130 
131 
132 
133 
134 #ifndef	LOG_LPR
135 /**	Default log feature for printing.
136 */
137 #define	LOG_LPR (6 << 3)
138 #endif
139 
140 
141 
142 #ifndef	LOG_EMERG
143 /**	Log message level to ignore, printqd does not make system unusable.
144 */
145 #define	LOG_EMERG	(0)
146 #endif
147 
148 #ifndef	LOG_ERR
149 /**	Log message level error.
150 */
151 #define	LOG_ERR		(3)
152 #endif
153 
154 #ifndef	LOG_INFO
155 /**	Log message level info.
156 */
157 #define	LOG_INFO	(6)
158 #endif
159 
160 /**	Input buffer, used
161 	* for configuration file reading and
162 	* for reading requests.
163 */
164 static	char		inbuf[1024];
165 
166 
167 /**	Buffer to construct key for database entries.
168 */
169 static	char		kb[sizeof(inbuf)];
170 
171 
172 /**	Buffer to construct/convert values for database entries.
173 */
174 static	char		vb[sizeof(inbuf)];
175 
176 
177 /**	Options used by the program.
178 */
179 static	dk4_option_t	options[] = {
180 
181   /*	Debug mode.
182   */
183   { { dkT('d'),	dkT("debug"),	DK4_OPT_ARG_NONE },	{ NULL },	0 },
184 
185   /*	Configuration file.
186   */
187   { { dkT('c'),	dkT("config"),	DK4_OPT_ARG_STRING },	{ NULL },	0 }
188 };
189 
190 
191 
192 /**	Default configuration file name.
193 */
194 static	const char	def_conf_file_name[] = {
195   DK4_INST_DIR_ETC "/printqd/printqd.conf"
196 };
197 
198 
199 
200 /**	Default socket file name.
201 */
202 static	const char	def_sock_file_name[] = {
203   DK4_INST_DIR_RUNSTATE "/printqd/printqd.sock"
204 };
205 
206 
207 
208 /**	Default database file name.
209 */
210 static	const char	def_db_file_name[] = {
211 #if DK4_HAVE_DB_H
212   "bdb::"	DK4_INST_DIR_VAR	"/lib/printqd/printqd.db"
213 #else
214 #if DK4_HAVE_NDBM_H
215   "ndbm::"	DK4_INST_DIR_VAR	"/lib/printqd/printqd"
216 #else
217   "mem::"	DK4_INST_DIR_VAR	"/lib/printqd/printqd.db"
218 #endif
219 #endif
220 };
221 
222 
223 
224 /**	Default log file name.
225 */
226 static	const char	def_log_file_name[] = {
227   DK4_INST_DIR_VAR "/log/printqd/printqd.log"
228 };
229 
230 
231 
232 
233 /**	PID file name.
234 */
235 static	const char	pid_file_name[] = {
236   DK4_INST_DIR_SYSTEMD_RUN "/printqd/printqd.pid"
237 };
238 
239 
240 
241 /**	Constant texts used by the module.
242 */
243 static	const char * const	printqd_kw[] = {
244 /* 0 */
245 "printqd",
246 
247 /* 1 */
248 "r",
249 
250 /* 2 */
251 "*",
252 
253 /* 3 */
254 "unlimited",
255 
256 /* 4 */
257 "denied",
258 
259 /* 5 */
260 "\n",
261 
262 /* 6 */
263 "# ",
264 
265 /* 7 */
266 ": ",
267 
268 /* 8 */
269 ":",
270 
271 /* 9 */
272 "ERROR: ",
273 
274 /* 10 */
275 "a",
276 
277 /* 11 */
278 "",
279 
280 /* 12 */
281 "Not an integer number:\n\"",
282 
283 /* 13 */
284 "\", reading stoppend at \"",
285 
286 /* 14 */
287 "\"!",
288 
289 /* 15 */
290 "Positive number required!",
291 
292 /* 16 */
293 "Not a size specification:\n\"",
294 
295 /* 17 */
296 "\", reading stopped at \"",
297 
298 /* 18 */
299 "\"!",
300 
301 /* 19 */
302 "Not a 16 bit unsigned number:\n\"",
303 
304 /* 20 */
305 "\", reading stopped at \"",
306 
307 /* 21 */
308 "\"!",
309 
310 /* 22 */
311 "Port number must not be 0!",
312 
313 /* 23 */
314 "Too much text, unexpected:\n\"",
315 
316 /* 24 */
317 "\"!",
318 
319 /* 25 */
320 "Not a peer definition:\n\"",
321 
322 /* 26 */
323 "\"!",
324 
325 /* 27 */
326 "Not enough memory (allocation failed)!",
327 
328 /* 28 */
329 "Not an unsigned number:\n\"",
330 
331 /* 29 */
332 "\", reading stopped at \"",
333 
334 /* 30 */
335 "\"!",
336 
337 /* 31 */
338 "Missing limit text!",
339 
340 /* 32 */
341 "Limit redefinition for: \"",
342 
343 /* 33 */
344 "\"!",
345 
346 /* 34 */
347 "Redefinition of default limit!",
348 
349 /* 35 */
350 "Redefinition of deny action!",
351 
352 /* 36 */
353 "Printer already exists: \"",
354 
355 /* 37 */
356 "\"!",
357 
358 /* 38 */
359 "Printer alias already exists: \"",
360 
361 /* 39 */
362 "\"!",
363 
364 /* 40 */
365 "Class not found: \"",
366 
367 /* 41 */
368 "\"!",
369 
370 /* 42 */
371 "Redefinition of printers class!",
372 
373 /* 43 */
374 "Class already exists: \"",
375 
376 /* 44 */
377 "\"!",
378 
379 /* 45 */
380 "Missing class name!",
381 
382 /* 46 */
383 "Printer or alias already exists: \"",
384 
385 /* 47 */
386 "\"!",
387 
388 /* 48 */
389 "Missing printer name!",
390 
391 /* 49 */
392 "Illegal section type name: \"",
393 
394 /* 50 */
395 "\"!",
396 
397 /* 51 */
398 "Missing section type!",
399 
400 /* 52 */
401 "Redefinition of user ID to run as!",
402 
403 /* 53 */
404 "User not found: \"",
405 
406 /* 54 */
407 "\"!",
408 
409 /* 55 */
410 "Only allowed in options section!",
411 
412 /* 56 */
413 "Redefinition of group ID to run as!",
414 
415 /* 57 */
416 "Group not found: \"",
417 
418 /* 58 */
419 "\"!",
420 
421 /* 59 */
422 "Redefinition of database name!",
423 
424 /* 60 */
425 "Redefinition of socket name!",
426 
427 /* 61 */
428 "Only allowed in class section!",
429 
430 /* 62 */
431 "Only allowed in printer section!",
432 
433 /* 63 */
434 "Redefinition of log file name!",
435 
436 /* 64 */
437 "Value missing!",
438 
439 /* 65 */
440 "Failed to open file for reading!",
441 
442 /* 66 */
443 "User to run as was changed!",
444 
445 /* 67 */
446 "Group to run as was changed!",
447 
448 /* 68 */
449 "Failed to install signal handlers!",
450 
451 /* 69 */
452 "Failed to restore signal handlers!",
453 
454 /* 70 */
455 ": ERROR: Failed to create new process!\n",
456 
457 /* 71 */
458 "Failed to create new process!",
459 
460 /* 72 */
461 "Service start prevented by errors!",
462 
463 /* 73 */
464 "Daemon starting.",
465 
466 /* 74 */
467 "Daemon exited.",
468 
469 /* 75 */
470 "Entering service mode.",
471 
472 /* 76 */
473 "Exiting service mode.",
474 
475 /* 77 */
476 "Exiting service mode for reconfiguration.",
477 
478 /* 78 */
479 "Exited service mode.",
480 
481 /* 79 */
482 "o:test",
483 
484 /* 80 */
485 "ACCEPT",
486 
487 /* 81 */
488 "REMOVE",
489 
490 /* 82 */
491 "HOLD",
492 
493 /* 83 */
494 "0 0 0 0",
495 
496 /* 84 */
497 "-1",
498 
499 /* 85 */
500 " ",
501 
502 /* 86 */
503 "<- ",
504 
505 /* 87 */
506 "-> ",
507 
508 /* 88 */
509 "p:",
510 
511 /* 89 */
512 "a:",
513 
514 /* 90 */
515 "j:",
516 
517 /* 91 */
518 "No class configured for printer: \"",
519 
520 /* 92 */
521 "\"!",
522 
523 /* 93 */
524 "Warning: No default limit configured for class: \"",
525 
526 /* 94 */
527 "\"!",
528 
529 /* 95 */
530 "Failed to create directory hierarchy for log file:\n\"",
531 
532 /* 96 */
533 "\"!",
534 
535 /* 97 */
536 "Failed to create directory hierarchy for database:\n\"",
537 
538 /* 98 */
539 "\"!",
540 
541 /* 99 */
542 "Failed to create directory hierarchy for socket:\n\"",
543 
544 /* 100 */
545 "\"!",
546 
547 /* 101 */
548 "Failed to listen on local socket:\n\"",
549 
550 /* 102 */
551 "\"!",
552 
553 /* 103 */
554 "Failed to create TCP listener socket set!",
555 
556 /* 104 */
557 "Failed to create UDP socket set!",
558 
559 /* 105 */
560 "Failed to open database:\n\"",
561 
562 /* 106 */
563 "\"!",
564 
565 /* 107 */
566 "Failed to write initial entry to database!",
567 
568 /* 108 */
569 "Failed to synchronize database to disk!",
570 
571 /* 109 */
572 "Failed to change log file ownership!",
573 
574 /* 110 */
575 "Failed to change log file permissions!",
576 
577 /* 111 */
578 "Failed to change database ownership and/or permissions!",
579 
580 /* 112 */
581 "Failed to change local socket ownership!",
582 
583 /* 113 */
584 "Failed to change local socket permissions!",
585 
586 /* 114 */
587 "Failed to switch group!",
588 
589 /* 115 */
590 "Failed to switch user!",
591 
592 /* 116 */
593 "Response text too long (bug)!",
594 
595 /* 117 */
596 "Failed to write database entry!",
597 
598 /* 118 */
599 "Failed to delete database entry!",
600 
601 /* 119 */
602 "The select() function failed!",
603 
604 /* 120 */
605 "Insufficient memory!",
606 
607 /* 121 */
608 "Failed to synchronize database to disk!",
609 
610 /* 122 */
611 "DB SET \"",
612 
613 /* 123 */
614 "\"=\"",
615 
616 /* 124 */
617 "\" ok.",
618 
619 /* 125 */
620 "\" FAILED (invalid arguments)!",
621 
622 /* 126 */
623 "\" FAILED (syntax)!",
624 
625 /* 127 */
626 "\" FAILED (numeric overflow in size calculation)!",
627 
628 /* 128 */
629 "\" FAILED (unsupported db backend)!",
630 
631 /* 129 */
632 "\" FAILED (no such entry)!",
633 
634 /* 130 */
635 "\" FAILED (insufficient memory)!",
636 
637 /* 131 */
638 "\" FAILED (can not write)!",
639 
640 /* 132 */
641 "\" FAILED (reason unknown)!",
642 
643 /* 133 */
644 "DB GET \"",
645 
646 /* 134 */
647 "\" FAILED (buffer too small)!",
648 
649 /* 135 */
650 "DB DEL \"",
651 
652 /* 136 */
653 "DB SYN ok.",
654 
655 /* 137 */
656 "DB SYN FAILED (invalid arguments)!",
657 
658 /* 138 */
659 "DB SYN FAILED (unsupported db backend)!",
660 
661 /* 139 */
662 "DB SYN FAILED (syntax)!",
663 
664 /* 140 */
665 "DB SYN FAILED (security checks for file failed)!",
666 
667 /* 141 */
668 "DB SYN FAILED (can not open file for writing)!",
669 
670 /* 142 */
671 "DB SYN FAILED (can not write)!",
672 
673 /* 143 */
674 "DB SYN FAILED (can not close file)!",
675 
676 /* 144 */
677 "DB SYN FAILED (unknown reason)!",
678 
679 /* 145 */
680 "(l=",
681 
682 /* 146 */
683 ",u=",
684 
685 /* 147 */
686 ",a=",
687 
688 /* 148 */
689 ") + u=",
690 
691 /* 149 */
692 " => (l=",
693 
694 /* 150 */
695 ")",
696 
697 /* 151 */
698 "unlimited",
699 
700 /* 152 */
701 "p",
702 
703 /* 153 */
704 ") + a=",
705 
706 /* 154 */
707 "Illegal log feature name: \"",
708 
709 /* 155 */
710 "\"!",
711 
712 /* 156 */
713 "Failed to update account data for user \"",
714 
715 /* 157 */
716 "\" in class \"",
717 
718 /* 158 */
719 "\"!",
720 
721 /* 159 */
722 "Missing class name in reset request!",
723 
724 /* 160 */
725 "Missing user name in reset request!",
726 
727 /* 161 */
728 "Failed to update account data for user \"",
729 
730 /* 162 */
731 "\" in class \"",
732 
733 /* 163 */
734 "\"!",
735 
736 /* 164 */
737 "No such class: \"",
738 
739 /* 165 */
740 "\"!",
741 
742 /* 166 */
743 "Not a number: \"",
744 
745 /* 167 */
746 "\"!",
747 
748 /* 168 */
749 "Illegal sub-command: \"",
750 
751 /* 169 */
752 "\"!",
753 
754 /* 170 */
755 "Logging to file \"",
756 
757 /* 171 */
758 "\" failed!",
759 
760 /* 172 */
761 "Database modification failed!",
762 
763 /* 173 */
764 "Database synchronization to disk failed!",
765 
766 /* 174 */
767 "Failed to change ownership on database file:\n\"",
768 
769 /* 175 */
770 "\"!",
771 
772 /* 176 */
773 "Failed to change permissions on database file:\n\"",
774 
775 /* 177 */
776 "\"!",
777 
778 /* 178 */
779 "\" (name too long)!",
780 
781 /* 179 */
782 "\" (file exists, but no socket)!",
783 
784 /* 180 */
785 "\" (failed to remove old socket)!",
786 
787 /* 181 */
788 "\" (failed to create socket: ",
789 
790 /* 182 */
791 ")!",
792 
793 /* 183 */
794 "\" (failed to bind local ",
795 
796 /* 184 */
797 "\" (failed to listen ",
798 
799 /* 185 */
800 "\" (failed to change ownership)!",
801 
802 /* 186 */
803 "\" (failed to change permissions)!",
804 
805 /* 187 */
806 "Daemon exited due to errors, see log file!",
807 
808 /* 188 */
809 "Failed to create TCP socket set (math overflow)!",
810 
811 /* 189 */
812 "Failed to create TCP socket set (memory)!",
813 
814 /* 190 */
815 "Failed to create TCP socket set (socket(): ",
816 
817 /* 191 */
818 ")!",
819 
820 /* 192 */
821 "Failed to create TCP socket set (bind(): ",
822 
823 /* 193 */
824 "Failed to create TCP socket set (listen(): ",
825 
826 /* 194 */
827 "Failed to create TCP socket set (getaddrinfo(): ",
828 
829 /* 195 */
830 "Failed to create UDP socket set (math overflow)!",
831 
832 /* 196 */
833 "Failed to create UDP socket set (memory)!",
834 
835 /* 197 */
836 "Failed to create UDP socket set (socket(): ",
837 
838 /* 198 */
839 ")!",
840 
841 /* 199 */
842 "Failed to create UDP socket set (bind(): ",
843 
844 /* 200 */
845 "Failed to create UDP socket set (listen(): ",
846 
847 /* 201 */
848 "Failed to create UDP socket set (getaddrinfo(): ",
849 
850 /* 202 */
851 "\" (backend type not supported)!",
852 
853 /* 203 */
854 "\" (overflow in size calculation)!",
855 
856 /* 204 */
857 "\" (insufficient memory)!",
858 
859 /* 205 */
860 "\"\n(not a regular file / not a database / key or value size too large)!",
861 
862 /* 206 */
863 "\" (denied by security check)!",
864 
865 /* 207 */
866 "\" (failed to open for reading)!",
867 
868 /* 208 */
869 "\" (failed to write to file)!",
870 
871 /* 209 */
872 "\" (failed to synchronize to disk)!",
873 
874 /* 210 */
875 "Failed to write initial entry to database (key or value too long)!",
876 
877 /* 211 */
878 "Failed to write initial entry to database (unsupported backend type)!",
879 
880 /* 212 */
881 "Failed to write initial entry to database (insufficient memory)!",
882 
883 /* 213 */
884 "Failed to write initial entry to database (can not open file for writing)!",
885 
886 /* 214 */
887 "Failed to write initial entry to database (can not write to file)!",
888 
889 /* 215 */
890 "Failed to write initial entry to database (can not synchronize to disk)!",
891 
892 /* 216 */
893 "Failed to write initial entry to database (denied by security check)!",
894 
895 /* 217 */
896 "Failed to change PID file ownership!",
897 
898 /* 218 */
899 "Failed to change PID file permissions!",
900 
901 NULL
902 
903 };
904 
905 
906 
907 /**	Choices for deny action.
908 */
909 static	const char * const	deny_action_names[] = {
910 /* 0 */
911 "remove",
912 
913 /* 1 */
914 "hold",
915 
916 NULL
917 
918 };
919 
920 
921 
922 /**	Section names in configuration files.
923 */
924 static	const char * const	config_section_names[] = {
925 /* 0 */
926 "options",
927 
928 /* 1 */
929 "class",
930 
931 /* 2 */
932 "printer",
933 
934 NULL
935 
936 };
937 
938 
939 
940 /**	Option names in configuration file.
941 */
942 static	const char * const	config_option_names[] = {
943 /* 0 */
944 "run as user",
945 
946 /* 1 */
947 "run as group",
948 
949 /* 2 */
950 "database",
951 
952 /* 3 */
953 "local socket",
954 
955 /* 4 */
956 "local socket backlog",
957 
958 /* 5 */
959 "max local connections",
960 
961 /* 6 */
962 "udp port",
963 
964 /* 7 */
965 "tcp port",
966 
967 /* 8 */
968 "tcp port backlog",
969 
970 /* 9 */
971 "max tcp connections",
972 
973 /* 10 */
974 "info allow",
975 
976 /* 11 */
977 "data allow",
978 
979 /* 12 */
980 "admin allow",
981 
982 /* 13 */
983 "user limit",
984 
985 /* 14 */
986 "group limit",
987 
988 /* 15 */
989 "default limit",
990 
991 /* 16 */
992 "deny action",
993 
994 /* 17 */
995 "alias",
996 
997 /* 18 */
998 "class",
999 
1000 /* 19 */
1001 "log file",
1002 
1003 /* 20 */
1004 "log features",
1005 
1006 /* 21 */
1007 "local socket owner",
1008 
1009 /* 22 */
1010 "local socket group",
1011 
1012 NULL
1013 
1014 };
1015 
1016 
1017 
1018 /**	Command names in the printqd protocol.
1019 */
1020 static	const char * const	pqd_command_names[] = {
1021 /* 0 */
1022 "jobstart",
1023 
1024 /* 1 */
1025 "jobend",
1026 
1027 /* 2 */
1028 "start",
1029 
1030 /* 3 */
1031 "end",
1032 
1033 /* 4 */
1034 "filestart",
1035 
1036 /* 5 */
1037 "fileend",
1038 
1039 /* 6 */
1040 "info",
1041 
1042 /* 7 */
1043 "acct-check",
1044 
1045 /* 8 */
1046 "acct-start",
1047 
1048 /* 9 */
1049 "acct-end",
1050 
1051 /* 10 */
1052 "acct-charge",
1053 
1054 /* 11 */
1055 "control",
1056 
1057 NULL
1058 
1059 };
1060 
1061 
1062 
1063 /**	Sub-commands of control.
1064 */
1065 static	const char * const	control_sub_cmds[] = {
1066 /* 0 */
1067 "r$eset",
1068 
1069 /* 1 */
1070 "a$dd",
1071 
1072 /* 2 */
1073 "d$atabase-cleanup",
1074 
1075 NULL
1076 
1077 };
1078 
1079 
1080 
1081 /**	Argument names for control requests.
1082 */
1083 static	const char * const	control_arg_names[] = {
1084 /* 0 */
1085 "c$lass",
1086 
1087 /* 1 */
1088 "u$ser",
1089 
1090 /* 2 */
1091 "p$ages",
1092 
1093 NULL
1094 
1095 };
1096 
1097 
1098 
1099 /**	Log feature names.
1100 */
1101 static const char * const	log_feature_names[] = {
1102 /* 0 */
1103 "db",
1104 
1105 /* 1 */
1106 "info",
1107 
1108 /* 2 */
1109 "all",
1110 
1111 /* 3 */
1112 "*",
1113 
1114 /* 4 */
1115 "none",
1116 
1117 /* 5 */
1118 "-",
1119 
1120 NULL
1121 
1122 };
1123 
1124 
1125 
1126 static	const char * const	db_type_names[] = {
1127 /* 0 */
1128 "p",
1129 
1130 /* 1 */
1131 "a",
1132 
1133 /* 2 */
1134 "j",
1135 
1136 NULL
1137 
1138 };
1139 
1140 
1141 /**	Daemon configuration.
1142 */
1143 static	pqd_conf_t	 conf;
1144 
1145 
1146 /**	Daemon tool function structure.
1147 */
1148 static	dk4dmt_t	dmt;
1149 
1150 
1151 /**	Connections over local socket, stores pqd_l_conn_t.
1152 	Not NULL in service (service is not run if allocation fails).
1153 */
1154 static	dk4_sto_t	*s_c_unix	= NULL;
1155 
1156 
1157 
1158 /**	Iterator through s_c_unix container.
1159 	Not NULL in service (service is not run if allocation failes).
1160 */
1161 static	dk4_sto_it_t	*i_c_unix	= NULL;
1162 
1163 
1164 
1165 /**	Container for TCP connections, stores pqd_n_conn_t.
1166 	Not NULL in service (service is not run if allocation fails).
1167 */
1168 static	dk4_sto_t	*s_c_tcp	= NULL;
1169 
1170 
1171 
1172 /**	Iterator through s_c_tcp container.
1173 	Not NULL in service (service is not run if allocation fails).
1174 */
1175 static	dk4_sto_it_t	*i_c_tcp	= NULL;
1176 
1177 
1178 
1179 /**	To accept TCP connections.
1180 	May be NULL in service, if no TCP port number is conigured.
1181 */
1182 static	dk4_socket_set_t	*ss_tcp	= NULL;
1183 
1184 
1185 
1186 /**	For info requests.
1187 	May be NULL in service, if no UDP port number is configured.
1188 */
1189 static	dk4_socket_set_t	*ss_udp	= NULL;
1190 
1191 
1192 
1193 /**	Database.
1194 	Not NULL in service (service is not run if allocation fails).
1195 */
1196 static	dk4_dbi_t		*db	= NULL;
1197 
1198 
1199 
1200 /**	Number of options in the options array.
1201 */
1202 static const size_t	szoptions =	sizeof(options)/sizeof(dk4_option_t);
1203 
1204 
1205 
1206 /**	Current connections on local socket.
1207 */
1208 static	size_t		 con_loc	= 0;
1209 
1210 
1211 
1212 /**	Current connections on TCP socket.
1213 */
1214 static	size_t		 con_tcp	= 0;
1215 
1216 
1217 
1218 /**	Timestamp of previous log message.
1219 */
1220 static	dk4_time_t	 prev_log_time	= (dk4_time_t)0UL;
1221 
1222 
1223 
1224 /**	Listen for incoming UNIX connection requests.
1225 	Always set in service, service exits when failed to
1226 	bind local address.
1227 */
1228 static	dk4_socket_t	 so_unix	= INVALID_SOCKET;
1229 
1230 
1231 
1232 /**	Program exit code, either EXIT_FAILURE or EXIT_SUCCESS.
1233 */
1234 static	int		 exval	= EXIT_FAILURE;
1235 
1236 
1237 
1238 /**	Flag: can continue outer (and inner) loop, 1=yes, 0=no, -1=abort.
1239 */
1240 static	int		 ccouter	= 1;
1241 
1242 
1243 
1244 /**	Flag: can continue inner loop, 1=yes, 0=no, -1=abort.
1245 */
1246 static	int		 ccinner	= 1;
1247 
1248 
1249 
1250 /**	Flag: User and group switching was already done.
1251 */
1252 static	int		 user_switched	= 0;
1253 
1254 
1255 
1256 /**	Syslog feature to use.
1257 */
1258 static	int		syslogf	= LOG_LPR;
1259 
1260 
1261 /**	Flag: Modified since last synchronization.
1262 */
1263 static	int		db_modified	= 0;
1264 
1265 
1266 /**	Flag: Debug mode, process runs in foreground and logs to stderr.
1267 */
1268 static	int		 debug	= 0;
1269 
1270 
1271 /**	Flag: Previous attempt to log to file failed.
1272 */
1273 static	int	 	prev_filelog_failed	= 0;
1274 
1275 
1276 /**	Flag: Previous database modification failed.
1277 */
1278 static	int		prev_dbmod_failed	= 0;
1279 
1280 
1281 /**	Flag: Previous database synchronization to disk failed.
1282 */
1283 static	int		prev_dbsync_failed	= 0;
1284 
1285 
1286 /**	UID in previous pass.
1287 */
1288 static	uid_t		 prev_uid	= (uid_t)0;
1289 
1290 
1291 
1292 /**	GID in previous pass.
1293 */
1294 static	gid_t		 prev_gid	= (gid_t)0;
1295 
1296 
1297 
1298 #ifdef SIGPIPE
1299 /**	Indicator: SIGPIPE signal received.
1300 */
1301 static
1302 DK4_VOLATILE
1303 dk4_sig_atomic_t	sig_had_pipe	=	0;
1304 #endif
1305 
1306 #ifdef SIGHUP
1307 /**	Indicator: SIGHUP signal received.
1308 */
1309 static
1310 DK4_VOLATILE
1311 dk4_sig_atomic_t	sig_had_hup	=	0;
1312 #endif
1313 
1314 
1315 /**	Indicator: SIGINT signal received.
1316 */
1317 static
1318 DK4_VOLATILE
1319 dk4_sig_atomic_t	sig_had_int	=	0;
1320 
1321 
1322 /**	Indicator: SIGTERM signal received.
1323 */
1324 static
1325 DK4_VOLATILE
1326 dk4_sig_atomic_t	sig_had_term	=	0;
1327 
1328 
1329 
1330 /**	Pass pointer through.
1331 	Use of this function is recommended by CERT C coding standard
1332 	to avoid optimizing out.
1333 	@param	ptr	Pointer to pass through.
1334 	@return	The ptr argument.
1335 */
1336 static
1337 DK4_VOLATILE
1338 dk4_sig_atomic_t *
sig_pass_pointer(DK4_VOLATILE dk4_sig_atomic_t * ptr)1339 sig_pass_pointer(DK4_VOLATILE dk4_sig_atomic_t *ptr)
1340 {
1341   return ptr;
1342 }
1343 
1344 
1345 #ifdef SIGPIPE
1346 /**	Handler for SIGPIPE signal.
1347 	@param	signo	Signal number (always SIGPIPE, ignored).
1348 */
1349 static
1350 void
sig_handler_pipe(int DK4_ARG_UNUSED (signo))1351 sig_handler_pipe(int DK4_ARG_UNUSED(signo) )
1352 {
1353   DK4_UNUSED_ARG(signo)
1354   *sig_pass_pointer(&sig_had_pipe) = 1;
1355 }
1356 #endif
1357 
1358 
1359 
1360 #ifdef SIGHUP
1361 /**	Handler for SIGHUP signal.
1362 	@param	signo	Signal number (always SIGHUP, ignored).
1363 */
1364 static
1365 void
sig_handler_hup(int DK4_ARG_UNUSED (signo))1366 sig_handler_hup(int DK4_ARG_UNUSED(signo) )
1367 {
1368   DK4_UNUSED_ARG(signo)
1369   *sig_pass_pointer(&sig_had_hup) = 1;
1370 }
1371 #endif
1372 
1373 
1374 
1375 /**	Handler for SIGINT signal.
1376 	@param	signo	Signal number (always SIGINT, ignored).
1377 */
1378 static
1379 void
sig_handler_int(int DK4_ARG_UNUSED (signo))1380 sig_handler_int(int DK4_ARG_UNUSED(signo) )
1381 {
1382   DK4_UNUSED_ARG(signo)
1383   *sig_pass_pointer(&sig_had_int) = 1;
1384 }
1385 
1386 
1387 
1388 /**	Handler for SIGTERM signal.
1389 	@param	signo	Signal number (always SIGTERM, ignored).
1390 */
1391 static
1392 void
sig_handler_term(int DK4_ARG_UNUSED (signo))1393 sig_handler_term(int DK4_ARG_UNUSED(signo) )
1394 {
1395   DK4_UNUSED_ARG(signo)
1396   *sig_pass_pointer(&sig_had_term) = 1;
1397 }
1398 
1399 
1400 /**	Read value from volatile atomic type.
1401 	This function is necessary as some compilers mis-optimize
1402 	direct access to volatile variables (at least if you believe
1403 	one of the coding standards).
1404 	@param	ap	Pointer to volatile atomic variable.
1405 	@return	Contents of the variable.
1406 */
1407 static
1408 dk4_sig_atomic_t
sig_read_atomic(DK4_VOLATILE dk4_sig_atomic_t * ap)1409 sig_read_atomic(DK4_VOLATILE dk4_sig_atomic_t *ap)
1410 {
1411   return (*ap);
1412 }
1413 
1414 
1415 
1416 /**	Check whether we can continue or must abort due to signal.
1417 	@param	dopipe	Flag: Check for SIGPIPE too.
1418 	@return	1 if we can continue, 0 otherwise.
1419 */
1420 static
1421 int
can_continue(int dohup,int dopipe)1422 can_continue(int dohup, int dopipe)
1423 {
1424   int		 back	= 1;
1425 
1426   if (0 != sig_read_atomic(&sig_had_term)) { back = 0; }
1427   if (0 != sig_read_atomic(&sig_had_int))  { back = 0; }
1428 #ifdef SIGHUP
1429   if (0 != dohup) {
1430     if (0 != sig_read_atomic(&sig_had_hup)) { back = 0; }
1431     if (1 > ccinner) { back = 0; }
1432   }
1433 #endif
1434 #ifdef SIGPIPE
1435   if (0 != dopipe) {
1436     if (0 != sig_read_atomic(&sig_had_pipe)) { back = 0; }
1437   }
1438 #endif
1439   if (1 > ccouter) { back = 0; }
1440 
1441   return back;
1442 }
1443 
1444 
1445 
1446 /**	Log a multi part message to file, either stderr or log file.
1447 	@param	fipo		Output file.
1448 	@param	timebuf		Text buffer containing timestamp.
1449 	@param	sourcefile	Source file name.
1450 	@param	linebuf		Text buffer containing source file line number.
1451 	@param	error		Flag: Insert keyword "ERROR:"
1452 	@param	shtime		Flag: Show timestamp from buffer.
1453 	@param	shline		Flag: Show line number from buffer.
1454 	@param	msgs		Array containing the message parts.
1455 	@param	szmsgs		Number of elements in msgs array.
1456 
1457 */
1458 static
1459 void
log_file_multipart_message(FILE * fipo,const char * timebuf,const char * sourcefile,const char * linebuf,int error,int shtime,int shline,const char * const * msgs,size_t szmsgs)1460 log_file_multipart_message(
1461   FILE			*fipo,
1462   const char		*timebuf,
1463   const char		*sourcefile,
1464   const char		*linebuf,
1465   int			 error,
1466   int			 shtime,
1467   int			 shline,
1468   const char * const	*msgs,
1469   size_t		 szmsgs
1470 )
1471 {
1472   size_t	i;
1473 
1474   if (0 != shtime) {
1475     fputs(printqd_kw[6], fipo);
1476     fputs(timebuf, fipo);
1477     fputs(printqd_kw[5], fipo);
1478   }
1479   if (NULL != sourcefile) {
1480     fputs(sourcefile, fipo);
1481     if (0 != shline) {
1482       fputs(printqd_kw[8], fipo);
1483 	fputs(linebuf, fipo);
1484     }
1485     fputs(printqd_kw[7], fipo);
1486   }
1487   if (0 != error) {
1488     fputs(printqd_kw[9], fipo);
1489   }
1490   for (i = 0; i < szmsgs; i++) {
1491     if (NULL != msgs[i]) {
1492       fputs(msgs[i], fipo);
1493     }
1494   }
1495   fputs(printqd_kw[5], fipo);
1496   fflush(fipo);
1497 
1498 }
1499 
1500 
1501 
1502 /**	Write a log message consisting of multiple parts.
1503 	@param	sourcefile	Configuration file name.
1504 	@param	sourceline	Configuration file line number.
1505 	@param	sll		Syslog level.
1506 	@param	msgs		Array containing the message parts.
1507 	@param	szmsgs		Number of elements in msgs array.
1508 */
1509 static
1510 void
log_multipart_message(const char * sourcefile,unsigned long sourceline,int sll,int error,char const * const * msgs,size_t szmsgs)1511 log_multipart_message(
1512   const char		*sourcefile,
1513   unsigned long		 sourceline,
1514   int			 sll,
1515   int			 error,
1516   char const * const	*msgs,
1517   size_t		 szmsgs
1518 )
1519 {
1520   char		 timebuf[64];
1521   char		 linebuf[64];
1522   FILE		*fipo;
1523   const char	*lfn;
1524   dk4_time_t	 current;
1525   int		 stests	= DK4_FOPEN_SC_PRIVILEGED;
1526   int		 shtime	= 0;
1527   int		 shline	= 0;
1528 
1529   /*	Check whether to prepend a timestamp line.
1530   */
1531   dk4time_get(&current);
1532   if (current != prev_log_time) {
1533     prev_log_time = current;
1534     if (0 != dk4time_as_text_c8(timebuf, sizeof(timebuf), &current, NULL)) {
1535       shtime = 1;
1536     }
1537   }
1538 
1539   /*	Check whether to prepend source file name and line number.
1540   */
1541   if ((NULL != sourcefile) && ((dk4_um_t)0UL != sourceline)) {
1542     shline = dk4ma_write_c8_decimal_unsigned(
1543       linebuf, sizeof(linebuf), (dk4_um_t)sourceline, 0, NULL
1544     );
1545   }
1546 
1547   /*	Output to log file.
1548   */
1549   lfn = conf.lname;
1550   if (NULL == lfn) { lfn = def_log_file_name; }
1551   fipo = dk4fopen_c8(lfn, printqd_kw[10], stests, NULL);
1552   if (NULL != fipo) {
1553     prev_filelog_failed = 0;
1554     log_file_multipart_message(
1555       fipo, timebuf, sourcefile, linebuf, error, shtime, shline, msgs, szmsgs
1556     );
1557     fclose(fipo);
1558   } else {
1559 #if DK4_HAVE_SYSLOG
1560     if (0 == prev_filelog_failed) {
1561       openlog(printqd_kw[0], LOG_PID, syslogf);
1562       syslog(LOG_ERR, "%s%s%s", printqd_kw[170], lfn, printqd_kw[171]);
1563       closelog();
1564     }
1565 #endif
1566     prev_filelog_failed = 1;
1567   }
1568 
1569   /*	Output to stderr when debugging.
1570   */
1571   if (0 != debug) {
1572     log_file_multipart_message(
1573       stderr, timebuf, sourcefile, linebuf, error, shtime, shline, msgs, szmsgs
1574     );
1575   }
1576 
1577   /*	Output to syslog.
1578   */
1579   if (LOG_EMERG != sll) {
1580 #if DK4_HAVE_SYSLOG
1581     openlog(printqd_kw[0], LOG_PID, syslogf);
1582     if (1 < szmsgs) {
1583       if (2 < szmsgs) {
1584         if (3 < szmsgs) {
1585 	  if (4 < szmsgs) {
1586 	    if (5 < szmsgs) {
1587 	      if (6 < szmsgs) {
1588 	        if (7 < szmsgs) {
1589 		  if (8 < szmsgs) {
1590                     syslog(
1591                       sll, "%s%s%s%s%s%s%s%s%s",
1592 	              ((NULL != msgs[0]) ? (msgs[0]) : (printqd_kw[11])),
1593 	              ((NULL != msgs[1]) ? (msgs[1]) : (printqd_kw[11])),
1594 	              ((NULL != msgs[2]) ? (msgs[2]) : (printqd_kw[11])),
1595 	              ((NULL != msgs[3]) ? (msgs[3]) : (printqd_kw[11])),
1596 		      ((NULL != msgs[4]) ? (msgs[4]) : (printqd_kw[11])),
1597 		      ((NULL != msgs[5]) ? (msgs[5]) : (printqd_kw[11])),
1598 		      ((NULL != msgs[6]) ? (msgs[6]) : (printqd_kw[11])),
1599 		      ((NULL != msgs[7]) ? (msgs[7]) : (printqd_kw[11])),
1600 		      ((NULL != msgs[8]) ? (msgs[8]) : (printqd_kw[11]))
1601                     );
1602 		  } else {
1603                     syslog(
1604                       sll, "%s%s%s%s%s%s%s%s",
1605 	              ((NULL != msgs[0]) ? (msgs[0]) : (printqd_kw[11])),
1606 	              ((NULL != msgs[1]) ? (msgs[1]) : (printqd_kw[11])),
1607 	              ((NULL != msgs[2]) ? (msgs[2]) : (printqd_kw[11])),
1608 	              ((NULL != msgs[3]) ? (msgs[3]) : (printqd_kw[11])),
1609 		      ((NULL != msgs[4]) ? (msgs[4]) : (printqd_kw[11])),
1610 		      ((NULL != msgs[5]) ? (msgs[5]) : (printqd_kw[11])),
1611 		      ((NULL != msgs[6]) ? (msgs[6]) : (printqd_kw[11])),
1612 		      ((NULL != msgs[7]) ? (msgs[7]) : (printqd_kw[11]))
1613                     );
1614 		  }
1615 		} else {
1616                   syslog(
1617                     sll, "%s%s%s%s%s%s%s",
1618 	            ((NULL != msgs[0]) ? (msgs[0]) : (printqd_kw[11])),
1619 	            ((NULL != msgs[1]) ? (msgs[1]) : (printqd_kw[11])),
1620 	            ((NULL != msgs[2]) ? (msgs[2]) : (printqd_kw[11])),
1621 	            ((NULL != msgs[3]) ? (msgs[3]) : (printqd_kw[11])),
1622 		    ((NULL != msgs[4]) ? (msgs[4]) : (printqd_kw[11])),
1623 		    ((NULL != msgs[5]) ? (msgs[5]) : (printqd_kw[11])),
1624 		    ((NULL != msgs[6]) ? (msgs[6]) : (printqd_kw[11]))
1625                   );
1626 		}
1627 	      } else {
1628                 syslog(
1629                   sll, "%s%s%s%s%s%s",
1630 	          ((NULL != msgs[0]) ? (msgs[0]) : (printqd_kw[11])),
1631 	          ((NULL != msgs[1]) ? (msgs[1]) : (printqd_kw[11])),
1632 	          ((NULL != msgs[2]) ? (msgs[2]) : (printqd_kw[11])),
1633 	          ((NULL != msgs[3]) ? (msgs[3]) : (printqd_kw[11])),
1634 		  ((NULL != msgs[4]) ? (msgs[4]) : (printqd_kw[11])),
1635 		  ((NULL != msgs[5]) ? (msgs[5]) : (printqd_kw[11]))
1636                 );
1637 	      }
1638 	    } else {
1639               syslog(
1640                 sll, "%s%s%s%s%s",
1641 	        ((NULL != msgs[0]) ? (msgs[0]) : (printqd_kw[11])),
1642 	        ((NULL != msgs[1]) ? (msgs[1]) : (printqd_kw[11])),
1643 	        ((NULL != msgs[2]) ? (msgs[2]) : (printqd_kw[11])),
1644 	        ((NULL != msgs[3]) ? (msgs[3]) : (printqd_kw[11])),
1645 		((NULL != msgs[4]) ? (msgs[4]) : (printqd_kw[11]))
1646               );
1647 	    }
1648 	  } else {
1649             syslog(
1650               sll, "%s%s%s%s",
1651 	      ((NULL != msgs[0]) ? (msgs[0]) : (printqd_kw[11])),
1652 	      ((NULL != msgs[1]) ? (msgs[1]) : (printqd_kw[11])),
1653 	      ((NULL != msgs[2]) ? (msgs[2]) : (printqd_kw[11])),
1654 	      ((NULL != msgs[3]) ? (msgs[3]) : (printqd_kw[11]))
1655             );
1656 	  }
1657 	} else {
1658           syslog(
1659             sll, "%s%s%s",
1660 	    ((NULL != msgs[0]) ? (msgs[0]) : (printqd_kw[11])),
1661 	    ((NULL != msgs[1]) ? (msgs[1]) : (printqd_kw[11])),
1662 	    ((NULL != msgs[2]) ? (msgs[2]) : (printqd_kw[11]))
1663           );
1664 	}
1665       } else {
1666         syslog(
1667           sll, "%s%s",
1668 	  ((NULL != msgs[0]) ? (msgs[0]) : (printqd_kw[11])),
1669 	  ((NULL != msgs[1]) ? (msgs[1]) : (printqd_kw[11]))
1670         );
1671       }
1672     } else {
1673       syslog(
1674         sll, "%s",
1675 	((NULL != msgs[0]) ? (msgs[0]) : (printqd_kw[11]))
1676       );
1677     }
1678     closelog();
1679 #endif
1680   }
1681 
1682 }
1683 
1684 
1685 
1686 static
1687 void
log_1(const char * sourcefile,unsigned long sourceline,int sll,int error,size_t i1)1688 log_1(
1689   const char		*sourcefile,
1690   unsigned long		 sourceline,
1691   int			 sll,
1692   int			 error,
1693   size_t		 i1
1694 )
1695 {
1696   const char		*msgs[2];
1697 
1698   msgs[0] = printqd_kw[i1];
1699   msgs[1] = NULL;
1700   log_multipart_message(sourcefile, sourceline, sll, error, msgs, 1);
1701 
1702 }
1703 
1704 
1705 
1706 static
1707 void
log_3(const char * sourcefile,unsigned long sourceline,int sll,int error,size_t i1,size_t i2,const char * s1)1708 log_3(
1709   const char		*sourcefile,
1710   unsigned long		 sourceline,
1711   int			 sll,
1712   int			 error,
1713   size_t		 i1,
1714   size_t		 i2,
1715   const char		*s1
1716 )
1717 {
1718   const char		*msgs[4];
1719 
1720   msgs[0] = printqd_kw[i1];
1721   msgs[1] = s1;
1722   msgs[2] = printqd_kw[i2];
1723   msgs[3] = NULL;
1724   log_multipart_message(sourcefile, sourceline, sll, error, msgs, 3);
1725 
1726 }
1727 
1728 
1729 
1730 static
1731 void
log_5(const char * sourcefile,unsigned long sourceline,int sll,int error,size_t i1,size_t i2,size_t i3,const char * s1,const char * s2)1732 log_5(
1733   const char		*sourcefile,
1734   unsigned long		 sourceline,
1735   int			 sll,
1736   int			 error,
1737   size_t		 i1,
1738   size_t		 i2,
1739   size_t		 i3,
1740   const char		*s1,
1741   const char		*s2
1742 )
1743 {
1744   const char		*msgs[6];
1745 
1746   msgs[0] = printqd_kw[i1];
1747   msgs[1] = s1;
1748   msgs[2] = printqd_kw[i2];
1749   msgs[3] = s2;
1750   msgs[4] = printqd_kw[i3];
1751   msgs[5] = NULL;
1752   log_multipart_message(sourcefile, sourceline, sll, error, msgs, 5);
1753 
1754 }
1755 
1756 
1757 
1758 /**	Set database entry (create or modify).
1759 	@param	db	Database to modify.
1760 	@param	k	Key.
1761 	@param	v	Value.
1762 	@param	erp	Error report, may be NULL.
1763 	@return	1 on success, 0 on error.
1764 */
1765 static
1766 int
dbi_set(dk4_dbi_t * db,const char * k,const char * v,dk4_er_t * erp)1767 dbi_set(
1768   dk4_dbi_t	*db,
1769   const char	*k,
1770   const char	*v,
1771   dk4_er_t	*erp
1772 )
1773 {
1774   dk4_er_t	 er;
1775   int		 back	= 0;
1776 
1777   dk4error_init(&er);
1778   back = dk4dbi_c8_set(db, k, v, &er);
1779   dk4error_copy(erp, &er);
1780   db_modified = 1;
1781   if (0 != back) {
1782     prev_dbmod_failed = 0;
1783     if (0 != conf.ldb) {
1784       log_5(NULL, 0UL, LOG_EMERG, 0, 122, 123, 124, k, v);
1785     }
1786   } else {
1787 #if DK4_HAVE_SYSLOG
1788     if (0 == prev_dbmod_failed) {
1789       openlog(printqd_kw[0], LOG_PID, syslogf);
1790       syslog(LOG_ERR, "%s", printqd_kw[172]);
1791       closelog();
1792     }
1793 #endif
1794     prev_dbmod_failed = 1;
1795     switch (er.ec) {
1796       case DK4_E_INVALID_ARGUMENTS : {
1797 	log_5(NULL, 0UL, LOG_EMERG, 1, 122, 123, 125, k, v);
1798       } break;
1799       case DK4_E_SYNTAX : {
1800 	log_5(NULL, 0UL, LOG_EMERG, 1, 122, 123, 126, k, v);
1801       } break;
1802       case DK4_E_MATH_OVERFLOW : {
1803 	log_5(NULL, 0UL, LOG_EMERG, 1, 122, 123, 127, k, v);
1804       } break;
1805       case DK4_E_NOT_SUPPORTED : {
1806 	log_5(NULL, 0UL, LOG_EMERG, 1, 122, 123, 128, k, v);
1807       } break;
1808       case DK4_E_NOT_FOUND : {
1809 	log_5(NULL, 0UL, LOG_EMERG, 1, 122, 123, 129, k, v);
1810       } break;
1811       case DK4_E_MEMORY_ALLOCATION_FAILED : {
1812 	log_5(NULL, 0UL, LOG_EMERG, 1, 122, 123, 130, k, v);
1813       } break;
1814       case DK4_E_WRITE_FAILED : {
1815 	log_5(NULL, 0UL, LOG_EMERG, 1, 122, 123, 131, k, v);
1816       } break;
1817       default : {
1818 	log_5(NULL, 0UL, LOG_EMERG, 1, 122, 123, 132, k, v);
1819       } break;
1820     }
1821   }
1822   return back;
1823 }
1824 
1825 
1826 
1827 /**	Retrieve database entry.
1828 	@param	db	Database to retrieve data from.
1829 	@param	k	Key text.
1830 	@param	vbuf	Buffer for text value.
1831 	@param	vsz	Size of buffer.
1832 	@param	erp	Error report, may be NULL.
1833 	@return	1 on success, 0 on error.
1834 */
1835 static
1836 int
dbi_get(dk4_dbi_t * db,const char * k,char * vbuf,size_t vsz,dk4_er_t * erp)1837 dbi_get(
1838   dk4_dbi_t	*db,
1839   const char	*k,
1840   char		*vbuf,
1841   size_t	 vsz,
1842   dk4_er_t	*erp
1843 )
1844 {
1845   dk4_er_t	 er;
1846   int		 back	= 0;
1847 
1848   dk4error_init(&er);
1849   back = dk4dbi_c8_get(db, k, vbuf, vsz, &er);
1850   dk4error_copy(erp, &er);
1851   if (0 != back) {
1852     if (0 != conf.ldb) {
1853       log_5(NULL, 0UL, LOG_EMERG, 0, 133, 123, 124, k, vbuf);
1854     }
1855   } else {
1856     switch (er.ec) {
1857       case DK4_E_INVALID_ARGUMENTS : {
1858 	log_3(NULL, 0UL, LOG_EMERG, 1, 133, 125, k);
1859       } break;
1860       case DK4_E_MATH_OVERFLOW : {
1861 	log_3(NULL, 0UL, LOG_EMERG, 1, 133, 127, k);
1862       } break;
1863       case DK4_E_NOT_SUPPORTED : {
1864 	log_3(NULL, 0UL, LOG_EMERG, 1, 133, 128, k);
1865       } break;
1866       case DK4_E_NOT_FOUND : {
1867         if (0 != conf.ldb) {
1868 	  log_3(NULL, 0UL, LOG_EMERG, 1, 133, 129, k);
1869 	}
1870       } break;
1871       case DK4_E_BUFFER_TOO_SMALL : {
1872 	log_3(NULL, 0UL, LOG_EMERG, 1, 133, 134, k);
1873       } break;
1874       default : {
1875 	log_3(NULL, 0UL, LOG_EMERG, 1, 133, 132, k);
1876       } break;
1877     }
1878   }
1879   return back;
1880 }
1881 
1882 
1883 
1884 /**	Delete DB entry if it exists.
1885 	@param	db	Database to modify.
1886 	@param	k	Key.
1887 	@param	erp	Error report, may be NULL.
1888 	@return	1 on success, 0 on error.
1889 */
1890 static
1891 int
dbi_del(dk4_dbi_t * db,const char * k,dk4_er_t * erp)1892 dbi_del(
1893   dk4_dbi_t	*db,
1894   const char	*k,
1895   dk4_er_t	*erp
1896 )
1897 {
1898   dk4_er_t	 er;
1899   int		 back	= 0;
1900 
1901   dk4error_init(&er);
1902   back = dk4dbi_c8_del(db, k, &er);
1903   dk4error_copy(erp, &er);
1904   db_modified = 1;
1905   if (0 != back) {
1906     prev_dbmod_failed = 0;
1907     if (0 != conf.ldb) {
1908       log_3(NULL, 0UL, LOG_EMERG, 0, 135, 124, k);
1909     }
1910   } else {
1911     if (DK4_E_NOT_FOUND != er.ec) {
1912 #if DK4_HAVE_SYSLOG
1913       if (0 == prev_dbmod_failed) {
1914         openlog(printqd_kw[0], LOG_PID, syslogf);
1915 	syslog(LOG_ERR, "%s", printqd_kw[172]);
1916 	closelog();
1917       }
1918 #endif
1919       prev_dbmod_failed = 1;
1920     }
1921     switch (er.ec) {
1922       case DK4_E_INVALID_ARGUMENTS : {
1923 	log_3(NULL, 0UL, LOG_EMERG, 1, 135, 125, k);
1924       } break;
1925       case DK4_E_SYNTAX : {
1926 	log_3(NULL, 0UL, LOG_EMERG, 1, 135, 126, k);
1927       } break;
1928       case DK4_E_MATH_OVERFLOW : {
1929 	log_3(NULL, 0UL, LOG_EMERG, 1, 135, 127, k);
1930       } break;
1931       case DK4_E_NOT_SUPPORTED : {
1932 	log_3(NULL, 0UL, LOG_EMERG, 1, 135, 128, k);
1933       } break;
1934       case DK4_E_WRITE_FAILED : {
1935 	log_3(NULL, 0UL, LOG_EMERG, 1, 135, 131, k);
1936       } break;
1937       case DK4_E_NOT_FOUND : {
1938         if (0 != conf.ldb) {
1939 	  log_3(NULL, 0UL, LOG_EMERG, 1, 135, 129, k);
1940 	}
1941       } break;
1942       default : {
1943 	log_3(NULL, 0UL, LOG_EMERG, 1, 135, 132, k);
1944       } break;
1945     }
1946   }
1947   return back;
1948 }
1949 
1950 
1951 
1952 /**	Synchronize database modifications to disk, if any.
1953 	@param	db	Database.
1954 	@param	erp	Error report, may be NULL.
1955 	@return	1 on success, 0 on error.
1956 */
1957 static
1958 int
dbi_sync(dk4_dbi_t * db,dk4_er_t * erp)1959 dbi_sync(dk4_dbi_t *db, dk4_er_t *erp)
1960 {
1961   dk4_er_t	 er;
1962   int		 back	= 0;
1963   if (0 != db_modified) {
1964     dk4error_init(&er);
1965     back = dk4dbi_sync(db, &er);
1966     dk4error_copy(erp, &er);
1967     if (0 != back) {
1968       db_modified = 0;
1969       prev_dbsync_failed = 0;
1970       if (0 != conf.ldb) {
1971         log_1(NULL, 0UL, LOG_EMERG, 0, 136);
1972       }
1973     } else {
1974 #if DK4_HAVE_SYSLOG
1975       if (0 == prev_dbsync_failed) {
1976         openlog(printqd_kw[0], LOG_PID, syslogf);
1977 	syslog(LOG_ERR, "%s", printqd_kw[173]);
1978 	closelog();
1979       }
1980 #endif
1981       prev_dbsync_failed = 1;
1982       switch (er.ec) {
1983 	case DK4_E_INVALID_ARGUMENTS : {
1984 	  log_1(NULL, 0UL, LOG_EMERG, 1, 137);
1985 	} break;
1986 	case DK4_E_NOT_SUPPORTED : {
1987 	  log_1(NULL, 0UL, LOG_EMERG, 1, 138);
1988 	} break;
1989 	case DK4_E_SYNTAX : {
1990 	  log_1(NULL, 0UL, LOG_EMERG, 1, 139);
1991 	} break;
1992 	case DK4_E_SEC_CHECK : {
1993 	  log_1(NULL, 0UL, LOG_EMERG, 1, 140);
1994 	} break;
1995 	case DK4_E_OPEN_WRITE_FAILED : {
1996 	  log_1(NULL, 0UL, LOG_EMERG, 1, 141);
1997 	} break;
1998 	case DK4_E_WRITE_FAILED : {
1999 	  log_1(NULL, 0UL, LOG_EMERG, 1, 142);
2000 	} break;
2001 	case DK4_E_CLOSE_FAILED : {
2002 	  log_1(NULL, 0UL, LOG_EMERG, 1, 143);
2003 	} break;
2004 	default : {
2005 	  log_1(NULL, 0UL, LOG_EMERG, 1, 144);
2006 	} break;
2007       }
2008     }
2009   } else {
2010     back = 1;
2011   }
2012   return back;
2013 }
2014 
2015 
2016 
2017 /**	Compare two pqd_l_conn_t structures.
2018 	@param	l	Left object.
2019 	@param	r	Right object.
2020 	@param	cr	Comparison criteria, ignored.
2021 	@return	Comparison result.
2022 */
2023 static
2024 int
compare_pqd_l_conn_t(const void * l,const void * r,int DK4_ARG_UNUSED (cr))2025 compare_pqd_l_conn_t(const void *l, const void *r, int DK4_ARG_UNUSED(cr) )
2026 {
2027   const pqd_l_conn_t	*pl;
2028   const pqd_l_conn_t	*pr;
2029   int			 back	= 0;
2030 
2031   DK4_UNUSED_ARG(cr)
2032   if (NULL != l) {
2033     if (NULL != r) {
2034       pl = (const pqd_l_conn_t *)l;
2035       pr = (const pqd_l_conn_t *)r;
2036       if (pl->sock > pr->sock) {
2037         back = 1;
2038       } else {
2039         if (pl->sock < pr->sock) {
2040 	  back = -1;
2041 	}
2042       }
2043     } else {
2044       back = 1;
2045     }
2046   } else {
2047     if (NULL != r)  { back = -1; }
2048   }
2049 
2050   return back;
2051 }
2052 
2053 
2054 
2055 /**	Compare two pqd_n_conn_t structures.
2056 	@param	l	Left object.
2057 	@param	r	Right object.
2058 	@param	cr	Comparison criteria, ignored.
2059 	@return	Comparison result.
2060 */
2061 static
2062 int
compare_pqd_n_conn_t(const void * l,const void * r,int DK4_ARG_UNUSED (cr))2063 compare_pqd_n_conn_t(const void *l, const void *r, int DK4_ARG_UNUSED(cr) )
2064 {
2065   const pqd_n_conn_t	*pl;
2066   const pqd_n_conn_t	*pr;
2067   int			 back	= 0;
2068 
2069   DK4_UNUSED_ARG(cr)
2070   if (NULL != l) {
2071     if (NULL != r) {
2072       pl = (const pqd_n_conn_t *)l;
2073       pr = (const pqd_n_conn_t *)r;
2074       if (pl->sock > pr->sock) {
2075         back = 1;
2076       } else {
2077         if (pl->sock < pr->sock) {
2078 	  back = -1;
2079 	}
2080       }
2081     } else {
2082       back = 1;
2083     }
2084   } else {
2085     if (NULL != r)  { back = -1; }
2086   }
2087 
2088   return back;
2089 }
2090 
2091 
2092 
2093 /**	Delete a limit structure (release memory).
2094 	@param	ptr	Limit to delete.
2095 */
2096 static
2097 void
limit_delete(pqd_limit_t * ptr)2098 limit_delete(pqd_limit_t *ptr)
2099 {
2100 
2101   if (NULL != ptr) {
2102     dk4mem_release(ptr->name);
2103     ptr->limit = (dk4_um_t)0UL;
2104     dk4mem_free(ptr);
2105   }
2106 
2107 }
2108 
2109 
2110 
2111 /**	Create limit structure (allocate memory).
2112 	@param	name	User or group name.
2113 	@param	max	Maximum page number.
2114 	@return	Valid pointer on success, NULL on error.
2115 */
2116 static
2117 pqd_limit_t *
limit_new(const char * name,dk4_um_t max)2118 limit_new(const char *name, dk4_um_t max)
2119 {
2120   pqd_limit_t	*back	= NULL;
2121 
2122   if (NULL != name) {
2123     back = dk4mem_new(pqd_limit_t,1,NULL);
2124     if (NULL != back) {
2125       back->limit = max;
2126       back->name  = dk4str8_dup(name, NULL);
2127       if (NULL == back->name) {
2128         limit_delete(back);
2129 	back = NULL;
2130       }
2131     }
2132 #if TRACE_DEBUG
2133     else {
2134     }
2135 #endif
2136   }
2137   return back;
2138 }
2139 
2140 
2141 
2142 /**	Compare limit structures.
2143 	@param	l	Left object.
2144 	@param	r	Right object.
2145 	@param	cr	Comparison criteria (0=limit/limit, 1=limit/name).
2146 	@return	Comparison result.
2147 */
2148 static
2149 int
limit_compare(const void * l,const void * r,int cr)2150 limit_compare(const void *l, const void *r, int cr)
2151 {
2152   const	pqd_limit_t	*pl;
2153   const	pqd_limit_t	*pr;
2154 
2155   int		 back	= 0;
2156   if (NULL != l) {
2157     if (NULL != r) {
2158       pl = (const pqd_limit_t *)l;
2159       switch (cr) {
2160         case 1: {
2161 	  if (NULL != pl->name) {
2162 	    back = strcmp(pl->name, (const char *)r);
2163 	    if (-1 > back) { back = -1; }
2164 	    if ( 1 < back) { back =  1; }
2165 	  } else { back = -1; }
2166 	} break;
2167 	default: {
2168 	  pr = (const pqd_limit_t *)r;
2169 	  if (NULL != pl->name) {
2170 	    if (NULL != pr->name) {
2171 	      back = strcmp(pl->name, pr->name);
2172 	      if (-1 > back) { back = -1; }
2173 	      if ( 1 < back) { back =  1; }
2174 	    } else { back = 1; }
2175 	  } else {
2176 	    if (NULL != pr->name) { back = -1; }
2177 	  }
2178 	} break;
2179       }
2180     } else { back = 1; }
2181   } else {
2182     if (NULL != r) { back = -1; }
2183   }
2184   return  back;
2185 }
2186 
2187 
2188 
2189 /**	Delete all limits in a storage.
2190 	@param	it	Storage iterator.
2191 */
2192 static
2193 void
limit_all_delete(dk4_sto_it_t * it)2194 limit_all_delete(dk4_sto_it_t *it)
2195 {
2196   pqd_limit_t	*ptr;
2197 
2198 
2199   dk4sto_it_reset(it);
2200   do {
2201     ptr = (pqd_limit_t *)dk4sto_it_next(it);
2202     if (NULL != ptr) {
2203       limit_delete(ptr);
2204     }
2205   } while (NULL != ptr);
2206   dk4sto_it_close(it);
2207 
2208 }
2209 
2210 
2211 
2212 /**	Delete a class structure (release memory).
2213 	@param	ptr	Class to delete.
2214 */
2215 static
2216 void
class_delete(pqd_class_t * ptr)2217 class_delete(pqd_class_t *ptr)
2218 {
2219 
2220   if (NULL != ptr) {
2221     dk4mem_release(ptr->name);
2222     if (NULL != ptr->i_u) {
2223       limit_all_delete(ptr->i_u);
2224     } ptr->i_u = NULL;
2225     if (NULL != ptr->s_u) {
2226       dk4sto_close(ptr->s_u);
2227     } ptr->s_u = NULL;
2228     if (NULL != ptr->i_g) {
2229       limit_all_delete(ptr->i_g);
2230     } ptr->i_g = NULL;
2231     if (NULL != ptr->s_g) {
2232       dk4sto_close(ptr->s_g);
2233     } ptr->s_g = NULL;
2234     ptr->dl = (dk4_um_t)0UL;
2235     ptr->da = 0;
2236     dk4mem_free(ptr);
2237   }
2238 #if TRACE_DEBUG
2239   else {
2240   }
2241 #endif
2242 
2243 }
2244 
2245 
2246 
2247 /**	Delete all classes from a containter.
2248 	@param	it	Container iterator.
2249 */
2250 static
2251 void
class_all_delete(dk4_sto_it_t * it)2252 class_all_delete(dk4_sto_it_t *it)
2253 {
2254   pqd_class_t	*ptr;
2255 
2256   dk4sto_it_reset(it);
2257   do {
2258     ptr = (pqd_class_t *)dk4sto_it_next(it);
2259     if (NULL != ptr) {
2260       class_delete(ptr);
2261     }
2262   } while (NULL != ptr);
2263   dk4sto_it_close(it);
2264 
2265 }
2266 
2267 
2268 
2269 /**	Create a class structure (allocate memory).
2270 	@param	n	Class name.
2271 	@return	Valid pointer on success, NULL on error.
2272 */
2273 static
2274 pqd_class_t *
class_new(const char * n)2275 class_new(const char *n)
2276 {
2277   pqd_class_t		*back	= NULL;
2278   int			 ok	= 0;
2279 
2280   if (NULL != n) {
2281     back = dk4mem_new(pqd_class_t,1,NULL);
2282     if (NULL != back) {
2283       back->s_u = NULL;
2284       back->i_u = NULL;
2285       back->s_g = NULL;
2286       back->i_g = NULL;
2287       back->dl  = (dk4_um_t)0UL;
2288       back->da  = 0;
2289       back->hdl = 0;
2290       back->name = dk4str8_dup(n, NULL);
2291       if (NULL != back->name) {
2292         back->s_u = dk4sto_open(NULL);
2293 	if (NULL != back->s_u) {
2294 	  dk4sto_set_comp(back->s_u, limit_compare, 0);
2295 	  back->i_u = dk4sto_it_open(back->s_u, NULL);
2296 	  if (NULL != back->i_u) {
2297 	    back->s_g = dk4sto_open(NULL);
2298 	    if (NULL != back->s_g) {
2299 	      dk4sto_set_comp(back->s_g, limit_compare, 0);
2300 	      back->i_g = dk4sto_it_open(back->s_g, NULL);
2301 	      if (NULL != back->i_g) {
2302 	        ok = 1;
2303 	      }
2304 #if TRACE_DEBUG
2305 	      else {
2306 	      }
2307 #endif
2308 	    }
2309 #if TRACE_DEBUG
2310 	    else {
2311 	    }
2312 #endif
2313 	  }
2314 #if TRACE_DEBUG
2315 	  else {
2316 	  }
2317 #endif
2318 	}
2319 #if TRACE_DEBUG
2320 	else {
2321 	}
2322 #endif
2323       }
2324 #if TRACE_DEBUG
2325       else {
2326       }
2327 #endif
2328       if (0 == ok) {
2329         class_delete(back);
2330 	back = NULL;
2331       }
2332     }
2333 #if TRACE_DEBUG
2334     else {
2335     }
2336 #endif
2337   }
2338 #if TRACE_DEBUG
2339   else {
2340   }
2341 #endif
2342 
2343   return back;
2344 }
2345 
2346 
2347 
2348 /**	Compare classes.
2349 	@param	l	Left object.
2350 	@param	r	Right object.
2351 	@param	cr	Comparison criteria (0=class/class, 1=class/name).
2352 	@return	Comparison result.
2353 */
2354 static
2355 int
class_compare(const void * l,const void * r,int cr)2356 class_compare(const void *l, const void *r, int cr)
2357 {
2358   const	pqd_class_t	*pl;
2359   const	pqd_class_t	*pr;
2360   int		 back	= 0;
2361 
2362   if (NULL != l) {
2363     if (NULL != r) {
2364       pl = (const pqd_class_t *)l;
2365       switch (cr) {
2366         case 1: {
2367 	  if (NULL != pl->name) {
2368 	    back = strcmp(pl->name, (const char *)r);
2369 	    if (-1 > back) { back = -1; }
2370 	    if ( 1 < back) { back =  1; }
2371 	  } else { back = -1; }
2372 	} break;
2373 	default: {
2374 	  pr = (const pqd_class_t *)r;
2375 	  if (NULL != pl->name) {
2376 	    if (NULL != pr->name) {
2377 	      back = strcmp(pl->name, pr->name);
2378 	      if (-1 > back) { back = -1; }
2379 	      if ( 1 < back) { back =  1; }
2380 	    } else { back = 1; }
2381 	  } else {
2382 	    if (NULL != pr->name) { back = -1; }
2383 	  }
2384 	} break;
2385       }
2386     } else { back = 1; }
2387   } else {
2388     if (NULL != r) { back = -1; }
2389   }
2390   return back;
2391 }
2392 
2393 
2394 
2395 /**	Delete a printer structure (release memory).
2396 	@param	ptr	Printer structure to delete.
2397 */
2398 static
2399 void
printer_delete(pqd_printer_t * ptr)2400 printer_delete(pqd_printer_t *ptr)
2401 {
2402 
2403   if (NULL != ptr) {
2404     dk4mem_release(ptr->name);
2405     ptr->cl = NULL;
2406     dk4mem_free(ptr);
2407   }
2408 
2409 }
2410 
2411 
2412 
2413 /**	Create printer structure (allocate memory).
2414 	@param	n	Printer name.
2415 	@return	Valid pointer on success, NULL on error.
2416 */
2417 static
2418 pqd_printer_t *
printer_new(const char * n)2419 printer_new(const char *n)
2420 {
2421   pqd_printer_t		*back	= NULL;
2422 
2423   if (NULL != n) {
2424     back = dk4mem_new(pqd_printer_t,1,NULL);
2425     if (NULL != back) {
2426       back->cl = NULL;
2427       back->name = dk4str8_dup(n,NULL);
2428       if (NULL == back->name) {
2429         printer_delete(back);
2430 	back = NULL;
2431       }
2432     }
2433 #if TRACE_DEBUG
2434     else {
2435     }
2436 #endif
2437   }
2438 #if TRACE_DEBUG
2439   else {
2440   }
2441 #endif
2442 
2443   return back;
2444 }
2445 
2446 
2447 
2448 /**	Compare two printers.
2449 	@param	l	Left object.
2450 	@param	r	Right object.
2451 	@param	cr	Comparison criteria (0=printer/printer, 1=printer/name).
2452 	@return	Comparison result.
2453 */
2454 static
2455 int
printer_compare(const void * l,const void * r,int cr)2456 printer_compare(const void *l, const void *r, int cr)
2457 {
2458   const pqd_printer_t	*pl;
2459   const	pqd_printer_t	*pr;
2460   int			 back	= 0;
2461 
2462   if (NULL != l) {
2463     if (NULL != r) {
2464       pl = (const pqd_printer_t *)l;
2465       switch (cr) {
2466         case 1: {
2467 	  if (NULL != pl->name) {
2468 	    back = strcmp(pl->name, (const char *)r);
2469 	    if (-1 > back) { back = -1; }
2470 	    if ( 1 < back) { back =  1; }
2471 	  } else { back = -1; }
2472 	} break;
2473 	default: {
2474 	  pr = (const pqd_printer_t *)r;
2475 	  if (NULL != pl->name) {
2476 	    if (NULL != pr->name) {
2477 	      back = strcmp(pl->name, pr->name);
2478 	      if (-1 > back) { back = -1; }
2479 	      if ( 1 < back) { back =  1; }
2480 	    } else { back = 1; }
2481 	  } else {
2482 	    if (NULL != pr->name) { back = -1; }
2483 	  }
2484 	} break;
2485       }
2486     } else { back = 1; }
2487   } else {
2488     if (NULL != r) { back = -1; }
2489   }
2490   return back;
2491 }
2492 
2493 
2494 
2495 /**	Delete all printers from a container.
2496 	@param	it	Container iterator.
2497 */
2498 static
2499 void
printer_all_delete(dk4_sto_it_t * it)2500 printer_all_delete(dk4_sto_it_t *it)
2501 {
2502   pqd_printer_t	*ptr;
2503 
2504   dk4sto_it_reset(it);
2505   do {
2506     ptr = (pqd_printer_t *)dk4sto_it_next(it);
2507     if (NULL != ptr) {
2508       printer_delete(ptr);
2509     }
2510   } while (NULL != ptr);
2511   dk4sto_it_close(it);
2512 
2513 }
2514 
2515 
2516 
2517 /**	Delete printer alias structure (release memory).
2518 	@param	ptr	Structure to delete.
2519 */
2520 static
2521 void
printer_alias_delete(pqd_printer_alias_t * ptr)2522 printer_alias_delete(pqd_printer_alias_t *ptr)
2523 {
2524 
2525   if (NULL != ptr) {
2526     dk4mem_release(ptr->name);
2527     ptr->pr = NULL;
2528     dk4mem_free(ptr);
2529   }
2530 
2531 }
2532 
2533 
2534 
2535 /**	Create printer alias structure (allocate memory).
2536 	@param	n	Alias name.
2537 	@param	pr	Printer for alias.
2538 	@return	Valid pointer on success, NULL on error.
2539 */
2540 static
2541 pqd_printer_alias_t *
printer_alias_new(const char * n,pqd_printer_t * pr)2542 printer_alias_new(const char *n, pqd_printer_t *pr)
2543 {
2544   pqd_printer_alias_t	*back	= NULL;
2545 
2546   if ((NULL != n) && (NULL != pr)) {
2547     back = dk4mem_new(pqd_printer_alias_t,1,NULL);
2548     if (NULL != back) {
2549       back->pr = pr;
2550       back->name = dk4str8_dup(n,NULL);
2551       if (NULL == back->name) {
2552         printer_alias_delete(back);
2553 	back = NULL;
2554       }
2555 #if TRACE_DEBUG
2556       else {
2557       }
2558 #endif
2559     }
2560 #if TRACE_DEBUG
2561     else {
2562     }
2563 #endif
2564   }
2565 #if TRACE_DEBUG
2566   else {
2567   }
2568 #endif
2569 
2570   return back;
2571 }
2572 
2573 
2574 
2575 /**	Compare printer alias structures.
2576 	@param	l	Left object.
2577 	@param	r	Right object.
2578 	@param	cr	Comparison criteria (0=alias/alias, 1=alias/name).
2579 	@return	Comparison result.
2580 */
2581 static
2582 int
printer_alias_compare(const void * l,const void * r,int cr)2583 printer_alias_compare(const void *l, const void *r, int cr)
2584 {
2585   const	pqd_printer_alias_t	*pl;
2586   const	pqd_printer_alias_t	*pr;
2587   int				 back	= 0;
2588 
2589   if (NULL != l) {
2590     if (NULL != r) {
2591       pl = (const pqd_printer_alias_t *)l;
2592       switch (cr) {
2593         case 1: {
2594 	  if (NULL != pl->name) {
2595 	    back = strcmp(pl->name, (const char *)r);
2596 	    if (-1 > back) { back = -1; }
2597 	    if ( 1 < back) { back =  1; }
2598 	  } else { back = -1; }
2599 	} break;
2600 	default: {
2601 	  pr = (const pqd_printer_alias_t *)r;
2602 	  if (NULL != pl->name) {
2603 	    if (NULL != pr->name) {
2604 	      back = strcmp(pl->name, pr->name);
2605 	      if (-1 > back) { back = -1; }
2606 	      if ( 1 < back) { back =  1; }
2607 	    } else { back = 1; }
2608 	  } else {
2609 	    if (NULL != pr->name) { back = -1; }
2610 	  }
2611 	} break;
2612       }
2613     } else { back = 1; }
2614   } else {
2615     if (NULL != r) { back = -1; }
2616   }
2617   return back;
2618 }
2619 
2620 
2621 
2622 /**	Delete all printer alias structures in a container.
2623 	@param	it	Container iterator.
2624 */
2625 static
2626 void
printer_alias_all_delete(dk4_sto_it_t * it)2627 printer_alias_all_delete(dk4_sto_it_t *it)
2628 {
2629   pqd_printer_alias_t	*ptr;
2630 
2631   dk4sto_it_reset(it);
2632   do {
2633     ptr = (pqd_printer_alias_t *)dk4sto_it_next(it);
2634     if (NULL != ptr) {
2635       printer_alias_delete(ptr);
2636     }
2637   } while (NULL != ptr);
2638   dk4sto_it_close(it);
2639 
2640 }
2641 
2642 
2643 
2644 /**	Initialize configuration before reading configuration file.
2645 */
2646 static
2647 void
config_init(void)2648 config_init(void)
2649 {
2650 
2651   DK4_MEMRES(&conf, sizeof(conf));
2652   conf.sname = NULL;
2653   conf.dname = NULL;
2654   conf.lname = NULL;
2655   conf.s_c = NULL;
2656   conf.i_c = NULL;
2657   conf.s_p = NULL;
2658   conf.i_p = NULL;
2659   conf.s_a = NULL;
2660   conf.i_a = NULL;
2661   conf.s_ai = NULL;
2662   conf.i_ai = NULL;
2663   conf.s_ad = NULL;
2664   conf.i_ad = NULL;
2665   conf.s_aa = NULL;
2666   conf.i_aa = NULL;
2667   conf.m_loc = 0;	/* Maximum 0 means unlimited number of connections. */
2668   conf.m_tcp = 0;	/* Maximum 0 means unlimited number of connections. */
2669   conf.uid  = 0;
2670   conf.gid  = 0;
2671   conf.suid = 0;
2672   conf.sgid = 0;
2673   conf.slbl = 5;
2674   conf.snbl = 5;
2675   conf.iglo = 0;
2676   conf.dglo = 0;
2677   conf.aglo = 0;
2678   conf.ptcp = 0;
2679   conf.pudp = 0;
2680   conf.linf = 0;
2681   conf.ldb  = 0;
2682 
2683 }
2684 
2685 
2686 
2687 /**	Allocate internal structures for configuration.
2688 	@return	1 on success, 0 on error.
2689 */
2690 static
2691 int
config_allocate(void)2692 config_allocate(void)
2693 {
2694   int		 back	= 0;
2695 
2696   conf.s_c  = dk4sto_open(NULL);
2697   conf.s_p  = dk4sto_open(NULL);
2698   conf.s_a  = dk4sto_open(NULL);
2699   conf.s_ai = dk4sto_open(NULL);
2700   conf.s_ad = dk4sto_open(NULL);
2701   conf.s_aa = dk4sto_open(NULL);
2702   if ((NULL != conf.s_ai) && (NULL != conf.s_ad) && (NULL != conf.s_aa)) {
2703   if ((NULL != conf.s_c) && (NULL != conf.s_p) && (NULL != conf.s_a)) {
2704     dk4sto_set_comp(conf.s_c, class_compare, 0);
2705     dk4sto_set_comp(conf.s_p, printer_compare, 0);
2706     dk4sto_set_comp(conf.s_a, printer_alias_compare, 0);
2707     dk4sto_set_comp(conf.s_ai, dk4socket_allowed_peer_compare, 0);
2708     dk4sto_set_comp(conf.s_ad, dk4socket_allowed_peer_compare, 0);
2709     dk4sto_set_comp(conf.s_aa, dk4socket_allowed_peer_compare, 0);
2710     conf.i_c  = dk4sto_it_open(conf.s_c, NULL);
2711     conf.i_p  = dk4sto_it_open(conf.s_p, NULL);
2712     conf.i_a  = dk4sto_it_open(conf.s_a, NULL);
2713     conf.i_ai = dk4sto_it_open(conf.s_ai, NULL);
2714     conf.i_ad = dk4sto_it_open(conf.s_ad, NULL);
2715     conf.i_aa = dk4sto_it_open(conf.s_aa, NULL);
2716     if ((NULL != conf.i_ai) && (NULL != conf.i_ad) && (NULL != conf.i_aa)) {
2717     if ((NULL != conf.i_c) && (NULL != conf.i_p) && (NULL != conf.i_a)) {
2718       back = 1;
2719     }
2720 #if TRACE_DEBUG
2721     else {
2722     }
2723 #endif
2724     }
2725 #if TRACE_DEBUG
2726     else {
2727     }
2728 #endif
2729   }
2730 #if TRACE_DEBUG
2731   else {
2732   }
2733 #endif
2734   }
2735 #if TRACE_DEBUG
2736   else {
2737   }
2738 #endif
2739 
2740   return back;
2741 }
2742 
2743 
2744 
2745 /**	Set backlog variable.
2746 	@param	iptr	Address of backlog number variable.
2747 	@param	pv	Text containing the number.
2748 	@param	fn	File name for diagnostics.
2749 	@param	lineno	Line number.
2750 	@return	1 on success, 0 on error.
2751 */
2752 static
2753 int
set_backlog(int * iptr,char * pv,const char * fn,unsigned long lineno)2754 set_backlog(int *iptr, char *pv, const char *fn, unsigned long lineno)
2755 {
2756   const char	*ep	= NULL;
2757   int		 i	= 0;
2758   int		 back	= 0;
2759   int		 res	= 0;
2760 
2761   res = dk4ma_input_c8_dec_int(&i, pv, &ep, 1, NULL);
2762   if (0 != res) {
2763     if (0 < i) {
2764       *iptr = i;
2765       back = 1;
2766     } else {
2767       /* ERROR: Must be positive */
2768       log_1(fn, lineno, LOG_EMERG, 1, 15);
2769     }
2770   } else {
2771     /* ERROR: Not an integer number */
2772     log_5(fn, lineno, LOG_EMERG, 1, 12, 13, 14, pv, ep);
2773   }
2774   return back;
2775 }
2776 
2777 
2778 
2779 /**	Set maximum number of connections.
2780 	@param	pmaxconn	Address of result variable.
2781 	@param	pv		Text containing the number.
2782 	@param	fn		File name for diagnostics.
2783 	@param	lineno		Line number.
2784 	@return	1 on success, 0 on error.
2785 */
2786 static
2787 int
set_max_connections(size_t * pmaxconn,char * pv,const char * fn,unsigned long lineno)2788 set_max_connections(
2789   size_t	*pmaxconn,
2790   char		*pv,
2791   const char	*fn,
2792   unsigned long	 lineno
2793 )
2794 {
2795   const char	*ep	= NULL;
2796   size_t	 sz	= 0;
2797   int		 back	= 0;
2798   int		 res	= 0;
2799 
2800   res = dk4ma_input_c8_dec_size_t(&sz, pv, &ep, 1, NULL);
2801   if (0 != res) {
2802     *pmaxconn = sz;
2803     back = 1;
2804   } else {
2805     /* ERROR: Not a size specification */
2806     log_5(fn, lineno, LOG_EMERG, 1, 16, 17, 18, pv, ep);
2807   }
2808 
2809   return back;
2810 }
2811 
2812 
2813 
2814 /**	Set port number from text.
2815 	@param	ppn	Address of port number variable.
2816 	@param	pv	Text containing the number.
2817 	@return	1 on success, 0 on error.
2818 */
2819 static
2820 int
set_port_number(unsigned short * ppn,char * pv,const char * fn,unsigned long lineno)2821 set_port_number(
2822   unsigned short	*ppn,
2823   char			*pv,
2824   const char		*fn,
2825   unsigned long		 lineno
2826 )
2827 {
2828   const char	*ep	= NULL;
2829   unsigned short pn	= 0;
2830   int		 back	= 0;
2831   int		 res	= 0;
2832 
2833   res = dk4ma_input_c8_dec_ushort(&pn, pv, &ep, 1, NULL);
2834   if (0 != res) {
2835     if (0 < pn) {
2836       *ppn = pn;
2837       back = 1;
2838     } else {
2839       /* ERROR: Port number must not be 0 */
2840       log_1(fn, lineno, LOG_EMERG, 1, 22);
2841     }
2842   } else {
2843     /* ERROR: Not a 16 bit unsigned number */
2844     log_5(fn, lineno, LOG_EMERG, 1, 19, 20, 21, pv, ep);
2845   }
2846 
2847   return back;
2848 }
2849 
2850 
2851 
2852 /**	Add address to list of allowed hosts.
2853 	@param	s	Containter of allowed peers.
2854 	@param	iptr	Address of global flag variable.
2855 	@param	str	Text containing the address.
2856 	@return	1 on success, 0 on error.
2857 */
2858 static
2859 int
allow_hosts(dk4_sto_t * s,int * iptr,char * str,const char * filename,unsigned long lineno)2860 allow_hosts(
2861   dk4_sto_t	*s,
2862   int		*iptr,
2863   char		*str,
2864   const char	*filename,
2865   unsigned long	 lineno
2866 )
2867 {
2868   dk4_allowed_peer_t	 ap;
2869   dk4_allowed_peer_t	*pap;
2870   char			*px	= NULL;
2871   int			 res	= 0;
2872   int			 back	= 0;
2873 
2874   px = dk4str8_next(str, NULL);
2875   if (NULL == px) {
2876     if (0 == strcmp(str, printqd_kw[2])) {
2877       *iptr = 1;
2878       back = 1;
2879     } else {
2880       DK4_MEMRES(&ap, sizeof(ap));
2881       res = dk4socket_c8_get_allowed_peer(&ap, str, NULL);
2882       if (DK4_SOCKET_RESULT_SUCCESS == res) {
2883         pap = dk4mem_new(dk4_allowed_peer_t,1,NULL);
2884 	if (NULL != pap) {
2885 	  DK4_MEMCPY(pap, &ap, sizeof(ap));
2886 	  if (0 != dk4sto_add(s, pap, NULL)) {
2887 	    back = 1;
2888 	  } else {
2889 	    dk4mem_free(pap);
2890 	    /* ERROR: Memory */
2891 	    log_1(filename, lineno, LOG_EMERG, 1, 27);
2892 	  }
2893 	} else {
2894 	  /* ERROR: Memory */
2895 	  log_1(filename, lineno, LOG_EMERG, 1, 27);
2896 	}
2897       } else {
2898         /* ERROR: Syntax, not a peer definition */
2899 	log_3(filename, lineno, LOG_EMERG, 1, 25, 26, str);
2900       }
2901     }
2902   } else {
2903     /* ERROR: Unexpected text */
2904     log_3(filename, lineno, LOG_EMERG, 1, 23, 24, px);
2905   }
2906 
2907   return back;
2908 }
2909 
2910 
2911 
2912 /**	Obtain limit value from text.
2913 	@param	plim	Address of limit variable to set.
2914 	@param	src	Text containing the limit.
2915 	@return	1 on success, 0 on error.
2916 */
2917 static
2918 int
get_limit_value(dk4_um_t * plim,char * src,const char * fn,unsigned long lineno)2919 get_limit_value(dk4_um_t *plim, char *src, const char *fn, unsigned long lineno)
2920 {
2921   const char	*ep	= NULL;
2922   dk4_um_t	 value	= (dk4_um_t)0UL;
2923   int		 back	= 0;
2924   int		 res	= 0;
2925 
2926   if (0 == strcmp(src, printqd_kw[3])) {
2927     *plim = DK4_UM_MAX;
2928     back  = 1;
2929   } else {
2930     if (0 == strcmp(src, printqd_kw[4])) {
2931       *plim = value;
2932       back  = 1;
2933     } else {
2934       res = dk4ma_input_c8_dec_dk4_um_t(&value, src, &ep, 1, NULL);
2935       if (0 != res) {
2936         *plim = value;
2937 	back  = 1;
2938       } else {
2939         /* ERROR: Syntax, not an unsigned number */
2940         log_5(fn, lineno, LOG_EMERG, 1, 28, 29, 30, src, ep);
2941       }
2942     }
2943   }
2944 
2945   return back;
2946 }
2947 
2948 
2949 
2950 /**	Add a user or group limit to a class.
2951 	@param	s	Container for limits.
2952 	@param	i	Container iterator.
2953 	@param	str	Text containing name and limit.
2954 	@param	fn	File name.
2955 	@param	lineno	Line number.
2956 	@return	1 on success, 0 on error.
2957 */
2958 static
2959 int
add_limit(dk4_sto_t * s,dk4_sto_it_t * i,char * str,const char * fn,dk4_um_t lineno)2960 add_limit(
2961   dk4_sto_t	*s,
2962   dk4_sto_it_t	*i,
2963   char		*str,
2964   const char	*fn,
2965   dk4_um_t	 lineno
2966 )
2967 {
2968   pqd_limit_t	*plim;
2969   char		*pnum;
2970   char		*px;
2971   dk4_um_t	 limval	= (dk4_um_t)0UL;
2972   int		 back	= 0;
2973 
2974   pnum	= dk4str8_next(str, NULL);
2975   if (NULL != pnum) {
2976     px = dk4str8_next(pnum, NULL);
2977     if (NULL == px) {
2978       if (0 != get_limit_value(&limval, pnum, fn, lineno)) {
2979         plim = (pqd_limit_t *)dk4sto_it_find_like(i, str, 1);
2980 	if (NULL == plim) {
2981 	  plim = limit_new(str, limval);
2982 	  if (NULL != plim) {
2983 	    if (0 != dk4sto_add(s, plim, NULL)) {
2984 	      back = 1;
2985 	    } else {
2986 	      /* ERROR: Memory */
2987 	      log_1(fn, lineno, LOG_EMERG, 1, 27);
2988 	      limit_delete(plim);
2989 	    }
2990 	  } else {
2991 	    /* ERROR: Memory */
2992 	    log_1(fn, lineno, LOG_EMERG, 1, 27);
2993 	  }
2994 	} else {
2995 	  /* ERROR: Limit redefinition */
2996 	  log_3(fn, lineno, LOG_EMERG, 1, 32, 33, str);
2997 	}
2998       }
2999     } else {
3000       /* ERROR: Syntax, no further text expected */
3001       log_3(fn, lineno, LOG_EMERG, 1, 23, 24, px);
3002     }
3003   } else {
3004     /* ERROR: Missing limit. */
3005     log_1(fn, lineno, LOG_EMERG, 1, 31);
3006   }
3007 
3008   return back;
3009 }
3010 
3011 
3012 
3013 /**	Set default limit for class.
3014 	@param	pcl	Class to modify.
3015 	@param	pv	String containing the limit.
3016 	@return	1 on success, 0 on error.
3017 */
3018 static
3019 int
set_default_limit(pqd_class_t * pcl,char * pv,const char * fn,unsigned long lineno)3020 set_default_limit(
3021   pqd_class_t	*pcl,
3022   char 		*pv,
3023   const char 	*fn,
3024   unsigned long	 lineno
3025 )
3026 {
3027   char		*px;
3028   dk4_um_t	 value	= (dk4_um_t)0UL;
3029   int		 back	= 0;
3030 
3031   px = dk4str8_next(pv, NULL);
3032   if (NULL == px) {
3033     if (0 != get_limit_value(&value, pv, fn, lineno)) {
3034       if ((0 == (1 & (pcl->hdl))) || (value == pcl->dl) ) {
3035         pcl->hdl |= 1;
3036 	pcl->dl  =  value;
3037 	back	 =  1;
3038       } else {
3039         /* ERROR: Syntax, default limit redefined */
3040 	log_1(fn, lineno, LOG_EMERG, 1, 34);
3041       }
3042     }
3043   } else {
3044     /* ERROR: No further text expected */
3045     log_3(fn, lineno, LOG_EMERG, 1, 23, 24, px);
3046   }
3047 
3048   return back;
3049 }
3050 
3051 
3052 
3053 /**	Set deny action for printer class.
3054 	@param	pcl	Class to modify.
3055 	@param	pv	String containing the action.
3056 	@return	1 on success, 0 on error.
3057 */
3058 static
3059 int
set_deny_action(pqd_class_t * pcl,char * pv,const char * fn,unsigned long lineno)3060 set_deny_action(
3061   pqd_class_t	*pcl,
3062   char		*pv,
3063   const char	*fn,
3064   unsigned long	 lineno
3065 )
3066 {
3067   char		*px	= NULL;
3068   int		 back	= 0;
3069   int		 res	= 0;
3070 
3071   px = dk4str8_next(pv, NULL);
3072   if (NULL == px) {
3073     switch ( (res = dk4str8_array_index(deny_action_names, pv, 0)) ) {
3074       case 0: case 1: {
3075         if (0 == (2 & pcl->hdl)) {
3076 	  pcl->da  =  res;
3077 	  pcl->hdl |= 2;
3078 	  back	   =  1;
3079 	} else {
3080 	  /* ERROR: Redefinition of deny action */
3081           log_1(fn, lineno, LOG_EMERG, 1, 35);
3082 	}
3083       } break;
3084       default: {
3085       } break;
3086     }
3087   } else {
3088     /* ERROR: Syntax, no further text expected */
3089     log_3(fn, lineno, LOG_EMERG, 1, 23, 24, px);
3090   }
3091 
3092   return back;
3093 }
3094 
3095 
3096 
3097 /**	Add an alias for the current printer to list.
3098 	@param	ppr	Printer to add alias for.
3099 	@param	pv	Alias name.
3100 	@return	1 on success, 0 on error.
3101 */
3102 static
3103 int
add_alias(pqd_printer_t * ppr,char * pv,const char * fn,unsigned long lineno)3104 add_alias(pqd_printer_t *ppr, char *pv, const char *fn, unsigned long lineno)
3105 {
3106   pqd_printer_alias_t	*ppa;
3107   pqd_printer_t		*pp;
3108   char			*px;
3109   int			 back	= 0;
3110 
3111   px = dk4str8_next(pv, NULL);
3112   if (NULL == px) {
3113     ppa = (pqd_printer_alias_t *)dk4sto_it_find_like(conf.i_a, pv, 1);
3114     if (NULL == ppa) {
3115       pp = (pqd_printer_t *)dk4sto_it_find_like(conf.i_p, pv, 1);
3116       if (NULL == pp) {
3117         ppa = printer_alias_new(pv, ppr);
3118 	if (NULL != ppa) {
3119 	  if (0 != dk4sto_add(conf.s_a, ppa, NULL)) {
3120 	    back = 1;
3121 	  } else {
3122 	    /* ERROR: Memory */
3123 	    log_1(fn, lineno, LOG_EMERG, 1, 27);
3124 	    printer_alias_delete(ppa);
3125 	  }
3126 	} else {
3127 	  /* ERROR: Memory */
3128 	  log_1(fn, lineno, LOG_EMERG, 1, 27);
3129 	}
3130       } else {
3131         /* ERROR: Printer exists */
3132         log_3(fn, lineno, LOG_EMERG, 1, 36, 37, pv);
3133       }
3134     } else {
3135       /* ERROR: Alias already exists */
3136       log_3(fn, lineno, LOG_EMERG, 1, 38, 39, pv);
3137     }
3138   } else {
3139     /* ERROR: Syntax, unexpected text */
3140     log_3(fn, lineno, LOG_EMERG, 1, 23, 24, px);
3141   }
3142 
3143   return back;
3144 }
3145 
3146 
3147 
3148 /**	Assign a class to a printer.
3149 	@param	ppr	Printer to modify.
3150 	@param	pv	Class name.
3151 	@return	1 on success, 0 on error.
3152 */
3153 static
3154 int
assign_class(pqd_printer_t * ppr,char * pv,const char * fn,unsigned long lineno)3155 assign_class(pqd_printer_t *ppr, char *pv, const char *fn, unsigned long lineno)
3156 {
3157   pqd_class_t	*pcl;
3158   char		*px;
3159   int		 back	= 0;
3160 
3161   px = dk4str8_next(pv, NULL);
3162   if (NULL == px) {
3163     if (NULL == ppr->cl) {
3164       pcl = (pqd_class_t *)dk4sto_it_find_like(conf.i_c, pv, 1);
3165       if (NULL != pcl) {
3166         ppr->cl = pcl;
3167 	back = 1;
3168       } else {
3169         /* ERROR: Syntax, class not found */
3170 	log_3(fn, lineno, LOG_EMERG, 1, 40, 41, pv);
3171       }
3172     } else {
3173       /* ERROR: Syntax, redefinition of printer class */
3174       log_1(fn, lineno, LOG_EMERG, 1, 42);
3175     }
3176   } else {
3177     /* ERROR: Syntax, unexpected text */
3178     log_3(fn, lineno, LOG_EMERG, 1, 23, 24, px);
3179   }
3180 
3181   return back;
3182 }
3183 
3184 
3185 
3186 /**	Check configuration for errors.
3187 	@return	1 if configuration is usable, 0 on errors.
3188 */
3189 static
3190 int
config_check(const char * filename,unsigned long lineno)3191 config_check(const char *filename, unsigned long lineno)
3192 {
3193   pqd_printer_t	*pr	= NULL;
3194   pqd_class_t	*cl	= NULL;
3195   int		 back	= 1;
3196 
3197 
3198   /*	Each printer must have a class assigned.
3199   */
3200   dk4sto_it_reset(conf.i_p);
3201   do {
3202     pr = (pqd_printer_t *)dk4sto_it_next(conf.i_p);
3203     if (NULL != pr) {
3204       if (NULL == pr->cl) {
3205         back = 0;
3206 	/* ERROR: No class for printer */
3207 	log_3(filename, lineno, LOG_EMERG, 1, 91, 92, pr->name);
3208       }
3209     }
3210   } while(NULL != pr);
3211 
3212   /*	Each class should have a default limit
3213   */
3214   dk4sto_it_reset(conf.i_c);
3215   do {
3216     cl = (pqd_class_t *)dk4sto_it_next(conf.i_c);
3217     if (NULL != cl) {
3218       if (0 == cl->hdl) {
3219 
3220         /* WARNING: Default limit missing for class */
3221 	log_3(filename, lineno, LOG_EMERG, 0, 93, 94, cl->name);
3222       }
3223     }
3224   } while (NULL != cl);
3225 
3226 
3227   return back;
3228 }
3229 
3230 
3231 
3232 /**	Set additional features to log.
3233 	@param	pv	Text containing the feature names.
3234 	@return	1 on success, 0 on errors.
3235 */
3236 static
3237 int
set_log_features(char * pv)3238 set_log_features(char *pv)
3239 {
3240 
3241   char		*pc;
3242   char		*pn;
3243   int		 back	= 0;
3244 
3245   if (NULL != pv) {
3246     back = 1;
3247     pc = dk4str8_start(pv, NULL);
3248     while (NULL != pc) {
3249       pn = strchr(pc, ',');
3250       if (NULL != pn) {
3251         *(pn++) = '\0';
3252 	pn = dk4str8_start(pn, NULL);
3253       }
3254       dk4str8_normalize(pc, NULL);
3255       switch ( dk4str8_array_index(log_feature_names, pc, 0) ) {
3256         case 0 : {
3257 	  conf.ldb = 1;
3258 	} break;
3259 	case 1 : {
3260 	  conf.linf = 1;
3261 	} break;
3262 	case 2 : case 3 : {
3263 	  conf.ldb = 1;
3264 	  conf.linf = 1;
3265 	} break;
3266 	case 4 : case 5 : {
3267 	  conf.ldb = 0;
3268 	  conf.linf = 0;
3269 	} break;
3270 	default : {
3271 	  /* ERROR: Unknown log feature name */
3272 	  log_3(NULL, 0UL, LOG_EMERG, 0, 154, 155, pc);
3273 	  back = 0;
3274 	} break;
3275       }
3276       pc = pn;
3277     }
3278   } else {
3279     /* ERROR: Value required */
3280     conf.ldb = 0; conf.linf = 0;
3281   }
3282   return back;
3283 }
3284 
3285 
3286 
3287 /**	Read configuration file.
3288 	@return	1 on success (can continue), 0 on error (must exit).
3289 */
3290 static
3291 int
config_read(void)3292 config_read(void)
3293 {
3294   const	char		*fn	= NULL;	/* Input file name */
3295   FILE			*fipo	= NULL;	/* Input file */
3296   pqd_class_t		*pcl	= NULL;	/* Current class to modify */
3297   pqd_printer_t		*ppr	= NULL;	/* Current printer to modify */
3298   pqd_printer_alias_t	*ppa	= NULL;	/* Printer alias */
3299   char			*pk	= NULL;	/* Key text */
3300   char			*pv	= NULL;	/* Value text */
3301   char			*px	= NULL;	/* Text after value */
3302   unsigned long		 lineno	= 0UL;	/* Current line number */
3303   int			 back	= 0;	/* Result */
3304   int			 sectt	= 0;	/* Section type: 0=opt, 1=class, 2=pr */
3305   int			 myres	= 0;	/* Internal operation result */
3306 
3307   if (0 != config_allocate()) {
3308     if (0 != options[1].found) { fn = options[1].val.t; }
3309     if (NULL == fn) { fn = def_conf_file_name; }
3310     fipo = dk4fopen_c8(fn, printqd_kw[1], DK4_FOPEN_SC_IS_REGULAR, NULL);
3311     if (NULL != fipo) {
3312       back	= 1;
3313       sectt	= 0;
3314       while ((1 == back) && (NULL != fgets(inbuf, sizeof(inbuf), fipo))) {
3315         lineno++;
3316         dk4str8_delnl(inbuf);
3317 	pk = dk4str8_start(inbuf, NULL);
3318 	if (NULL != pk) {
3319 	  if ('#' != *pk) {
3320 	    if ('[' == *pk) {
3321 	      /*
3322 		Opening a new section.
3323 	      */
3324 	      pk = dk4str8_start(++pk, NULL);
3325 	      if (NULL != pk) {
3326 	        sectt = -1;
3327 	        pcl   = NULL;
3328 	        ppr   = NULL;
3329 	        pv = dk4str8_chr(pk, ']');
3330 	        if (NULL != pv) { *pv = '\0'; }
3331 	        pv = dk4str8_next(pk, NULL);
3332 	        switch ( dk4str8_array_index(config_section_names, pk, 0) ) {
3333 	          /*	Opening options section.
3334 		  */
3335 	          case 0 : {
3336 		    sectt = 0;
3337 		  } break;
3338 		  /*	Opening class section.
3339 		  */
3340 		  case 1 : {
3341 		    sectt = 1;
3342 		    if (NULL != pv) {
3343 		      if (NULL == (px = dk4str8_next(pv, NULL))) {
3344 		        pcl = (pqd_class_t *)dk4sto_it_find_like(
3345 			  conf.i_c, pv, 1
3346 			);
3347 		        if (NULL == pcl) {
3348 		          pcl = class_new(pv);
3349 			  if (NULL != pcl) {
3350 			    if (0 == dk4sto_add(conf.s_c, pcl, NULL)) {
3351 			      /* ERROR: Memory */
3352 			      log_1(fn, lineno, LOG_EMERG, 1, 27);
3353 			      class_delete(pcl);
3354 			      pcl = NULL;
3355 			      back = 0;
3356 			    }
3357 			  } else {
3358 			    /* ERROR: MEMORY */
3359 			    log_1(fn, lineno, LOG_EMERG, 1, 27);
3360 			    back = 0;
3361 			  }
3362 		        } else {
3363 		          /* ERROR: Syntax, class already exists */
3364 			  log_3(fn, lineno, LOG_EMERG, 1, 43, 44, pv);
3365 		          back = 0;
3366 		        }
3367 		      } else {
3368 		        /* ERROR: Syntax, only one component allowed */
3369 			log_3(fn, lineno, LOG_EMERG, 1, 23, 24, px);
3370 		        back = 0;
3371 		      }
3372 		    } else {
3373 		      /* ERROR: Syntax, missing class name */
3374 		      log_1(fn, lineno, LOG_EMERG, 1, 45);
3375 		      back = 0;
3376 		    }
3377 		  } break;
3378 		  /*	Opening printer section.
3379 		  */
3380 		  case 2 : {
3381 		    sectt = 2;
3382 		    if (NULL != pv) {
3383 		      if (NULL == (px = dk4str8_next(pv, NULL))) {
3384 		        ppr = (pqd_printer_t *)dk4sto_it_find_like(
3385 			  conf.i_p,pv,1
3386 			);
3387 		        ppa = (pqd_printer_alias_t *)dk4sto_it_find_like(
3388 		          conf.i_a,pv,1
3389 		        );
3390 		        if ((NULL == ppr) && (NULL == ppa)) {
3391 		          ppr = printer_new(pv);
3392 			  if (NULL != ppr) {
3393 			    if (0 == dk4sto_add(conf.s_p, ppr, NULL)) {
3394 			      /* ERROR: Memory */
3395 			      log_1(fn, lineno, LOG_EMERG, 1, 27);
3396 			      printer_delete(ppr);
3397 			      ppr = NULL;
3398 			      back = 0;
3399 			    }
3400 			  } else {
3401 			    /* ERROR: Memory */
3402 			    log_1(fn, lineno, LOG_EMERG, 1, 27);
3403 			    back = 0;
3404 			  }
3405 		        } else {
3406 		          /* ERROR: Syntax, pr/al already exists */
3407 			  log_3(fn, lineno, LOG_EMERG, 1, 46, 47, pv);
3408 		          back = 0;
3409 		        }
3410 		      } else {
3411 		        /* ERROR: Syntax, just one component allowed */
3412 			log_3(fn, lineno, LOG_EMERG, 1, 23, 24, px);
3413 		        back = 0;
3414 		      }
3415 		    } else {
3416 		      /* ERROR: Syntax, name required */
3417 		      log_1(fn, lineno, LOG_EMERG, 1, 48);
3418 		      back = 0;
3419 		    }
3420 		  } break;
3421 		  default : {
3422 		    /* ERROR: Syntax, illegal section name */
3423 		    log_3(fn, lineno, LOG_EMERG, 1, 49, 50, pk);
3424 		    back = 0;
3425 		  } break;
3426 	        }
3427 	      } else {
3428 	        /* ERROR: Syntax, empty section */
3429 		log_1(fn, lineno, LOG_EMERG, 1, 51);
3430 	        back = 0;
3431 	      }
3432 	    } else {
3433 	      /*
3434 		Data line for existing section.
3435 	      */
3436 	      pv = dk4str8_chr(pk, '=');
3437 	      if (NULL != pv) {
3438 	        *(pv++) = '\0';
3439 		pv = dk4str8_start(pv, NULL);
3440 		if (NULL != pv) {
3441 		  dk4str8_normalize(pk, NULL);
3442 		  switch ( dk4str8_array_index(config_option_names, pk, 0) ) {
3443 		    case 0 : {
3444 
3445 		      if (0 == sectt) {
3446 		        struct passwd *pw;
3447 		        if (NULL == (px = dk4str8_next(pv, NULL))) {
3448 		          pw = getpwnam(pv);
3449 			  if (NULL != pw) {
3450 			    if ((0 == conf.uid) || (conf.uid == pw->pw_uid)) {
3451 			      conf.uid = pw->pw_uid;
3452 			    } else {
3453 			      /* ERROR: Redefinition */
3454 			      log_1(fn, lineno, LOG_EMERG, 1, 52);
3455 			      back = 0;
3456 			    }
3457 			  } else {
3458 			    /* ERROR: User not found */
3459 			    log_3(fn, lineno, LOG_EMERG, 1, 53, 54, pv);
3460 			    back = 0;
3461 			  }
3462 		        } else {
3463 		          /* ERROR: Syntax, just one component allowed */
3464 			  log_3(fn, lineno, LOG_EMERG, 1, 23, 24, px);
3465 			  back = 0;
3466 		        }
3467 		      } else {
3468 		        /* ERROR: Only allwowed in options section */
3469 			log_1(fn, lineno, LOG_EMERG, 1, 55);
3470 		        back = 0;
3471 		      }
3472 		    } break;
3473 		    case 1 : {
3474 		      if (0 == sectt) {
3475 		        struct group	*pgr;
3476 			if (NULL == (px = dk4str8_next(pv, NULL))) {
3477 			  pgr = getgrnam(pv);
3478 			  if (NULL != pgr) {
3479 			    if ((0 == conf.gid) || (conf.gid == pgr->gr_gid)) {
3480 			      conf.gid = pgr->gr_gid;
3481 			    } else {
3482 			      /* ERROR: Syntax, group redefinition */
3483 			      log_1(fn, lineno, LOG_EMERG, 1, 56);
3484 			      back = 0;
3485 			    }
3486 			  } else {
3487 			    /* ERROR: Syntax, group not found */
3488 			    log_3(fn, lineno, LOG_EMERG, 1, 57, 58, pv);
3489 			    back = 0;
3490 			  }
3491 			} else {
3492 			  /* ERROR: Syntax, just one component allowed */
3493 			  log_3(fn, lineno, LOG_EMERG, 1, 23, 24, px);
3494 			  back = 0;
3495 			}
3496 		      } else {
3497 		        /* ERROR: Syntax, only allowed in options */
3498 			log_1(fn, lineno, LOG_EMERG, 1, 55);
3499 		        back = 0;
3500 		      }
3501 		    } break;
3502 		    case 2 : {
3503 		      if (0 == sectt) {
3504 		        if (NULL == conf.dname) {
3505 			  conf.dname = dk4str8_dup(pv, NULL);
3506 			  if (NULL == conf.dname) {
3507 			    /* ERROR: Memory */
3508 			    log_1(fn, lineno, LOG_EMERG, 1, 27);
3509 			    back = 0;
3510 			  }
3511 			} else {
3512 			  /* ERROR: Redefinition */
3513 			  log_1(fn, lineno, LOG_EMERG, 1, 59);
3514 			  back = 0;
3515 			}
3516 		      } else {
3517 		        /* ERROR: Syntax, only allowed in options */
3518 			log_1(fn, lineno, LOG_EMERG, 1, 55);
3519 		        back = 0;
3520 		      }
3521 		    } break;
3522 		    case 3 : {
3523 		      if (0 == sectt) {
3524 		        if (NULL == conf.sname) {
3525 			  conf.sname = dk4str8_dup(pv, NULL);
3526 			  if (NULL == conf.sname) {
3527 			    /* ERROR: Memory */
3528 			    log_1(fn, lineno, LOG_EMERG, 1, 27);
3529 			    back = 0;
3530 			  }
3531 			} else {
3532 			  /* ERROR: Redefinition */
3533 			  log_1(fn, lineno, LOG_EMERG, 1, 60);
3534 			  back = 0;
3535 			}
3536 		      } else {
3537 		        /* ERROR: Syntax, only allowed in options */
3538 			log_1(fn, lineno, LOG_EMERG, 1, 55);
3539 		        back = 0;
3540 		      }
3541 		    } break;
3542 		    case 4 : {
3543 		      if (0 == sectt) {
3544 		        if (0 == set_backlog(&(conf.slbl), pv, fn, lineno)) {
3545 			  back = 0;
3546 			}
3547 		      } else {
3548 		        /* ERROR: Syntax, only allowed in options */
3549 			log_1(fn, lineno, LOG_EMERG, 1, 55);
3550 		        back = 0;
3551 		      }
3552 		    } break;
3553 		    case 5 : {
3554 		      if (0 == sectt) {
3555 		        if(0 == set_max_connections(&(conf.m_loc),pv,fn,lineno))
3556 			{
3557 			  back = 0;
3558 			}
3559 		      } else {
3560 		        /* ERROR: Syntax, only allowed in options */
3561 			log_1(fn, lineno, LOG_EMERG, 1, 55);
3562 		        back = 0;
3563 		      }
3564 		    } break;
3565 		    case 6 : {
3566 		      if (0 == sectt) {
3567 		        if (0 == set_port_number(&(conf.pudp),pv,fn,lineno)) {
3568 			  back = 0;
3569 			}
3570 		      } else {
3571 		        /* ERROR: Syntax, only allowed in options */
3572 			log_1(fn, lineno, LOG_EMERG, 1, 55);
3573 		        back = 0;
3574 		      }
3575 		    } break;
3576 		    case 7 : {
3577 		      if (0 == sectt) {
3578 		        if (0 == set_port_number(&(conf.ptcp),pv,fn,lineno)) {
3579 			  back = 0;
3580 			}
3581 		      } else {
3582 		        /* ERROR: Syntax, only allowed in options */
3583 			log_1(fn, lineno, LOG_EMERG, 1, 55);
3584 		        back = 0;
3585 		      }
3586 		    } break;
3587 		    case 8 : {
3588 		      if (0 == sectt) {
3589 		        if (0 == set_backlog(&(conf.snbl), pv, fn, lineno)) {
3590 			  back = 0;
3591 			}
3592 		      } else {
3593 		        /* ERROR: Syntax, only allowed in options */
3594 			log_1(fn, lineno, LOG_EMERG, 1, 55);
3595 		        back = 0;
3596 		      }
3597 		    } break;
3598 		    case 9 : {
3599 		      if (0 == sectt) {
3600 		        if(0 == set_max_connections(&(conf.m_tcp),pv,fn,lineno))
3601 			{
3602 			  back = 0;
3603 			}
3604 		      } else {
3605 		        /* ERROR: Syntax, only allowed in options */
3606 			log_1(fn, lineno, LOG_EMERG, 1, 55);
3607 		        back = 0;
3608 		      }
3609 		    } break;
3610 		    case 10 : {
3611 		      if (0 == sectt) {
3612 			myres = allow_hosts(
3613 			  conf.s_ai, &(conf.iglo), pv,
3614 			  fn, lineno
3615 			);
3616 			if (0 == myres) {
3617 			  back = 0;
3618 			}
3619 		      } else {
3620 		        /* ERROR: Syntax, only allowed in options */
3621 			log_1(fn, lineno, LOG_EMERG, 1, 55);
3622 		        back = 0;
3623 		      }
3624 		    } break;
3625 		    case 11 : {
3626 		      if (0 == sectt) {
3627 			myres = allow_hosts(
3628 			  conf.s_ad, &(conf.dglo), pv,
3629 			  fn, lineno
3630 			);
3631 			if (0 == myres) {
3632 			  back = 0;
3633 			}
3634 		      } else {
3635 		        /* ERROR: Syntax, only allowed in options */
3636 			log_1(fn, lineno, LOG_EMERG, 1, 55);
3637 		        back = 0;
3638 		      }
3639 		    } break;
3640 		    case 12 : {
3641 		      if (0 == sectt) {
3642 			myres = allow_hosts(
3643 			  conf.s_aa, &(conf.aglo), pv,
3644 			  fn, lineno
3645 			);
3646 			if (0 == myres) {
3647 			  back = 0;
3648 			}
3649 		      } else {
3650 		        /* ERROR: Syntax, only allowed in options */
3651 			log_1(fn, lineno, LOG_EMERG, 1, 55);
3652 		        back = 0;
3653 		      }
3654 		    } break;
3655 		    case 13 : {
3656 		      if ((1 == sectt) && (NULL != pcl)) {
3657 			myres = add_limit(
3658 			  pcl->s_u, pcl->i_u, pv, fn, lineno
3659 			);
3660 			if (0 == myres) {
3661 			  back = 0;
3662 			}
3663 		      } else {
3664 		        /* ERROR: Syntax, only allowed in class */
3665 			log_1(fn, lineno, LOG_EMERG, 1, 61);
3666 		        back = 0;
3667 		      }
3668 		    } break;
3669 		    case 14 : {
3670 		      if ((1 == sectt) && (NULL != pcl)) {
3671 			myres = add_limit(
3672 			  pcl->s_g, pcl->i_g, pv, fn, lineno
3673 			);
3674 			if (0 == myres) {
3675 			  back = 0;
3676 			}
3677 		      } else {
3678 		        /* ERROR: Syntax, only allowed in class */
3679 			log_1(fn, lineno, LOG_EMERG, 1, 61);
3680 		        back = 0;
3681 		      }
3682 		    } break;
3683 		    case 15 : {
3684 		      if ((1 == sectt) && (NULL != pcl)) {
3685 			myres = set_default_limit(pcl, pv, fn, lineno);
3686 			if (0 == myres) {
3687 			  back = 0;
3688 			}
3689 		      } else {
3690 		        /* ERROR: Syntax, only allowed in class */
3691 			log_1(fn, lineno, LOG_EMERG, 1, 61);
3692 		        back = 0;
3693 		      }
3694 		    } break;
3695 		    case 16 : {
3696 		      if ((1 == sectt) && (NULL != pcl)) {
3697 			myres = set_deny_action(pcl, pv, fn, lineno);
3698 			if (0 == myres) {
3699 			  back = 0;
3700 			}
3701 		      } else {
3702 		        /* ERROR: Syntax, only allowed in class */
3703 			log_1(fn, lineno, LOG_EMERG, 1, 61);
3704 		        back = 0;
3705 		      }
3706 		    } break;
3707 		    case 17 : {
3708 		      if ((2 == sectt) && (NULL != ppr)) {
3709 			myres = add_alias(ppr, pv, fn, lineno);
3710 			if (0 == myres) {
3711 			  back = 0;
3712 			}
3713 		      } else {
3714 		        /* ERROR: Syntax, only allowed in printer */
3715 			log_1(fn, lineno, LOG_EMERG, 1, 62);
3716 		        back = 0;
3717 		      }
3718 		    } break;
3719 		    case 18 : {
3720 		      if ((2 == sectt) && (NULL != ppr)) {
3721 		        myres = assign_class(ppr, pv, fn, lineno);
3722 			if (0 == myres) {
3723 			  back = 0;
3724 			}
3725 		      } else {
3726 		        /* ERROR: Syntax, only allowed in printer */
3727 			log_1(fn, lineno, LOG_EMERG, 1, 62);
3728 		        back = 0;
3729 		      }
3730 		    } break;
3731 		    case 19 : {
3732 		      if (0 == sectt) {
3733 		        if (NULL == conf.lname) {
3734 			  conf.lname = dk4str8_dup(pv, NULL);
3735 			  if (NULL == conf.lname) {
3736 			    /* ERROR: Memory */
3737 			    log_1(fn, lineno, LOG_EMERG, 1, 27);
3738 			    back = 0;
3739 			  }
3740 			} else {
3741 			  /* ERROR: Redefinition */
3742 			  log_1(fn, lineno, LOG_EMERG, 1, 63);
3743 			  back = 0;
3744 			}
3745 		      } else {
3746 		        /* ERROR: Only in options */
3747 			log_1(fn, lineno, LOG_EMERG, 1, 55);
3748 		        back = 0;
3749 		      }
3750 		    } break;
3751 		    case 20 : {
3752 		      back = set_log_features(pv);
3753 		    } break;
3754 		    case 21 : {
3755 		      if (0 == sectt) {
3756 		        struct passwd *pw;
3757 		        if (NULL == (px = dk4str8_next(pv, NULL))) {
3758 		          pw = getpwnam(pv);
3759 			  if (NULL != pw) {
3760 			    if ((0 == conf.suid) || (conf.suid == pw->pw_uid)) {
3761 			      conf.suid = pw->pw_uid;
3762 			    } else {
3763 			      /* ERROR: Redefinition */
3764 			      log_1(fn, lineno, LOG_EMERG, 1, 52);
3765 			      back = 0;
3766 			    }
3767 			  } else {
3768 			    /* ERROR: User not found */
3769 			    log_3(fn, lineno, LOG_EMERG, 1, 53, 54, pv);
3770 			    back = 0;
3771 			  }
3772 		        } else {
3773 		          /* ERROR: Syntax, just one component allowed */
3774 			  log_3(fn, lineno, LOG_EMERG, 1, 23, 24, px);
3775 			  back = 0;
3776 		        }
3777 		      } else {
3778 		        /* ERROR: Only allwowed in options section */
3779 			log_1(fn, lineno, LOG_EMERG, 1, 55);
3780 		        back = 0;
3781 		      }
3782 		    } break;
3783 		    case 22 : {
3784 		      if (0 == sectt) {
3785 		        struct group	*pgr;
3786 			if (NULL == (px = dk4str8_next(pv, NULL))) {
3787 			  pgr = getgrnam(pv);
3788 			  if (NULL != pgr) {
3789 			    if((0 == conf.sgid) || (conf.sgid == pgr->gr_gid)) {
3790 			      conf.sgid = pgr->gr_gid;
3791 			    } else {
3792 			      /* ERROR: Syntax, group redefinition */
3793 			      log_1(fn, lineno, LOG_EMERG, 1, 56);
3794 			      back = 0;
3795 			    }
3796 			  } else {
3797 			    /* ERROR: Syntax, group not found */
3798 			    log_3(fn, lineno, LOG_EMERG, 1, 57, 58, pv);
3799 			    back = 0;
3800 			  }
3801 			} else {
3802 			  /* ERROR: Syntax, just one component allowed */
3803 			  log_3(fn, lineno, LOG_EMERG, 1, 23, 24, px);
3804 			  back = 0;
3805 			}
3806 		      } else {
3807 		        /* ERROR: Syntax, only allowed in options */
3808 			log_1(fn, lineno, LOG_EMERG, 1, 55);
3809 		        back = 0;
3810 		      }
3811 		    } break;
3812 		  }
3813 		} else {
3814 		  /* ERROR: Syntax, missing value */
3815 		  log_1(fn, lineno, LOG_EMERG, 1, 64);
3816 		  back = 0;
3817 		}
3818 	      } else {
3819 	        /* ERROR: Syntax, missing value */
3820 		log_1(fn, lineno, LOG_EMERG, 1, 64);
3821 		back = 0;
3822 	      }
3823 	    }
3824 	  }
3825 #if TRACE_DEBUG
3826 	  else {
3827 	  }
3828 #endif
3829 	}
3830 #if TRACE_DEBUG
3831 	else {
3832 	}
3833 #endif
3834       }
3835       fclose(fipo);
3836       if (1 == back) {
3837         back = config_check(fn, lineno);
3838       }
3839     } else {
3840       /* ERROR: Failed to open file */
3841       log_1(fn, 0UL, LOG_EMERG, 1, 65);
3842     }
3843   } else {
3844     /* ERROR: Memory */
3845     log_1(NULL, 0UL, LOG_EMERG, 1, 27);
3846   }
3847 
3848   return back;
3849 }
3850 
3851 
3852 
3853 static
3854 void
release_allowed_peers(dk4_sto_it_t * it)3855 release_allowed_peers(dk4_sto_it_t *it)
3856 {
3857   dk4_allowed_peer_t	*peer;
3858 
3859   dk4sto_it_reset(it);
3860   do {
3861     peer = (dk4_allowed_peer_t *)dk4sto_it_next(it);
3862     if (NULL != peer) {
3863       dk4mem_free(peer);
3864     }
3865   } while (NULL != peer);
3866   dk4sto_it_close(it);
3867 
3868 }
3869 
3870 
3871 
3872 /**	Release resources used to save configuration data.
3873 */
3874 static
3875 void
config_release(void)3876 config_release(void)
3877 {
3878 
3879   prev_uid = conf.uid;
3880   prev_gid = conf.gid;
3881 
3882   if (NULL != conf.i_aa) {	/* Allowed peers for administration */
3883     release_allowed_peers(conf.i_aa);
3884   } conf.i_aa = NULL;
3885   if (NULL != conf.s_aa) {
3886     dk4sto_close(conf.s_aa);
3887   } conf.s_aa = NULL;
3888   if (NULL != conf.i_ad) {	/* Allowed peers for data */
3889     release_allowed_peers(conf.i_ad);
3890   } conf.i_ad = NULL;
3891   if (NULL != conf.s_ad) {
3892     dk4sto_close(conf.s_ad);
3893   } conf.s_ad = NULL;
3894   if (NULL != conf.i_ai) {	/* Allowed peers for information */
3895     release_allowed_peers(conf.i_ai);
3896   } conf.i_ai = NULL;
3897   if (NULL != conf.s_ai) {
3898     dk4sto_close(conf.s_ai);
3899   } conf.s_ai = NULL;
3900   if (NULL != conf.i_a) {	/* Aliases */
3901     printer_alias_all_delete(conf.i_a);
3902   } conf.i_a = NULL;
3903   if (NULL != conf.s_a) {
3904     dk4sto_close(conf.s_a);
3905   } conf.s_a = NULL;
3906   if (NULL != conf.i_p) {	/* Printers */
3907     printer_all_delete(conf.i_p);
3908   } conf.i_p = NULL;
3909   if (NULL != conf.s_p) {
3910     dk4sto_close(conf.s_p);
3911   } conf.s_p = NULL;
3912   if (NULL != conf.i_c) {	/* Classes */
3913     class_all_delete(conf.i_c);
3914   } conf.i_c = NULL;
3915   if (NULL != conf.s_c) {
3916     dk4sto_close(conf.s_c);
3917   } conf.s_c = NULL;
3918   dk4mem_release(conf.dname);
3919   dk4mem_release(conf.sname);
3920   dk4mem_release(conf.lname);
3921   conf.m_loc = 0;
3922   conf.m_tcp = 0;
3923   conf.uid   = 0;
3924   conf.gid   = 0;
3925   conf.slbl  = 0;
3926   conf.snbl  = 0;
3927   conf.ptcp  = 9100;
3928   conf.pudp  = 9100;
3929 
3930 }
3931 
3932 
3933 
3934 /**	Allocate resources before starting outer loop.
3935 	@return	1 on success (can enter loop), 0 on error (exit).
3936 */
3937 static
3938 int
outer_allocate_resources(void)3939 outer_allocate_resources(void)
3940 {
3941   int		 back	= 0;
3942 
3943 
3944   /*	Initialize variables to NULL.
3945   */
3946   s_c_unix = NULL;
3947   i_c_unix = NULL;
3948   s_c_tcp  = NULL;
3949   i_c_tcp  = NULL;
3950 
3951   /*	Allocate resources.
3952   */
3953   s_c_unix = dk4sto_open(NULL);
3954   if (NULL == s_c_unix) {
3955     /* ERROR: Memory */
3956     log_1(NULL, 0UL, LOG_EMERG, 1, 27);
3957     goto finished;
3958   }
3959   dk4sto_set_comp(s_c_unix, compare_pqd_l_conn_t, 0);
3960   i_c_unix = dk4sto_it_open(s_c_unix, NULL);
3961   if (NULL == i_c_unix) {
3962     /* ERROR: Memory */
3963     log_1(NULL, 0UL, LOG_EMERG, 1, 27);
3964     goto finished;
3965   }
3966   s_c_tcp = dk4sto_open(NULL);
3967   if (NULL == s_c_tcp) {
3968     /* ERROR: Memory */
3969     log_1(NULL, 0UL, LOG_EMERG, 1, 27);
3970     goto finished;
3971   }
3972   dk4sto_set_comp(s_c_tcp, compare_pqd_n_conn_t, 0);
3973   i_c_tcp = dk4sto_it_open(s_c_tcp, NULL);
3974   if (NULL == i_c_tcp) {
3975     /* ERROR: Memory */
3976     log_1(NULL, 0UL, LOG_EMERG, 1, 27);
3977     goto finished;
3978   }
3979 
3980   /*	Indicate success.
3981   */
3982   back = 1;
3983 
3984   finished:
3985 
3986   return back;
3987 }
3988 
3989 
3990 
3991 /**	Release resources after finishing outer loop.
3992 */
3993 static
3994 void
outer_release_resources(void)3995 outer_release_resources(void)
3996 {
3997   pqd_n_conn_t	*pnc;
3998   pqd_l_conn_t	*plc;
3999 
4000 
4001   if (NULL != i_c_tcp) {
4002     dk4sto_it_reset(i_c_tcp);
4003     do {
4004       pnc = (pqd_n_conn_t *)dk4sto_it_next(i_c_tcp);
4005       if (NULL != pnc) {
4006         /* Release pnc */
4007 	if (INVALID_SOCKET != pnc->sock) {
4008 	  (void)dk4socket_close(pnc->sock, NULL);
4009 	}
4010 	dk4mem_free(pnc);
4011       }
4012     } while(NULL != pnc);
4013     dk4sto_it_close(i_c_tcp);
4014   }
4015   i_c_tcp = NULL;
4016   if (NULL != s_c_tcp) {
4017     dk4sto_close(s_c_tcp);
4018   }
4019   s_c_tcp = NULL;
4020   if (NULL != i_c_unix) {
4021     dk4sto_it_reset(i_c_unix);
4022     do {
4023       plc = (pqd_l_conn_t *)dk4sto_it_next(i_c_unix);
4024       if (NULL != plc) {
4025         /* Release plc */
4026 	if (INVALID_SOCKET != plc->sock) {
4027 	  (void)dk4socket_close(plc->sock, NULL);
4028 	}
4029 	dk4mem_free(plc);
4030       }
4031     } while (NULL != plc);
4032     dk4sto_it_close(i_c_unix);
4033   }
4034   i_c_unix = NULL;
4035   if (NULL != s_c_unix) {
4036     dk4sto_close(s_c_unix);
4037   }
4038   s_c_unix = NULL;
4039 
4040 }
4041 
4042 
4043 
4044 static
4045 void
pqd_dbi_open_error(const char * fn,dk4_er_t * erp)4046 pqd_dbi_open_error(const char *fn, dk4_er_t *erp)
4047 {
4048   switch (erp->ec) {
4049     case DK4_E_NOT_SUPPORTED : {
4050       log_3(NULL, 0UL, LOG_EMERG, 1, 105, 202, fn);
4051     } break;
4052     case DK4_E_MATH_OVERFLOW : {
4053       log_3(NULL, 0UL, LOG_EMERG, 1, 105, 203, fn);
4054     } break;
4055     case DK4_E_MEMORY_ALLOCATION_FAILED : {
4056       log_3(NULL, 0UL, LOG_EMERG, 1, 105, 204, fn);
4057     } break;
4058     case DK4_E_SYNTAX : {
4059       log_3(NULL, 0UL, LOG_EMERG, 1, 105, 205, fn);
4060     } break;
4061     case DK4_E_SEC_CHECK : {
4062       log_3(NULL, 0UL, LOG_EMERG, 1, 105, 206, fn);
4063     } break;
4064     case DK4_E_OPEN_READ_FAILED : {
4065       log_3(NULL, 0UL, LOG_EMERG, 1, 105, 207, fn);
4066     } break;
4067     case DK4_E_OPEN_WRITE_FAILED : {
4068       log_3(NULL, 0UL, LOG_EMERG, 1, 105, 208, fn);
4069     } break;
4070     case DK4_E_CLOSE_FAILED : {
4071       log_3(NULL, 0UL, LOG_EMERG, 1, 105, 209, fn);
4072     } break;
4073     default : {
4074       log_3(NULL, 0UL, LOG_EMERG, 1, 105, 106, fn);
4075     } break;
4076   }
4077 }
4078 
4079 
4080 /**	Allocate resources before starting inner loop.
4081 	* Create log directory and log file.
4082 	* Open database.
4083 	* Log message for starting service.
4084 	@return	1 on success (can enter loop), 0 on error (exit).
4085 */
4086 static
4087 int
inner_allocate_resources(void)4088 inner_allocate_resources(void)
4089 {
4090   char		 necbuf[16*sizeof(dk4_um_t)];
4091   dk4_er_t	 er;
4092   const char	*fn;
4093   uid_t		 sockuid;
4094   gid_t		 sockgid;
4095   int		 res;
4096   int		 back	= 0;
4097 
4098 
4099   /*	Log file directory hierarchy.
4100   */
4101   fn = conf.lname;
4102   if (NULL == fn) { fn = def_log_file_name; }
4103   if (0 != user_switched) {
4104     res = dk4mkdir_hierarchy_c8(fn, 0, NULL);
4105   } else {
4106     res = dk4mkdir_hierarchy_ugm_c8(fn, 0, conf.uid, conf.gid, 0750, NULL);
4107   }
4108   if (0 == res) {
4109     /* ERROR: Failed to create directory hierachy for log file */
4110     log_3(NULL, 0UL, LOG_EMERG, 1, 95, 96, fn);
4111     goto finished;
4112   }
4113 
4114   /*	Database directory hierarchy
4115   */
4116   fn = conf.dname;
4117   if (NULL == fn) { fn = def_db_file_name; }
4118   fn = dk4dbi_filename_part(fn);
4119   if (0 != user_switched) {
4120     res = dk4mkdir_hierarchy_c8(fn, 0, NULL);
4121   } else {
4122     res = dk4mkdir_hierarchy_ugm_c8(fn, 0, conf.uid, conf.gid, 0750, NULL);
4123   }
4124   if (0 == res) {
4125     /* ERROR: Failed to create directory hierarchy for db file */
4126     log_3(NULL, 0UL, LOG_EMERG, 1, 97, 98, fn);
4127     goto finished;
4128   }
4129 
4130   /*	Socket directory hierarchy
4131   */
4132   fn = conf.sname;
4133   if (NULL == fn) { fn = def_sock_file_name; }
4134   sockuid = conf.suid;
4135   if (0 == sockuid) { sockuid = conf.uid; }
4136   sockgid = conf.sgid;
4137   if (0 == sockgid) { sockgid = conf.gid; }
4138   if ((0 != user_switched) && (0 != conf.uid)) {
4139     res = dk4mkdir_hierarchy_c8(fn, 0, NULL);
4140   } else {
4141     /*
4142 	In contrast to the db and log directories the non-privileged
4143 	user needs write access to the directory as the socket is deleted
4144 	and newly created.
4145     */
4146     res = dk4mkdir_hierarchy_ugm_c8(fn, 0, sockuid, sockgid, 0770, NULL);
4147   }
4148   if (0 == res) {
4149     /* ERROR: Failed to create directory hierarchy for socket */
4150     log_3(NULL, 0UL, LOG_EMERG, 1, 99, 100, fn);
4151     goto finished;
4152   }
4153 
4154   /*	UNIX listener socket.
4155   */
4156   fn = conf.sname;
4157   if (NULL == fn) { fn = def_sock_file_name; }
4158 
4159   dk4error_init(&er);
4160   if (
4161     ((0 != sockuid) || (0 != sockgid))
4162     && ((0 == user_switched) || (0 == conf.uid))
4163   )
4164   {
4165     so_unix = dk4socket_c8_unix_listener_owner_group_mode(
4166       fn, ((0 < conf.slbl) ? (conf.slbl) : 5), sockuid, sockgid, 0660, &er
4167     );
4168   } else {
4169     so_unix = dk4socket_c8_unix_listener(
4170       fn, ((0 < conf.slbl) ? (conf.slbl) : 5), &er
4171     );
4172   }
4173   if (INVALID_SOCKET == so_unix) {
4174     /* ERROR: Failed to create listener socket */
4175     res = dk4ma_write_c8_decimal_signed(
4176       necbuf, sizeof(necbuf), (dk4_im_t)(er.dt.iDetails1), 0, NULL
4177     );
4178     if (0 != res) {
4179       switch (er.ec) {
4180         case DK4_E_SYNTAX : {
4181 	  log_3(NULL, 0UL, LOG_EMERG, 1, 101, 178, fn);
4182 	} break;
4183 	case DK4_E_NON_SOCKET : {
4184 	  log_3(NULL, 0UL, LOG_EMERG, 1, 101, 179, fn);
4185 	} break;
4186 	case DK4_E_UNLINK_FAILED : {
4187 	  log_3(NULL, 0UL, LOG_EMERG, 1, 101, 180, fn);
4188 	} break;
4189 	case DK4_E_SOCKET_SOCKET : {
4190 	  log_5(NULL, 0UL, LOG_EMERG, 1, 101, 181, 182, fn, necbuf);
4191 	} break;
4192 	case DK4_E_SOCKET_BIND : {
4193 	  log_5(NULL, 0UL, LOG_EMERG, 1, 101, 183, 182, fn, necbuf);
4194 	} break;
4195 	case DK4_E_SOCKET_LISTEN : {
4196 	  log_5(NULL, 0UL, LOG_EMERG, 1, 101, 184, 182, fn, necbuf);
4197 	} break;
4198 	case DK4_E_CHOWN_FAILED : {
4199 	  log_3(NULL, 0UL, LOG_EMERG, 1, 101, 185, fn);
4200 	} break;
4201 	case DK4_E_CHMOD_FAILED : {
4202 	  log_3(NULL, 0UL, LOG_EMERG, 1, 101, 186, fn);
4203 	} break;
4204 	default : {
4205 	  log_3(NULL, 0UL, LOG_EMERG, 1, 101, 102, fn);
4206 	} break;
4207       }
4208     } else {
4209       log_3(NULL, 0UL, LOG_EMERG, 1, 101, 102, fn);
4210     }
4211     goto finished;
4212   }
4213 
4214   /*	TCP listener socket set.
4215   */
4216   if (0 < conf.ptcp) {
4217     dk4error_init(&er);
4218     ss_tcp = dk4socket_c8_set_server(
4219       conf.ptcp, ((0 < conf.snbl) ? (conf.snbl) : 5), 0, &er
4220     );
4221     if (NULL == ss_tcp) {
4222       /* ERROR: Failed to create TCP listener socket */
4223       res = dk4ma_write_c8_decimal_signed(
4224         necbuf, sizeof(necbuf), (dk4_im_t)(er.dt.iDetails1), 0, NULL
4225       );
4226       if (0 != res) {
4227         switch (er.ec) {
4228 	  case DK4_E_MATH_OVERFLOW : {
4229             log_1(NULL, 0UL, LOG_EMERG, 1, 188);
4230 	  } break;
4231 	  case DK4_E_MEMORY_ALLOCATION_FAILED : {
4232 	    log_1(NULL, 0UL, LOG_EMERG, 1, 189);
4233 	  } break;
4234 	  case DK4_E_SOCKET_SOCKET : {
4235 	    log_3(NULL, 0UL, LOG_EMERG, 1, 190, 191, necbuf);
4236 	  } break;
4237 	  case DK4_E_SOCKET_BIND : {
4238 	    log_3(NULL, 0UL, LOG_EMERG, 1, 192, 191, necbuf);
4239 	  } break;
4240 	  case DK4_E_SOCKET_LISTEN : {
4241 	    log_3(NULL, 0UL, LOG_EMERG, 1, 193, 191, necbuf);
4242 	  } break;
4243 	  case DK4_E_SOCKET_GETADDRLOC : {
4244 	    log_3(NULL, 0UL, LOG_EMERG, 1, 194, 191, necbuf);
4245 	  } break;
4246 	  default : {
4247             log_1(NULL, 0UL, LOG_EMERG, 1, 103);
4248 	  } break;
4249 	}
4250       } else {
4251         log_1(NULL, 0UL, LOG_EMERG, 1, 103);
4252       }
4253       goto finished;
4254     }
4255   }
4256 
4257   /*	UDP socket set.
4258   */
4259   if (0 < conf.pudp) {
4260     dk4error_init(&er);
4261     ss_udp = dk4socket_c8_set_udp(conf.pudp, 0, 0, &er);
4262     if (NULL == ss_udp) {
4263       /* ERROR: Failed to create UDP socket set */
4264       res = dk4ma_write_c8_decimal_signed(
4265         necbuf, sizeof(necbuf), (dk4_im_t)(er.dt.iDetails1), 0, NULL
4266       );
4267       if (0 != res) {
4268         switch (er.ec) {
4269 	  case DK4_E_MATH_OVERFLOW : {
4270             log_1(NULL, 0UL, LOG_EMERG, 1, 195);
4271 	  } break;
4272 	  case DK4_E_MEMORY_ALLOCATION_FAILED : {
4273 	    log_1(NULL, 0UL, LOG_EMERG, 1, 196);
4274 	  } break;
4275 	  case DK4_E_SOCKET_SOCKET : {
4276 	    log_3(NULL, 0UL, LOG_EMERG, 1, 197, 198, necbuf);
4277 	  } break;
4278 	  case DK4_E_SOCKET_BIND : {
4279 	    log_3(NULL, 0UL, LOG_EMERG, 1, 199, 198, necbuf);
4280 	  } break;
4281 	  case DK4_E_SOCKET_LISTEN : {
4282 	    log_3(NULL, 0UL, LOG_EMERG, 1, 200, 198, necbuf);
4283 	  } break;
4284 	  case DK4_E_SOCKET_GETADDRLOC : {
4285 	    log_3(NULL, 0UL, LOG_EMERG, 1, 201, 198, necbuf);
4286 	  } break;
4287 	}
4288       } else {
4289         log_1(NULL, 0UL, LOG_EMERG, 1, 104);
4290       }
4291       goto finished;
4292     }
4293   }
4294 
4295   fn = conf.dname;
4296   if (NULL == fn) { fn = def_db_file_name; }
4297 
4298   dk4error_init(&er);
4299   db = dk4dbi_open(fn, 1, 0, 1024, 1024, &er);
4300   if (NULL != db) {
4301     db_modified = 0;
4302     res = 1;
4303     dk4error_init(&er);
4304     if (0 == dbi_set(db, printqd_kw[79],printqd_kw[79],&er)) { res = 0; }
4305     if (0 == dk4dbi_close(db, &er)) { res = 0; }
4306     db = NULL;
4307     db_modified = 0;
4308     if (0 != res) {
4309 
4310       dk4error_init(&er);
4311       db = dk4dbi_open(fn, 1, 0, 1024, 1024, &er);
4312       if (NULL != db) {
4313         db_modified = 0;
4314       } else {
4315         /* ERROR: Failed to open database */
4316 	pqd_dbi_open_error(fn, &er);
4317         goto finished;
4318       }
4319     } else {
4320       /* ERROR: Failed to write initial entry to database */
4321       log_1(NULL, 0UL, LOG_EMERG, 1, 107);
4322       switch (er.ec) {
4323         case DK4_E_SYNTAX : {
4324 	  log_1(NULL, 0UL, LOG_EMERG, 1, 210);
4325 	} break;
4326 	case DK4_E_NOT_SUPPORTED : {
4327 	  log_1(NULL, 0UL, LOG_EMERG, 1, 211);
4328 	} break;
4329 	case DK4_E_MEMORY_ALLOCATION_FAILED : {
4330 	  log_1(NULL, 0UL, LOG_EMERG, 1, 212);
4331 	} break;
4332 	case DK4_E_OPEN_WRITE_FAILED : {
4333 	  log_1(NULL, 0UL, LOG_EMERG, 1, 213);
4334 	} break;
4335 	case DK4_E_WRITE_FAILED : {
4336 	  log_1(NULL, 0UL, LOG_EMERG, 1, 214);
4337 	} break;
4338 	case DK4_E_CLOSE_FAILED : {
4339 	  log_1(NULL, 0UL, LOG_EMERG, 1, 215);
4340 	} break;
4341 	case DK4_E_SEC_CHECK : {
4342 	  log_1(NULL, 0UL, LOG_EMERG, 1, 216);
4343 	} break;
4344 	default : {
4345 	  log_1(NULL, 0UL, LOG_EMERG, 1, 107);
4346 	} break;
4347       }
4348       goto finished;
4349     }
4350   } else {
4351     /* ERROR: Failed to open database */
4352     pqd_dbi_open_error(fn, &er);
4353     goto finished;
4354   }
4355 
4356   /*	Finally indicate success.
4357   */
4358   back = 1;
4359 
4360   finished:
4361 
4362   return back;
4363 }
4364 
4365 
4366 
4367 /**	Release resources after finishing inner loop.
4368 	* Log message for finishing service.
4369 	* Synchronize and close database.
4370 	* Close log file.
4371 */
4372 static
4373 int
inner_release_resources(void)4374 inner_release_resources(void)
4375 {
4376   const char	*fn;
4377   int		 back	= 1;
4378 
4379 
4380   /*	Database
4381   */
4382   if (NULL != db) {
4383     if (0 == dk4dbi_close(db, NULL)) {
4384       /* ERROR: Failed to synchronize database to disk */
4385       log_1(NULL, 0UL, LOG_EMERG, 1, 108);
4386       back = 0;
4387     }
4388     db = NULL;
4389     db_modified = 0;
4390   }
4391 
4392   /*	UDP socket set.
4393   */
4394   if (NULL != ss_udp) {
4395     dk4socket_set_close(ss_udp, NULL);
4396   }
4397   ss_udp = NULL;
4398 
4399   /*	TCP listener socket set.
4400   */
4401   if (NULL != ss_tcp) {
4402     dk4socket_set_close(ss_tcp, NULL);
4403   }
4404   ss_tcp = NULL;
4405 
4406   /*	Unix listener socket.
4407   */
4408   if (INVALID_SOCKET != so_unix) { dk4socket_close(so_unix, NULL); }
4409   so_unix = INVALID_SOCKET;
4410   fn = conf.sname;
4411   if (NULL == fn) { fn = def_sock_file_name; }
4412   (void)dk4delete_file_c8(fn, NULL);
4413 
4414 
4415   return back;
4416 }
4417 
4418 
4419 
4420 /**	Switch to non-privileged user and group if configured to do so.
4421 	@return	1 on success (can continue), 0 on error (exit).
4422 */
4423 static
4424 int
change_group_and_user(void)4425 change_group_and_user(void)
4426 {
4427   const char	*fn	= NULL;
4428 #if (!(DK4_HAVE_SETGROUPS)) && DK4_HAVE_INITGROUPS && DK4_HAVE_GETPWUID
4429   struct pwent	*pw;
4430 #endif
4431   uid_t		 myuid;
4432   gid_t		 mygid;
4433   int		 dbt	= DK4_DB_BE_UNKNOWN;
4434   int		 back	= 1;
4435 
4436   if (0 != user_switched) {
4437     if (conf.uid != prev_uid) {
4438       back = 0;
4439       /* ERROR: User to run as was changed */
4440       log_1(NULL, 0UL, LOG_EMERG, 1, 66);
4441     } else {
4442       if (conf.gid != prev_gid) {
4443         back = 0;
4444 	/* ERROR: Group to run as was changed */
4445 	log_1(NULL, 0UL, LOG_EMERG, 1, 67);
4446       }
4447     }
4448   } else {
4449     user_switched = 1;
4450     myuid = geteuid();
4451     mygid = getegid();
4452     if ((myuid != conf.uid) || (mygid != conf.gid)) {
4453       /*
4454 	  PID file ownership and permissions
4455       */
4456       if (0 != chown(pid_file_name, conf.uid, conf.gid)) {
4457         back = 0;
4458 	/* ERROR: Failed to change PID file ownership */
4459         log_1(NULL, 0UL, LOG_EMERG, 1, 217);
4460       }
4461       if (0 != chmod(pid_file_name, 0660)) {
4462         back = 0;
4463 	/* ERROR: Failed to change PID file permissions */
4464         log_1(NULL, 0UL, LOG_EMERG, 1, 218);
4465       }
4466       /*
4467     	  Log file ownership and permissions
4468       */
4469       fn = conf.lname;
4470       if (NULL == fn) { fn = def_log_file_name; }
4471       if (0 != chown(fn, conf.uid, conf.gid)) {
4472         back = 0;
4473         /* ERROR: Failed to change log file ownership */
4474         log_1(NULL, 0UL, LOG_EMERG, 1, 109);
4475       }
4476       if (0 != chmod(fn, 0660)) {
4477         back = 0;
4478         /* ERROR: Failed to change log file permissions */
4479         log_1(NULL, 0UL, LOG_EMERG, 1, 110);
4480       }
4481       /*
4482 	  Database ownership and permissions
4483       */
4484       if (0 == dk4dbi_change_owner_and_mode(db,conf.uid,conf.gid,0660,NULL)) {
4485         back = 0;
4486         /* ERROR: failed to change db ownership and permissions */
4487         log_1(NULL, 0UL, LOG_EMERG, 1, 111);
4488       }
4489       switch ( (dbt = dk4dbi_get_type(db)) ) {
4490         case DK4_DB_BE_BDB : case DK4_DB_BE_NDBM : {
4491 
4492           if (0 == dk4dbi_close(db, NULL)) {
4493 	    /* ERROR: Failed to synchronize database to disk */
4494 	    log_1(NULL, 0UL, LOG_EMERG, 1, 121);
4495 	  }
4496 	  db = NULL;
4497 	  db_modified = 0;
4498 	  if (DK4_DB_BE_BDB == dbt) {
4499 	    fn = ((NULL != conf.dname) ? (conf.dname) : (def_db_file_name));
4500 	    fn = dk4dbi_filename_part(fn);
4501 	    if (0 != chown(fn, conf.uid, conf.gid)) {
4502 	      back = 0;
4503 	      log_3(NULL, 0UL, LOG_EMERG, 1, 174, 175, fn);
4504 	    }
4505 	    if (0 != chmod(fn, 0660)) {
4506 	      back = 0;
4507 	      log_3(NULL, 0UL, LOG_EMERG, 1, 176, 177, fn);
4508 	    }
4509 	  }
4510         } break;
4511       }
4512       /*
4513 	  Local UNIX socket ownership and permission
4514       */
4515       if (INVALID_SOCKET != so_unix) {
4516 
4517         if (0 != fchown(so_unix, conf.uid, conf.gid)) {
4518           back = 0;
4519 	  /* ERROR: Failed to change socket ownership */
4520 	  log_1(NULL, 0UL, LOG_EMERG, 1, 112);
4521         }
4522 
4523         if (0 != fchmod(so_unix, 0660)) {
4524           back = 0;
4525 	  /* ERROR: Failed to change socket permissions */
4526 	  log_1(NULL, 0UL, LOG_EMERG, 1, 113);
4527         }
4528       } else {
4529       }
4530 #if DK4_HAVE_SETGROUPS
4531       if (0 != setgroups(1, &(conf.gid))) {
4532         back = 0;
4533 	log_1(NULL, 0UL, LOG_EMERG, 1, 114);
4534       }
4535 #else
4536 #if DK4_HAVE_INITGROUPS && DK4_HAVE_GETPWUID
4537       pw = getpwuid(myuid);
4538       if (NULL != pw) {
4539         if (NULL != pw->pw_name) {
4540 	  if (0 != initgroups(pw->pw_name, conf.gid)) {
4541 	    back = 0;
4542 	    log_1(NULL, 0UL, LOG_EMERG, 1, 114);
4543 	  }
4544 	}
4545       }
4546 #endif
4547 #endif
4548       /*
4549 	  Switch group
4550       */
4551       if (mygid != conf.gid) {
4552         if (0 != setgid(conf.gid)) {
4553           back = 0;
4554           /* ERROR: Failed to switch group */
4555           log_1(NULL, 0UL, LOG_EMERG, 1, 114);
4556         }
4557       }
4558       /*
4559 	  Switch user
4560       */
4561       if (myuid != conf.uid) {
4562         if (0 != setuid(conf.uid)) {
4563           back = 0;
4564           /* ERROR: Failed to switch user */
4565           log_1(NULL, 0UL, LOG_EMERG, 1, 115);
4566         }
4567       }
4568       /*
4569 	  Re-open database if closed.
4570       */
4571       if (NULL == db) {
4572         fn = conf.dname;
4573         if (NULL == fn) { fn = def_db_file_name; }
4574         db = dk4dbi_open(fn, 1, 0, 1024, 1024, NULL);
4575         if (NULL != db) {
4576           db_modified = 0;
4577         } else {
4578           back = 0;
4579 	  /* ERROR: Failed to open database */
4580 	  log_3(NULL, 0UL, LOG_EMERG, 1, 105, 106, fn);
4581         }
4582       }
4583     } else {
4584     }
4585   }
4586 
4587   return back;
4588 }
4589 
4590 
4591 
4592 static
4593 int
protocol_level_for_address(struct sockaddr * so)4594 protocol_level_for_address(struct sockaddr *so)
4595 {
4596   int		 back	= PQD_PROTO_NONE;
4597 
4598   if (0 != conf.aglo) {
4599     back = PQD_PROTO_ADMIN;
4600   } else {
4601     if (NULL != dk4sto_it_find_like(conf.i_aa, so, 1)) {
4602       back = PQD_PROTO_ADMIN;
4603     } else {
4604       if (0 != conf.dglo) {
4605         back = PQD_PROTO_DATA;
4606       } else {
4607         if (NULL != dk4sto_it_find_like(conf.i_ad, so, 1)) {
4608 	  back = PQD_PROTO_DATA;
4609 	} else {
4610 	  if (0 != conf.iglo) {
4611 	    back = PQD_PROTO_INFO;
4612 	  } else {
4613 	    if (NULL != dk4sto_it_find_like(conf.i_ai, so, 1)) {
4614 	      back = PQD_PROTO_INFO;
4615 	    }
4616 	  }
4617 	}
4618       }
4619     }
4620   }
4621 
4622   return back;
4623 }
4624 
4625 
4626 
4627 /**	Check whether the action is allowed in the protocol level.
4628 	@param	act	Action to check.
4629 	@param	protlev	Protocol level.
4630 	@return	1 if action is allowed, 0 otherwise.
4631 */
4632 static
4633 int
protocol_level_check(int act,int protlev)4634 protocol_level_check(int act, int protlev)
4635 {
4636   int		 back	= 0;
4637 
4638   switch (act) {
4639     case PQD_CMD_INFO : {
4640       if (PQD_PROTO_INFO <= protlev) { back = 1; }
4641     } break;
4642     case PQD_CMD_CONTROL : {
4643       if (PQD_PROTO_ADMIN <= protlev) { back = 1; }
4644     } break;
4645     default : {
4646       if (PQD_PROTO_DATA <= protlev) { back = 1; }
4647     } break;
4648   }
4649 
4650   return back;
4651 }
4652 
4653 
4654 
4655 static
4656 void
job_init(pqd_rq_t * ptr)4657 job_init(pqd_rq_t *ptr)
4658 {
4659 
4660   DK4_MEMRES(ptr, sizeof(pqd_rq_t));
4661   ptr->connptr = NULL;
4662   ptr->sto     = NULL;
4663   ptr->soa     = NULL;
4664   ptr->pnconn  = NULL;
4665   ptr->cmdptr  = NULL;
4666   ptr->argptr  = NULL;
4667   ptr->szsoa   = 0;
4668   ptr->sock    = 0;
4669   ptr->action  = 0;
4670   ptr->protlev = PQD_PROTO_NONE;
4671   ptr->logthis = 1;
4672 
4673 }
4674 
4675 
4676 
4677 static
4678 void
account_init(pqd_account_t * ptr)4679 account_init(pqd_account_t *ptr)
4680 {
4681 
4682   DK4_MEMRES(ptr, sizeof(pqd_account_t));
4683   ptr->limit   = (dk4_um_t)0UL;
4684   ptr->used    = (dk4_um_t)0UL;
4685   ptr->account = (dk4_um_t)0UL;
4686   ptr->da      = 0;
4687 
4688 }
4689 
4690 
4691 
4692 /**	Close a stream connection record.
4693 	@param	sock	Socket to close.
4694 	@param	sto	Container for the records.
4695 	@param	ptr	Record to delete, containing the socket.
4696 	@param	pnconn	Address of connection number variable to decrease.
4697 */
4698 static
4699 void
close_stream_conn(dk4_socket_t sock,dk4_sto_t * sto,void * ptr,size_t * pnconn)4700 close_stream_conn(
4701   dk4_socket_t	 sock,
4702   dk4_sto_t	*sto,
4703   void		*ptr,
4704   size_t	*pnconn
4705 )
4706 {
4707 
4708   if ((NULL != sto) && (NULL != ptr)) {
4709     dk4sto_remove(sto, ptr, NULL);
4710   }
4711   if (INVALID_SOCKET != sock) {
4712     (void)dk4socket_close(sock, NULL);
4713   }
4714   if (NULL != ptr) {
4715     dk4mem_free(ptr);
4716   }
4717   if (NULL != pnconn) {
4718     if (0 < *pnconn) {
4719       *pnconn -= 1;
4720     }
4721   }
4722 
4723 }
4724 
4725 
4726 
4727 /**	Send a text response.
4728 	@param	job	Job structure.
4729 	@param	str	Text to send (still without newline).
4730 */
4731 static
4732 void
send_text(pqd_rq_t * job,const char * str)4733 send_text(pqd_rq_t *job, const char *str)
4734 {
4735   const char *	msgs[3];	/* Log message text parts */
4736   size_t	sz;		/* Number of bytes to send */
4737   size_t	wr;		/* Number of bytes successfully sent */
4738   int		res;		/* Operation result */
4739 
4740   if (0 != dk4str8_cpy_s(inbuf, sizeof(inbuf), str, NULL)) {
4741     if (0 != job->logthis) {
4742       msgs[0] = printqd_kw[86];
4743       msgs[1] = str;
4744       msgs[2] = NULL;
4745       log_multipart_message(NULL, 0UL, LOG_EMERG, 0, msgs, 2);
4746     }
4747     if (0 != dk4str8_cat_s(inbuf, sizeof(inbuf), printqd_kw[5], NULL)) {
4748       sz = dk4str8_len(inbuf);
4749       wr = sz;
4750       if ((NULL != job->soa) && (0 < job->szsoa)) {
4751         (void)dk4socket_sendto(
4752 	  job->sock, inbuf, &wr, 0, job->soa, job->szsoa, 0L, 0L, NULL
4753 	);
4754       } else {
4755         res = dk4socket_send(job->sock, inbuf, &wr, 0, 0L, 0L, NULL);
4756 	switch (res) {
4757 	  case DK4_SOCKET_RESULT_SUCCESS :
4758 	  case DK4_SOCKET_RESULT_IN_PROGRESS : {
4759 	    if (wr != sz) {
4760 	      res = DK4_SOCKET_RESULT_FAILED;
4761 	    }
4762 	  } break;
4763 	}
4764 	if (DK4_SOCKET_RESULT_FAILED == res) {
4765 	  close_stream_conn(job->sock, job->sto, job->connptr, job->pnconn);
4766 	}
4767       }
4768     } else {
4769       /* ERROR: Response text too long (BUG)! */
4770       log_1(NULL, 0UL, LOG_EMERG, 1, 116);
4771     }
4772   } else {
4773     /* ERROR: Response text too long (BUG)! */
4774     log_1(NULL, 0UL, LOG_EMERG, 1, 116);
4775   }
4776 
4777 }
4778 
4779 
4780 
4781 /**	Send response for info or acct-check request.
4782 	@param	job	Job structure.
4783 	@param	account	Account structure containing limits and used pages.
4784 	@param	summary	Summary: Allowed to print.
4785 	@param	how	How to respond: 0=info, 1=acct-check/jobstart.
4786 */
4787 static
4788 void
send_response(pqd_rq_t * job,pqd_account_t * account,int summary,int how)4789 send_response(
4790   pqd_rq_t	*job,
4791   pqd_account_t	*account,
4792   int		 summary,
4793   int		 how
4794 )
4795 {
4796   char		res[16+32*sizeof(dk4_um_t)];
4797   char		b1[16+8*sizeof(dk4_um_t)];
4798   int		ok	= 0;
4799 
4800   switch (how) {
4801     case 0: {
4802       /* Limit Used Account Summary */
4803       if (DK4_UM_MAX == account->limit) {
4804         ok = dk4str8_cpy_s(res, sizeof(res), printqd_kw[84], NULL);
4805       } else {
4806         ok = dk4ma_write_c8_decimal_unsigned(
4807 	  b1, sizeof(b1), account->limit, 0, NULL
4808 	);
4809 	if (0 != ok) {
4810 	  ok = dk4str8_cpy_s(res, sizeof(res), b1, NULL);
4811 	}
4812       }
4813       if (0 != ok) {
4814 	ok = dk4ma_write_c8_decimal_unsigned(
4815 	  b1, sizeof(b1), account->used, 0, NULL
4816 	);
4817 	if (0 != ok) {
4818 	  ok = dk4str8_cat_s(res, sizeof(res), printqd_kw[85], NULL);
4819 	  if (0 != ok) {
4820 	    ok = dk4str8_cat_s(res, sizeof(res), b1, NULL);
4821 	    if (0 != ok) {
4822 	      ok = dk4ma_write_c8_decimal_unsigned(
4823 	        b1, sizeof(b1), account->account, 0, NULL
4824 	      );
4825 	      if (0 != ok) {
4826 	        ok = dk4str8_cat_s(res, sizeof(res), printqd_kw[85], NULL);
4827 		if (0 != ok) {
4828 		  ok = dk4str8_cat_s(res, sizeof(res), b1, NULL);
4829 		  if (0 != ok) {
4830 		    ok = dk4ma_write_c8_decimal_signed(
4831 		      b1, sizeof(b1), (dk4_im_t)summary, 0, NULL
4832 		    );
4833 		    if (0 != ok) {
4834 		      ok = dk4str8_cat_s(res,sizeof(res),printqd_kw[85],NULL);
4835 		      if (0 != ok) {
4836 		        ok = dk4str8_cat_s(res, sizeof(res), b1, NULL);
4837 		      }
4838 		    }
4839 		  }
4840 		}
4841 	      }
4842 	    }
4843 	  }
4844 	}
4845       }
4846       if (0 != ok) {
4847         send_text(job, res);
4848       } else {
4849         send_text(job, printqd_kw[83]);
4850       }
4851     } break;
4852     default: {
4853       if (0 != summary) {
4854         send_text(job, printqd_kw[80]);
4855       } else {
4856         switch (account->da) {
4857 	  case 0: {
4858 	    send_text(job, printqd_kw[81]);
4859 	  } break;
4860 	  default: {
4861 	    send_text(job, printqd_kw[82]);
4862 	  } break;
4863 	}
4864       }
4865     } break;
4866   }
4867 
4868 }
4869 
4870 
4871 
4872 /**	Get printer entry for name (printer or alias name).
4873 	@param	name	Printer or alias name.
4874 	@return	Printer entry.
4875 */
4876 static
4877 pqd_printer_t *
get_printer_for_name(const char * name)4878 get_printer_for_name(const char *name)
4879 {
4880   pqd_printer_t		*back	= NULL;
4881   pqd_printer_alias_t	*al	= NULL;
4882 
4883   back = (pqd_printer_t *)dk4sto_it_find_like(conf.i_p, name, 1);
4884   if (NULL == back) {
4885     al = (pqd_printer_alias_t *)dk4sto_it_find_like(conf.i_a, name, 1);
4886     if (NULL != al) {
4887       back = al->pr;
4888     }
4889   }
4890 
4891   return back;
4892 }
4893 
4894 
4895 
4896 /**	Save one dk4_um_t value to database.
4897 	@param	kwi	Keyword index for key start.
4898 	@param	un	User name.
4899 	@param	cn	Class name.
4900 	@param 	val	Value to store.
4901 	@return	1 on success, 0 on error.
4902 */
4903 static
4904 int
save_one_number(size_t kwi,const char * un,const char * cn,dk4_um_t val)4905 save_one_number(
4906   size_t	 kwi,
4907   const char	*un,
4908   const char	*cn,
4909   dk4_um_t	 val
4910 )
4911 {
4912   int		 back	= 0;
4913   int		 strok	= 0;
4914 
4915   if (0 != dk4str8_cpy_s(kb, sizeof(kb), printqd_kw[kwi], NULL)) {
4916     if (0 != dk4str8_cat_s(kb, sizeof(kb), cn, NULL)) {
4917       if (0 != dk4str8_cat_s(kb, sizeof(kb), printqd_kw[8], NULL)) {
4918         if (0 != dk4str8_cat_s(kb, sizeof(kb), un, NULL)) {
4919 	  if ((dk4_um_t)0UL != val) {
4920 	    if(0 != dk4ma_write_c8_decimal_unsigned(vb,sizeof(vb),val,0,NULL)) {
4921 	      strok = 1;
4922 
4923 	      if (0 != dbi_set(db, kb, vb, NULL)) {
4924 	        back = 1;
4925 	      }
4926 	      else {
4927 	        /* ERROR: Failed to set DB entry */
4928 		log_1(NULL, 0UL, LOG_EMERG, 1, 117);
4929 	      }
4930 	    }
4931 #if TRACE_DEBUG
4932 	    else {
4933 	    }
4934 #endif
4935 	  } else {
4936 	    strok = 1;
4937 
4938 	    if (0 != dbi_del(db, kb, NULL)) {
4939 	      back = 1;
4940 	    } else {
4941 	      /* ERROR: Failed to delete DB entry */
4942 	      log_1(NULL, 0UL, LOG_EMERG, 1, 118);
4943 	    }
4944 	  }
4945 	}
4946       }
4947     }
4948   }
4949   if (0 == strok) {
4950     /* ##### ERROR: Strings too long */
4951   }
4952 
4953   return back;
4954 }
4955 
4956 
4957 
4958 /**	Save changes in account to database.
4959 	@param	oldacc	Previous account information, may be NULL.
4960 	@param	newacc	Updated account information, not NULL.
4961 	@param	un	User name.
4962 	@param	cl	Class structure.
4963 	@return	1 on success, 0 on error.
4964 */
4965 static
4966 int
save_account_for_user_and_class(pqd_account_t * oldacc,pqd_account_t * newacc,const char * un,pqd_class_t * cl)4967 save_account_for_user_and_class(
4968   pqd_account_t	*oldacc,
4969   pqd_account_t	*newacc,
4970   const char	*un,
4971   pqd_class_t	*cl
4972 )
4973 {
4974   int		 mustsave;		/* Flag: Must save item */
4975   int		 back		= 1;
4976 
4977   mustsave = 1;
4978   if (NULL != oldacc) {
4979     if (oldacc->used == newacc->used) {
4980       mustsave = 0;
4981     }
4982   }
4983   if (0 != mustsave) {
4984     if (0 == save_one_number(88, un, cl->name, newacc->used)) {
4985       back = 0;
4986     }
4987   }
4988   mustsave = 1;
4989   if (NULL != oldacc) {
4990     if (oldacc->account == newacc->account) {
4991       mustsave = 0;
4992     }
4993   }
4994   if (0 != mustsave) {
4995     if (0 == save_one_number(89, un, cl->name, newacc->account)) {
4996       back = 0;
4997     }
4998   }
4999 
5000   return back;
5001 }
5002 
5003 
5004 
5005 /**	Retrieve account data for a user in a specified printer class.
5006 	@param	account	Data structure to fill.
5007 	@param	un	User name.
5008 	@param	cl	Printer class.
5009 	@param	mi	Flag: Must initialize account before filling it.
5010 	@return	1 on success, 0 on error.
5011 */
5012 static
5013 int
retrieve_account_for_user_and_class(pqd_account_t * account,const char * un,pqd_class_t * cl,int mi)5014 retrieve_account_for_user_and_class(
5015   pqd_account_t	*account,
5016   const char	*un,
5017   pqd_class_t	*cl,
5018   int		 mi
5019 )
5020 {
5021   char		**grmem	= NULL;
5022   const char	 *ep	= NULL;			/* End of data */
5023   pqd_limit_t	 *lim	= NULL;			/* Limit set */
5024   struct passwd	 *pw	= NULL;			/* Password struct */
5025   struct group	 *gr	= NULL;			/* Group struct */
5026   dk4_um_t	  um	= (dk4_um_t)0UL;	/* Value found in text */
5027   gid_t		  pg	= 0;			/* Primary group */
5028   int		  ingr	= 0;			/* Flag: User in group */
5029   int		 back	= 0;
5030 
5031   /*
5032 	Check arguments
5033   */
5034   if (NULL == account) {
5035     goto finished;
5036   }
5037   if (0 != mi) {
5038     account_init(account);
5039   }
5040   if ((NULL == un) || (NULL == cl)) {
5041     goto finished;
5042   }
5043   if (NULL == cl->name) {
5044     goto finished;
5045   }
5046   /*
5047 	Use default action from class
5048   */
5049   account->da = cl->da;
5050   /*
5051 	Find number of pages already printed
5052   */
5053   if (0 != dk4str8_cpy_s(kb, sizeof(kb), printqd_kw[88], NULL)) {
5054     if (0 != dk4str8_cat_s(kb, sizeof(kb), cl->name, NULL)) {
5055       if (0 != dk4str8_cat_s(kb, sizeof(kb), printqd_kw[8], NULL)) {
5056         if (0 != dk4str8_cat_s(kb, sizeof(kb), un, NULL)) {
5057 
5058 	  if (0 != dbi_get(db, kb, vb, sizeof(vb), NULL)) {
5059 	    if (0 != dk4ma_input_c8_dec_dk4_um_t(&um, vb, &ep, 1, NULL)) {
5060 	      account->used = um;
5061 	    }
5062 #if TRACE_DEBUG
5063 	    else {
5064 	    }
5065 #endif
5066 	  }
5067 #if TRACE_DEBUG
5068 	  else {
5069 	  }
5070 #endif
5071 	}
5072       }
5073     }
5074   }
5075   /*
5076 	Find number of pages in personal print account
5077   */
5078   if (0 != dk4str8_cpy_s(kb, sizeof(kb), printqd_kw[89], NULL)) {
5079     if (0 != dk4str8_cat_s(kb, sizeof(kb), cl->name, NULL)) {
5080       if (0 != dk4str8_cat_s(kb, sizeof(kb), printqd_kw[8], NULL)) {
5081         if (0 != dk4str8_cat_s(kb, sizeof(kb), un, NULL)) {
5082 
5083 	  if (0 != dbi_get(db, kb, vb, sizeof(vb), NULL)) {
5084 	    um = (dk4_um_t)0UL; ep = NULL;
5085 	    if (0 != dk4ma_input_c8_dec_dk4_um_t(&um, vb, &ep, 1, NULL)) {
5086 	      account->account = um;
5087 	    }
5088 #if TRACE_DEBUG
5089 	    else {
5090 	    }
5091 #endif
5092 	  }
5093 #if TRACE_DEBUG
5094 	  else {
5095 	  }
5096 #endif
5097 	}
5098       }
5099     }
5100   }
5101   /*
5102 	Find user limit
5103   */
5104 
5105   lim = (pqd_limit_t *)dk4sto_it_find_like(cl->i_u, un, 1);
5106   if (NULL != lim) {
5107     account->limit = lim->limit;
5108     back = 1;
5109     goto finished;
5110   }
5111   /*
5112 	Find group limit
5113   */
5114 
5115   pw = getpwnam(un);
5116   if (NULL != pw) {
5117     pg = pw->pw_gid;
5118     dk4sto_it_reset(cl->i_g);
5119     do {
5120 
5121       lim = (pqd_limit_t *)dk4sto_it_next(cl->i_g);
5122       if (NULL != lim) {
5123         if (lim->limit > account->limit) {
5124 
5125 	  gr = getgrnam(lim->name);
5126 	  if (NULL != gr) {
5127 	    if (pg == gr->gr_gid) {
5128 	      account->limit = lim->limit;
5129 	      back = 1;
5130 	    } else {
5131 	      if (NULL != gr->gr_mem) {
5132 	        grmem = gr->gr_mem;
5133 		ingr  = 0;
5134 		while ((0 == ingr) && (NULL != *grmem)) {
5135 
5136 		  if (0 == strcmp(un, *grmem)) {
5137 		    ingr = 1;
5138 		  }
5139 		  grmem++;
5140 		}
5141 		if (0 != ingr) {
5142 		  account->limit = lim->limit;
5143 		  back = 1;
5144 		}
5145 #if TRACE_DEBUG
5146 		else {
5147 		}
5148 #endif
5149 	      }
5150 #if TRACE_DEBUG
5151 	      else {
5152 	      }
5153 #endif
5154 	    }
5155 	  }
5156 #if TRACE_DEBUG
5157 	  else {
5158 	  }
5159 #endif
5160 	}
5161       }
5162 #if TRACE_DEBUG
5163       else {
5164       }
5165 #endif
5166 
5167     } while(NULL != lim);
5168     if (0 != back) {
5169       goto finished;
5170     }
5171   }
5172 #if TRACE_DEBUG
5173   else {
5174   }
5175 #endif
5176   /*
5177 	Apply default limit
5178   */
5179 
5180   account->limit = cl->dl;
5181   back = 1;
5182 
5183   finished:
5184 
5185   return back;
5186 }
5187 
5188 
5189 
5190 /**	Retrieve user account data for a given user name and a given printer
5191 	name.
5192 	@param	account		Account structure to fill.
5193 	@param	printer_name	Print queue name or alias.
5194 	@param	user_name	User name.
5195 	@return	1 on success, 0 on error.
5196 */
5197 static
5198 int
retrieve_account_data(pqd_account_t * account,const char * printer_name,const char * user_name)5199 retrieve_account_data(
5200   pqd_account_t	*account,
5201   const char	*printer_name,
5202   const char	*user_name
5203 )
5204 {
5205   pqd_printer_t	 *pr	= NULL;			/* Printer */
5206   pqd_class_t	 *cl	= NULL;			/* Class */
5207   int		  back	= 0;
5208 
5209   /*
5210 	Initialize account data
5211   */
5212   account_init(account);
5213   /*
5214 	Find printer
5215   */
5216   pr = get_printer_for_name(printer_name);
5217   if (NULL == pr) {
5218     goto finished;
5219   }
5220   /*
5221 	Find class for printer
5222   */
5223   cl = pr->cl;
5224   if (NULL == cl) {
5225     goto finished;
5226   }
5227   if (NULL == cl->name) {
5228     goto finished;
5229   }
5230   /*
5231 	Search for data
5232   */
5233   back = retrieve_account_for_user_and_class(account, user_name, cl, 0);
5234   /*
5235 	Return result
5236   */
5237   finished:
5238 
5239   return back;
5240 }
5241 
5242 
5243 
5244 /**	Add a number of pages for a print job to existing account data.
5245 	@param	account	Account data for user.
5246 	@param	pages	Number of pages used by print job.
5247 */
5248 static
5249 void
account_add_pages_from_job(pqd_account_t * account,dk4_um_t pages)5250 account_add_pages_from_job(pqd_account_t *account, dk4_um_t pages)
5251 {
5252   dk4_um_t		available;
5253 
5254   /*	The limit is used first.
5255   */
5256   if (account->limit > account->used) {
5257     available = account->limit - account->used;
5258     if (available >= pages) {
5259       account->used += pages;
5260       pages = (dk4_um_t)0UL;
5261     } else {
5262       account->used = account->limit;
5263       pages -= available;
5264     }
5265   }
5266   /*	The personal print account is used only if the limit is reached.
5267   */
5268   if ((dk4_um_t)0UL < pages) {
5269     if (account->account >= pages) {
5270       account->account -= pages;
5271       pages = (dk4_um_t)0UL;
5272     } else {
5273       pages -= account->account;
5274       account->account = (dk4_um_t)0UL;
5275     }
5276   }
5277   /*	Finally keep track of pages printed over limit.
5278   */
5279   if ((dk4_um_t)0UL < pages) {
5280     if ((DK4_UM_MAX - pages) >= account->used) {
5281       account->used += pages;
5282     } else {
5283       account->used =  DK4_UM_MAX;
5284     }
5285   }
5286 }
5287 
5288 
5289 
5290 /**	Find summary (allowed to print) for account details.
5291 	@param	limit	Limit (maximum number of pages) for user.
5292 	@param	used	Number of used pages within the limit.
5293 	@param	account	Number of pages in additional personal print account.
5294 	@return	1 if printing is allowed, 0 otherwise.
5295 */
5296 static
5297 int
account_summary(dk4_um_t limit,dk4_um_t used,dk4_um_t account)5298 account_summary(dk4_um_t limit, dk4_um_t used, dk4_um_t account)
5299 {
5300   int		 back	= 0;
5301 
5302   if (DK4_UM_MAX == limit) {
5303     back = 1;
5304   } else {
5305     if (used < limit) {
5306       back = 1;
5307     } else {
5308       if ((dk4_um_t)0UL < account) {
5309         back = 1;
5310       }
5311     }
5312   }
5313 
5314   return back;
5315 }
5316 
5317 
5318 /**	Process info or acct-check request, only retrieve data
5319 	without modifying anything.
5320 	@param	job	Data for one request to process.
5321 	@param	how	Response type: 0=info, 1=acct-check.
5322 */
5323 static
5324 void
rq_retrieve_data(pqd_rq_t * job,int how)5325 rq_retrieve_data(pqd_rq_t *job, int how)
5326 {
5327   pqd_account_t	 account;
5328   char		*printer_name	= NULL;
5329   char		*user_name	= NULL;
5330   int		 summary	= 0;
5331 
5332   printer_name = job->argptr;
5333   if (NULL != printer_name) {
5334     user_name = dk4str8_next(printer_name, NULL);
5335     if (NULL != user_name) {
5336       (void)dk4str8_next(user_name, NULL);
5337     }
5338   }
5339   if ((NULL != printer_name) && (NULL != user_name)) {
5340     if (0 != retrieve_account_data(&account, printer_name, user_name)) {
5341 #if VERSION_BEFORE_20160329
5342       if ((account.used < account.limit) || ((dk4_um_t)0UL < account.account)) {
5343         summary = 1;
5344       }
5345 #else
5346       summary = account_summary(account.limit, account.used, account.account);
5347 #endif
5348     }
5349     send_response(job, &account, summary, how);
5350   } else {
5351     /*	Close connection on malformed request.
5352     */
5353     if ((NULL == job->soa) && (0 == job->szsoa)) {
5354       close_stream_conn(job->sock, job->sto, job->connptr, job->pnconn);
5355     }
5356   }
5357 
5358 }
5359 
5360 
5361 
5362 /**	Process info request.
5363 	@param	job	Data for one request to process.
5364 */
5365 static
5366 void
rq_info(pqd_rq_t * job)5367 rq_info(pqd_rq_t *job)
5368 {
5369 
5370   rq_retrieve_data(job, 0);
5371 
5372 }
5373 
5374 
5375 
5376 /**	Find final quote for current word.
5377 	@param	str	String to find quote in.
5378 	@param	quote	Quote character.
5379 	@return	Pointer to found quote on success, NULL on error.
5380 */
5381 static
5382 char *
lprng_final_quote(char * str,char quote)5383 lprng_final_quote(char *str, char quote)
5384 {
5385   char		*back	= NULL;
5386 
5387   while (('\0' != *str) && (NULL == back)) {
5388     if (quote == *str) {
5389       *str = '\0';
5390       back = str;
5391       back++;
5392       back = dk4str8_start(back, NULL);
5393     } else {
5394       if ('\\' == *str) {
5395         if ('\0' != str[1]) {
5396 	  dk4str8_cpy_to_left(str, &(str[1]));
5397 	  str++;
5398 	} else {
5399 	  *str = '\0';
5400 	}
5401       } else {
5402         str++;
5403       }
5404     }
5405   }
5406 
5407   return back;
5408 }
5409 
5410 
5411 
5412 /**	Find start of next text word in LPRng accounting line.
5413 	@param	str	Current word (remaining text) in accounting line.
5414 	@return	Pointer to next word if found, NULL on error.
5415 */
5416 static
5417 char *
lprng_next_word(char * str)5418 lprng_next_word(char *str)
5419 {
5420   char		*back	= NULL;
5421 
5422   switch (*str) {
5423     case '\'' : {
5424       back = lprng_final_quote(&(str[1]), '\'');
5425     } break;
5426     case '"'  : {
5427       back = lprng_final_quote(&(str[1]), '"');
5428     } break;
5429     default : {
5430       back = dk4str8_next(str, NULL);
5431     } break;
5432   }
5433   return back;
5434 }
5435 
5436 
5437 
5438 /**	Fill data structure from LPRng accounting line.
5439 	@param	liptr		Structure to fill.
5440 	@param	textline	The text line to use.
5441 	@return	1 on success, 0 on error.
5442 */
5443 static
5444 int
lprng_info_from_line(lprng_info_t * liptr,char * textline)5445 lprng_info_from_line(lprng_info_t *liptr, char *textline)
5446 {
5447   char		*next;
5448   int		 back	= 1;
5449 
5450   DK4_MEMRES(liptr, sizeof(lprng_info_t));
5451   liptr->username = NULL; liptr->queuename = NULL;
5452   liptr->jobtitle = NULL; liptr->pagecount = NULL;
5453   while (NULL != textline) {
5454     next = lprng_next_word(textline);
5455     if (('\'' == *textline) || ('"' == *textline)) {
5456       textline++;
5457     }
5458     if ('-' == *textline) {
5459       textline++;
5460       switch (*textline) {
5461         case 'n': {
5462 	  liptr->username = ++textline;
5463 	} break;
5464 	case 'P': {
5465 	  liptr->queuename = ++textline;
5466 	} break;
5467 	case 'J': {
5468 	  liptr->jobtitle = ++textline;
5469 	} break;
5470 	case 'p': {
5471 	  liptr->pagecount = ++textline;
5472 	} break;
5473       }
5474     } else {
5475 #if 0
5476       /*	2016-02-15	Simply ignore non-option text.
5477       */
5478       back = 0;
5479       /* ERROR: No minus sign */
5480 #endif
5481     }
5482     textline = next;
5483   }
5484 
5485   return back;
5486 }
5487 
5488 
5489 
5490 /**	Process jobstart request.
5491 	@param	job	Data for one request to process.
5492 */
5493 static
5494 void
rq_jobstart(pqd_rq_t * job)5495 rq_jobstart(pqd_rq_t *job)
5496 {
5497   lprng_info_t		 lpi;
5498   pqd_account_t		 account;
5499   char			*un	= NULL;
5500   char			*qn	= NULL;
5501   int			 summ	= 0;
5502 
5503   if (0 != lprng_info_from_line(&lpi, job->argptr)) {
5504     un = lpi.username; qn = lpi.queuename;
5505   }
5506   if ((NULL != un) && (NULL != qn)) {
5507     if (0 != retrieve_account_data(&account, qn, un)) {
5508       summ = account_summary(account.limit, account.used, account.account);
5509     }
5510     send_response(job, &account, summ, 1);
5511   } else {
5512     /*	Close connection on malformed request.
5513     */
5514     if ((NULL == job->soa) && (0 == job->szsoa)) {
5515       close_stream_conn(job->sock, job->sto, job->connptr, job->pnconn);
5516     }
5517   }
5518 
5519 }
5520 
5521 
5522 
5523 /**	Report change result to log file.
5524 	@param	un	User name.
5525 	@param	cl	Class.
5526 	@param	olda	Old account values.
5527 	@param	newa	New account values.
5528 	@param	pages	Number of pages to add.
5529 	@param	doadd	Flag: Show added pages instead of used pages.
5530 */
5531 static
5532 void
log_old_and_new_account(const char * un,const pqd_class_t * cl,const pqd_account_t * olda,const pqd_account_t * newa,dk4_um_t pages,int doadd)5533 log_old_and_new_account(
5534   const char		*un,
5535   const pqd_class_t	*cl,
5536   const pqd_account_t	*olda,
5537   const pqd_account_t	*newa,
5538   dk4_um_t		 pages,
5539   int			 doadd
5540 )
5541 {
5542   char		 nb[8*sizeof(dk4_um_t)];
5543   const char	*msgs[2];
5544   int		 res	= 1;
5545   if (0 == dk4str8_cpy_s(kb, sizeof(kb), un, NULL)) { res = 0; }
5546   if (0 == dk4str8_cat_s(kb, sizeof(kb), printqd_kw[85], NULL)) { res = 0; }
5547   if (0 == dk4str8_cat_s(kb, sizeof(kb), cl->name, NULL)) { res = 0; }
5548   if (0 == dk4str8_cat_s(kb, sizeof(kb), printqd_kw[7], NULL)) { res = 0; }
5549   if (0 == dk4str8_cat_s(kb, sizeof(kb), printqd_kw[145], NULL)) { res = 0; }
5550   if (DK4_UM_MAX == olda->limit) {
5551     if (0 == dk4str8_cat_s(kb, sizeof(kb), printqd_kw[151], NULL)) { res = 0; }
5552   } else {
5553     if(0 != dk4ma_write_c8_decimal_unsigned(nb,sizeof(nb),olda->limit,0,NULL)) {
5554       if (0 == dk4str8_cat_s(kb, sizeof(kb), nb, NULL)) { res = 0; }
5555     } else {
5556       res = 0;
5557     }
5558   }
5559   if (0 == dk4str8_cat_s(kb, sizeof(kb), printqd_kw[146], NULL)) { res = 0; }
5560   if(0 != dk4ma_write_c8_decimal_unsigned(nb,sizeof(nb),olda->used,0,NULL)) {
5561     if (0 == dk4str8_cat_s(kb, sizeof(kb), nb, NULL)) { res = 0; }
5562   } else {
5563     res = 0;
5564   }
5565   if (0 == dk4str8_cat_s(kb, sizeof(kb), printqd_kw[147], NULL)) { res = 0; }
5566   if(0 != dk4ma_write_c8_decimal_unsigned(nb,sizeof(nb),olda->account,0,NULL)) {
5567     if (0 == dk4str8_cat_s(kb, sizeof(kb), nb, NULL)) { res = 0; }
5568   } else {
5569     res = 0;
5570   }
5571   switch (doadd) {
5572     case 1: {
5573       if (0 == dk4str8_cat_s(kb,sizeof(kb),printqd_kw[153],NULL)) { res = 0; }
5574     } break;
5575     default: {
5576       if (0 == dk4str8_cat_s(kb,sizeof(kb),printqd_kw[148],NULL)) { res = 0; }
5577     } break;
5578   }
5579   if(0 != dk4ma_write_c8_decimal_unsigned(nb,sizeof(nb),pages,0,NULL)) {
5580     if (0 == dk4str8_cat_s(kb, sizeof(kb), nb, NULL)) { res = 0; }
5581   } else {
5582     res = 0;
5583   }
5584   if (0 == dk4str8_cat_s(kb, sizeof(kb), printqd_kw[149], NULL)) { res = 0; }
5585   if (DK4_UM_MAX == newa->limit) {
5586     if (0 == dk4str8_cat_s(kb, sizeof(kb), printqd_kw[151], NULL)) { res = 0; }
5587   } else {
5588     if(0 != dk4ma_write_c8_decimal_unsigned(nb,sizeof(nb),newa->limit,0,NULL)) {
5589       if (0 == dk4str8_cat_s(kb, sizeof(kb), nb, NULL)) { res = 0; }
5590     } else {
5591       res = 0;
5592     }
5593   }
5594   if (0 == dk4str8_cat_s(kb, sizeof(kb), printqd_kw[146], NULL)) { res = 0; }
5595   if(0 != dk4ma_write_c8_decimal_unsigned(nb,sizeof(nb),newa->used,0,NULL)) {
5596     if (0 == dk4str8_cat_s(kb, sizeof(kb), nb, NULL)) { res = 0; }
5597   } else {
5598     res = 0;
5599   }
5600   if (0 == dk4str8_cat_s(kb, sizeof(kb), printqd_kw[147], NULL)) { res = 0; }
5601   if(0 != dk4ma_write_c8_decimal_unsigned(nb,sizeof(nb),newa->account,0,NULL)) {
5602     if (0 == dk4str8_cat_s(kb, sizeof(kb), nb, NULL)) { res = 0; }
5603   } else {
5604     res = 0;
5605   }
5606   if (0 == dk4str8_cat_s(kb, sizeof(kb), printqd_kw[150], NULL)) { res = 0; }
5607   if (0 != res) {
5608     msgs[0] = kb;
5609     msgs[1] = NULL;
5610     log_multipart_message(NULL, 0UL, LOG_EMERG, 0, msgs, 1);
5611   }
5612 }
5613 
5614 
5615 
5616 /**	Charge user for a print job.
5617 	@param	un	User name.
5618 	@param	cl	Printer class of printer the job was printed on.
5619 	@param	pcval	Number of pages in print job.
5620 */
5621 static
5622 void
do_charge(const char * un,pqd_class_t * cl,dk4_um_t pcval)5623 do_charge(
5624   const char	*un,
5625   pqd_class_t	*cl,
5626   dk4_um_t	 pcval
5627 )
5628 {
5629   pqd_account_t		 oldacc;
5630   pqd_account_t		 newacc;
5631 
5632   if (0 != retrieve_account_for_user_and_class(&oldacc, un, cl, 1)) {
5633     DK4_MEMCPY(&newacc, &oldacc, sizeof(pqd_account_t));
5634     account_add_pages_from_job(&newacc, pcval);
5635     log_old_and_new_account(un, cl, &oldacc, &newacc, pcval, 0);
5636     if (0 == save_account_for_user_and_class(&oldacc, &newacc, un, cl)) {
5637 
5638       /* ERROR: Failed to update account data */
5639       log_5(NULL, 0UL, LOG_EMERG, 1, 156, 157, 158, un, cl->name);
5640     }
5641   }
5642 #if TRACE_DEBUG
5643   else {
5644   }
5645 #endif
5646 
5647 }
5648 
5649 
5650 
5651 /**	On start of file printing save user name, job name and pagecount
5652 	value to database for later use.
5653 	@param	job	Job structure.
5654 	@param	un	User name.
5655 	@param	pn	Printer name.
5656 	@param	jn	Job name.
5657 	@param	pc	Printer page count at start of job.
5658 */
5659 static
5660 void
do_filestart(pqd_rq_t * job,const char * un,const char * pn,const char * jn,const char * pc)5661 do_filestart(
5662   pqd_rq_t	*job,
5663   const char	*un,
5664   const char	*pn,
5665   const char	*jn,
5666   const char	*pc
5667 )
5668 {
5669   const char	*ep	= NULL;
5670   pqd_printer_t	*pr	= NULL;
5671   pqd_class_t	*cl	= NULL;
5672   dk4_um_t	 pcstt	= (dk4_um_t)0UL;
5673   int		 res	= 0;
5674 
5675   pr = get_printer_for_name(pn);
5676   if (NULL != pr) {
5677     cl = pr->cl;
5678   }
5679   if (NULL != cl) {
5680     res = dk4ma_input_c8_dec_dk4_um_t(&pcstt, pc, &ep, 1, NULL);
5681   }
5682   if ((NULL != pr) && (NULL != cl) && (0 != res)) {
5683 
5684     if (0 == dk4str8_cpy_s(kb, sizeof(kb), printqd_kw[90], NULL)) { res = 0; }
5685     if (0 == dk4str8_cat_s(kb, sizeof(kb), pr->name, NULL)) { res = 0; }
5686     if (0 == dk4str8_cpy_s(vb, sizeof(vb), pc, NULL)) { res = 0; }
5687     if (0 == dk4str8_cat_s(vb, sizeof(vb), printqd_kw[8], NULL)) { res = 0; }
5688     if (0 == dk4str8_cat_s(vb, sizeof(vb), un, NULL)) { res = 0; }
5689     if (0 == dk4str8_cat_s(vb, sizeof(vb), printqd_kw[8], NULL)) { res = 0; }
5690     if (0 == dk4str8_cat_s(vb, sizeof(vb), jn, NULL)) { res = 0; }
5691     if (0 != res) {
5692       if (0 == dbi_set(db, kb, vb, NULL)) {
5693         /* ERROR: Failed to set database entry */
5694 	log_1(NULL, 0UL, LOG_EMERG, 1, 117);
5695       }
5696     }
5697 #if TRACE_DEBUG
5698     else {
5699     }
5700 #endif
5701   } else {
5702     /*	Close connection on malformed request
5703     */
5704     if ((NULL == job->soa) && (0 == job->szsoa)) {
5705       close_stream_conn(job->sock, job->sto, job->connptr, job->pnconn);
5706     }
5707   }
5708 
5709 }
5710 
5711 
5712 
5713 /**	On end of file calculate page number used by the job and
5714 	save modified account to database.
5715 	@param	job	Job structure.
5716 	@param	un	User name.
5717 	@param	pn	Printer name.
5718 	@param	jn	Job name.
5719 	@param	pc	Printer page count at start of job.
5720 */
5721 static
5722 void
do_fileend(pqd_rq_t * job,const char * un,const char * pn,const char * jn,const char * pc)5723 do_fileend(
5724   pqd_rq_t	*job,
5725   const char	*un,
5726   const char	*pn,
5727   const char	*jn,
5728   const char	*pc
5729 )
5730 {
5731   const char	*ep	= NULL;			/* End of processed text */
5732   pqd_printer_t	*pr	= NULL;			/* Printer */
5733   pqd_class_t	*cl	= NULL;			/* Printer class */
5734   char		*oun	= NULL;			/* Old user name */
5735   char		*opc	= NULL;			/* Old page counter value */
5736   char		*ojn	= NULL;			/* Old job name */
5737   dk4_um_t	 pcstt	= (dk4_um_t)0UL;	/* Page counter at job start */
5738   dk4_um_t	 pcend	= (dk4_um_t)0UL;	/* Page counter at job end */
5739   int		 res	= 0;
5740 
5741 
5742   pr = get_printer_for_name(pn);
5743   if (NULL != pr) {
5744     cl = pr->cl;
5745   }
5746   if (NULL != cl) {
5747     res = dk4ma_input_c8_dec_dk4_um_t(&pcend, pc, &ep, 1, NULL);
5748   }
5749   if ((NULL != pr) && (NULL != cl) && (0 != res)) {
5750     if (0 == dk4str8_cpy_s(kb, sizeof(kb), printqd_kw[90], NULL)) { res = 0; }
5751     if (0 == dk4str8_cat_s(kb, sizeof(kb), pr->name, NULL)) { res = 0; }
5752     if (0 != res) {
5753       if (0 != dbi_get(db, kb, vb, sizeof(vb), NULL)) {
5754 
5755         if (0 == dbi_del(db, kb, NULL)) {
5756           /* ERROR: Failed to delete db entry */
5757 	  log_1(NULL, 0UL, LOG_EMERG, 1, 118);
5758         }
5759 
5760         opc = dk4str8_start(vb, NULL);
5761 	if (NULL != opc) {
5762 	  oun = dk4str8_chr(opc, ':');
5763 	  if (NULL != oun) {
5764 	    *(oun++) = '\0';
5765 	    oun = dk4str8_start(oun, NULL);
5766 	  }
5767 	}
5768 	if (NULL != oun) {
5769 	  ojn = dk4str8_chr(oun, ':');
5770 	  if (NULL != ojn) {
5771 	    *(ojn++) = '\0';
5772 	    ojn = dk4str8_start(ojn, NULL);
5773 	  }
5774 	}
5775 	if ((NULL != opc) && (NULL != oun) && (NULL != ojn)) {
5776 
5777 
5778 
5779 	  if (0 == strcmp(ojn, jn)) {
5780 	    if (0 == strcmp(oun, un)) {
5781 	      ep = NULL;
5782 	      res = dk4ma_input_c8_dec_dk4_um_t(&pcstt, opc, &ep, 1, NULL);
5783 	      if (0 != res) {
5784 	        if (pcend > pcstt) {
5785 		  do_charge(un, cl, (pcend - pcstt));
5786 		}
5787 #if TRACE_DEBUG
5788 		else {
5789 		}
5790 #endif
5791 	      }
5792 #if TRACE_DEBUG
5793 	      else {
5794 	      }
5795 #endif
5796 	    }
5797 #if TRACE_DEBUG
5798 	    else {
5799 	    }
5800 #endif
5801 	  }
5802 #if TRACE_DEBUG
5803 	  else {
5804 	  }
5805 #endif
5806 	}
5807 #if TRACE_DEBUG
5808 	else {
5809 	}
5810 #endif
5811       }
5812       else {
5813 
5814         if (0 == dbi_del(db, kb, NULL)) {
5815           /* ERROR: Failed to delete db entry */
5816 	  log_1(NULL, 0UL, LOG_EMERG, 1, 118);
5817         }
5818       }
5819     }
5820 #if TRACE_DEBUG
5821     else {
5822     }
5823 #endif
5824   } else {
5825     /*	Close connection on malformed request
5826     */
5827     if ((NULL == job->soa) && (0 == job->szsoa)) {
5828       close_stream_conn(job->sock, job->sto, job->connptr, job->pnconn);
5829     }
5830   }
5831 
5832 }
5833 
5834 
5835 
5836 /**	Process filestart request.
5837 	@param	job	Data for one request to process.
5838 */
5839 static
5840 void
rq_filestart(pqd_rq_t * job)5841 rq_filestart(pqd_rq_t *job)
5842 {
5843   lprng_info_t		 lpi;
5844   char			*un	= NULL;
5845   char			*pn	= NULL;
5846   char			*jn	= NULL;
5847   char			*pc	= NULL;
5848 
5849   if (0 != lprng_info_from_line(&lpi, job->argptr)) {
5850     un = lpi.username; pn = lpi.queuename;
5851     jn = lpi.jobtitle; pc = lpi.pagecount;
5852   }
5853   if ((NULL != un) && (NULL != pn) && (NULL != jn) && (NULL != pc)) {
5854     do_filestart(job, un, pn, jn, pc);
5855   } else {
5856     /*	Close connection on malformed request
5857     */
5858     if ((NULL == job->soa) && (0 == job->szsoa)) {
5859       close_stream_conn(job->sock, job->sto, job->connptr, job->pnconn);
5860     }
5861   }
5862 
5863 }
5864 
5865 
5866 
5867 /**	Process fileend request.
5868 	@param	job	Data for one request to process.
5869 */
5870 static
5871 void
rq_fileend(pqd_rq_t * job)5872 rq_fileend(pqd_rq_t *job)
5873 {
5874   lprng_info_t		 lpi;
5875   char			*un	= NULL;
5876   char			*pn	= NULL;
5877   char			*jn	= NULL;
5878   char			*pc	= NULL;
5879 
5880   if (0 != lprng_info_from_line(&lpi, job->argptr)) {
5881     un = lpi.username; pn = lpi.queuename;
5882     jn = lpi.jobtitle; pc = lpi.pagecount;
5883   }
5884   if ((NULL != un) && (NULL != pn) && (NULL != jn) && (NULL != pc)) {
5885     do_fileend(job, un, pn, jn, pc);
5886   } else {
5887     /*	Close connection on malformed request
5888     */
5889     if ((NULL == job->soa) && (0 == job->szsoa)) {
5890       close_stream_conn(job->sock, job->sto, job->connptr, job->pnconn);
5891     }
5892   }
5893 
5894 }
5895 
5896 
5897 
5898 /**	Process acct-check request.
5899 	@param	job	Data for one request to process.
5900 */
5901 static
5902 void
rq_acct_check(pqd_rq_t * job)5903 rq_acct_check(pqd_rq_t *job)
5904 {
5905 
5906   rq_retrieve_data(job, 1);
5907 
5908 }
5909 
5910 
5911 
5912 /**	Process acct-start request.
5913 	@param	job	Data for one request to process.
5914 */
5915 static
5916 void
rq_acct_start(pqd_rq_t * job)5917 rq_acct_start(pqd_rq_t *job)
5918 {
5919   char		*un	= NULL;
5920   char		*pn	= NULL;
5921   char		*jn	= NULL;
5922   char		*pc	= NULL;
5923 
5924   pn = job->argptr;
5925   if (NULL != pn) {
5926     un = dk4str8_next(pn, NULL);
5927   }
5928   if (NULL != un) {
5929     pc = dk4str8_next(un, NULL);
5930   }
5931   if (NULL != pc) {
5932     jn = dk4str8_next(pc, NULL);
5933   }
5934   if (NULL != jn) {
5935     (void)dk4str8_next(jn, NULL);
5936   }
5937   if ((NULL != un) && (NULL != pn) && (NULL != jn) && (NULL != pc)) {
5938     do_filestart(job, un, pn, jn, pc);
5939   } else {
5940     /*	Close connection on malformed request
5941     */
5942     if ((NULL == job->soa) && (0 == job->szsoa)) {
5943       close_stream_conn(job->sock, job->sto, job->connptr, job->pnconn);
5944     }
5945   }
5946 
5947 }
5948 
5949 
5950 
5951 /**	Process acct-end request.
5952 	@param	job	Data for one request to process.
5953 */
5954 static
5955 void
rq_acct_end(pqd_rq_t * job)5956 rq_acct_end(pqd_rq_t *job)
5957 {
5958   char		*un	= NULL;
5959   char		*pn	= NULL;
5960   char		*jn	= NULL;
5961   char		*pc	= NULL;
5962 
5963   pn = job->argptr;
5964   if (NULL != pn) {
5965     un = dk4str8_next(pn, NULL);
5966   }
5967   if (NULL != un) {
5968     pc = dk4str8_next(un, NULL);
5969   }
5970   if (NULL != pc) {
5971     jn = dk4str8_next(pc, NULL);
5972   }
5973   if (NULL != jn) {
5974     (void)dk4str8_next(jn, NULL);
5975   }
5976   if ((NULL != un) && (NULL != pn) && (NULL != jn) && (NULL != pc)) {
5977     do_fileend(job, un, pn, jn, pc);
5978   } else {
5979     /*	Close connection on malformed request
5980     */
5981     if ((NULL == job->soa) && (0 == job->szsoa)) {
5982       close_stream_conn(job->sock, job->sto, job->connptr, job->pnconn);
5983     }
5984   }
5985 
5986 }
5987 
5988 
5989 
5990 /**	Process acct-charge request.
5991 	@param	job	Data for one request to process.
5992 */
5993 static
5994 void
rq_acct_charge(pqd_rq_t * job)5995 rq_acct_charge(pqd_rq_t *job)
5996 {
5997   const char	*ep	= NULL;
5998   pqd_printer_t	*pr	= NULL;
5999   pqd_class_t	*cl	= NULL;
6000   char		*un	= NULL;
6001   char		*pn	= NULL;
6002   char		*pc	= NULL;
6003   dk4_um_t	 pcval	= (dk4_um_t)0UL;
6004 
6005   pn = job->argptr;
6006   if (NULL != pn) {
6007     un = dk4str8_next(pn, NULL);
6008   }
6009   if (NULL != un) {
6010     pc = dk4str8_next(un, NULL);
6011   }
6012   if (NULL != pc) {
6013     (void)dk4str8_next(pc, NULL);
6014   }
6015   if (NULL != pn) {
6016     pr = get_printer_for_name(pn);
6017   }
6018   if (NULL != pr) {
6019     cl = pr->cl;
6020   }
6021   if (
6022     (NULL != un) && (NULL != pn) && (NULL != pc) && (NULL != pr) && (NULL != cl)
6023   )
6024   {
6025     if (0 != dk4ma_input_c8_dec_dk4_um_t(&pcval, pc, &ep, 1, NULL)) {
6026       do_charge(un, cl, pcval);
6027     } else {
6028       /*	Close connection on malformed request
6029       */
6030       if ((NULL == job->soa) && (0 == job->szsoa)) {
6031         close_stream_conn(job->sock, job->sto, job->connptr, job->pnconn);
6032       }
6033     }
6034   } else {
6035     /*	Close connection on malformed request
6036     */
6037     if ((NULL == job->soa) && (0 == job->szsoa)) {
6038       close_stream_conn(job->sock, job->sto, job->connptr, job->pnconn);
6039     }
6040   }
6041 
6042 }
6043 
6044 
6045 
6046 /**	Object for DB traversal in control requests.
6047 */
6048 typedef struct {
6049   dk4_sto_t	*s;	/**< Key name storage. */
6050   dk4_sto_it_t	*i;	/**< Key name storage iterator. */
6051   char		*cn;	/**< Class name. */
6052   char		*un;	/**< User name. */
6053 } pqd_control_t;
6054 
6055 
6056 
6057 /**	Comparison function for storage.
6058 	@param	l	Left object.
6059 	@param	r	Right object.
6060 	@param	cr	Comparison criteria (ignored).
6061 	@return	Comparison result.
6062 */
6063 static
6064 int
db_entry_compare(const void * l,const void * r,int DK4_ARG_UNUSED (cr))6065 db_entry_compare(const void *l, const void *r, int DK4_ARG_UNUSED(cr) )
6066 {
6067   int		 back	= 0;
6068   DK4_UNUSED_ARG(cr)
6069   if (NULL != l) {
6070     if (NULL != r) {
6071       back = strcmp((const char *)l, (const char *)r);
6072       if (-1 > back) back = -1;
6073       if ( 1 < back) back =  1;
6074     } else {
6075       back = 1;
6076     }
6077   } else {
6078     if (NULL != r) {
6079       back = -1;
6080     }
6081   }
6082   return back;
6083 }
6084 
6085 
6086 
6087 /**	Traverse simple database containing text.
6088 	@param	obj	Object to modify during traversal.
6089 	@param	k	Key text.
6090 	@param	v	Value text.
6091 	@return	1 on success, 0 on error (continue traversal),
6092 		-1 on error (abort).
6093 */
6094 static
6095 int
rq_c_reset_traverse(void * obj,const char * k,const char * DK4_ARG_UNUSED (v))6096 rq_c_reset_traverse(void *obj, const char *k, const char * DK4_ARG_UNUSED(v) )
6097 {
6098   pqd_control_t	*ctoptr	= NULL;		/* Traversal object pointer */
6099   char		*p1	= NULL;		/* DB entry type */
6100   char		*p2	= NULL;		/* Class name */
6101   char		*p3	= NULL;		/* User name */
6102   int		 clm	= 0;		/* Flag: Class name matches */
6103   int		 unm	= 0;		/* Flag: User name matches */
6104   int		 back	= 1;
6105 
6106   DK4_UNUSED_ARG(v)
6107   ctoptr = (pqd_control_t *)obj;
6108   if (0 != dk4str8_cpy_s(kb, sizeof(kb), k, NULL)) {
6109     p1 = dk4str8_start(kb, NULL);
6110     if (NULL != p1) {
6111       p2 = strchr(p1, ':');
6112       if (NULL != p2) {
6113         *(p2++) = '\0';
6114 	p2 = dk4str8_start(p2, NULL);
6115       }
6116       if (NULL != p2) {
6117 	if (0 == strcmp(p1, printqd_kw[152])) {
6118           p3 = strchr(p2, ':');
6119 	  if (NULL != p3) {
6120 	    *(p3++) = '\0';
6121 	    p3 = dk4str8_start(p3, NULL);
6122 	  }
6123 	  if (NULL != p3) {
6124 	    if (NULL != ctoptr->cn) {
6125 	      if (0 == strcmp(ctoptr->cn, p2)) {
6126 	        clm = 1;
6127 	      }
6128 	    } else {
6129 	      clm = 1;
6130 	    }
6131 	    if (0 != clm) {
6132 	      if (NULL != ctoptr->un) {
6133 	        if (0 == strcmp(ctoptr->un, p3)) {
6134 		  unm = 1;
6135 		}
6136 	      } else {
6137 	        unm = 1;
6138 	      }
6139 	      if (0 != unm) {
6140 	        p1 = dk4str8_dup(k, NULL);
6141 		if (NULL != p1) {
6142 		  if (0 == dk4sto_add(ctoptr->s, p1, NULL)) {
6143 		    dk4mem_free(p1);
6144 		  }
6145 		}
6146 #if TRACE_DEBUG
6147 		else {
6148 		}
6149 #endif
6150 	      }
6151 #if TRACE_DEBUG
6152 	      else {
6153 	      }
6154 #endif
6155 	    }
6156 #if TRACE_DEBUG
6157 	    else {
6158 	    }
6159 #endif
6160 	  }
6161 #if TRACE_DEBUG
6162 	  else {
6163 	  }
6164 #endif
6165 	}
6166 #if TRACE_DEBUG
6167 	else {
6168 	}
6169 #endif
6170       }
6171 #if TRACE_DEBUG
6172       else {
6173       }
6174 #endif
6175     }
6176 #if TRACE_DEBUG
6177     else {
6178     }
6179 #endif
6180   }
6181   if (0 == can_continue(0, 0)) { back = -1; }
6182 
6183   return back;
6184 }
6185 
6186 
6187 
6188 /**	Traverse simple database containing text.
6189 	@param	obj	Object to modify during traversal.
6190 	@param	k	Key text.
6191 	@param	v	Value text.
6192 	@return	1 on success, 0 on error (continue traversal),
6193 		-1 on error (abort).
6194 */
6195 static
6196 int
rc_c_dbcl_traverse(void * obj,const char * k,const char * DK4_ARG_UNUSED (v))6197 rc_c_dbcl_traverse(void *obj, const char *k, const char * DK4_ARG_UNUSED(v) )
6198 {
6199   pqd_control_t	*pctobj;
6200   pqd_class_t	*cl;
6201   char		*p1;		/* First argument */
6202   char		*p2;		/* Second argument */
6203   int		 cdel	= 0;	/* Flag: Can delete item */
6204   int		 back	= 1;
6205 
6206   DK4_UNUSED_ARG(v)
6207   if (0 != dk4str8_cpy_s(kb, sizeof(kb), k, NULL)) {
6208     if (0 != dk4str8_cpy_s(vb, sizeof(vb), k, NULL)) {
6209       p1 = strchr(kb, ':');
6210       if (NULL != p1) {
6211         *(p1++) = '\0';
6212 	p1 = dk4str8_start(p1, NULL);
6213 	dk4str8_normalize(kb, NULL);
6214 	if (NULL != p1) {
6215 	  pctobj = (pqd_control_t *)obj;
6216 	  switch ( dk4str8_array_index(db_type_names, kb, 0) ) {
6217 	    case 0 :	/* p:class:user */
6218 	    case 1 :	/* a:class:user */
6219 	    {
6220 	      p2 = strchr(p1, ':');
6221 	      if (NULL != p2) {
6222 	        *(p2++) = '\0';
6223 		p2 = dk4str8_start(p2, NULL);
6224 		if (NULL != p2) {
6225 		  dk4str8_normalize(p1, NULL);
6226 		  dk4str8_normalize(p2, NULL);
6227 		  cl = (pqd_class_t *)dk4sto_it_find_like(conf.i_c, p1, 1);
6228 		  if (NULL != cl) {
6229 		    if (NULL == dk4sto_it_find_like(cl->i_u, p2, 1)) {
6230 		      if (NULL == getpwnam(p2)) {
6231 		        cdel = 1;
6232 		      }
6233 		    }
6234 		  } else {
6235 		    cdel = 1;
6236 		  }
6237 		  if (0 != cdel) {
6238 		    p1 = dk4str8_dup(vb, NULL);
6239 		    if (NULL != p1) {
6240 		      if (0 == dk4sto_add(pctobj->s, p1, NULL)) {
6241 		        dk4mem_free(p1);
6242 			back = 0;
6243 		      }
6244 		    } else {
6245 		      back = 0;
6246 		    }
6247 		  }
6248 		}
6249 	      }
6250 	    } break;
6251 	    case 2 : {	/* j:printer */
6252 	      dk4str8_normalize(p1, NULL);
6253 	      if (NULL == get_printer_for_name(p1)) {
6254 	        p1 = dk4str8_dup(vb, NULL);
6255 		if (NULL != p1) {
6256 		  if (0 == dk4sto_add(pctobj->s, p1, NULL)) {
6257 		    dk4mem_free(p1);
6258 		    back = 0;
6259 		  }
6260 		} else {
6261 		  back = 0;
6262 		}
6263 	      }
6264 	    } break;
6265 	  }
6266 	}
6267       }
6268     }
6269   }
6270   if (0 == can_continue(0, 0)) { back = -1; }
6271   return back;
6272 }
6273 
6274 
6275 
6276 /**	Process control reset request.
6277 	@param	job	Arguments for request.
6278 */
6279 static
6280 void
rq_c_reset(pqd_rq_t * job)6281 rq_c_reset(pqd_rq_t *job)
6282 {
6283   pqd_control_t	 ctobj;
6284   char		*pc;
6285   char		*pn;
6286   char		*pv;
6287 
6288   /*	Initialize variable
6289   */
6290   ctobj.s  = NULL;
6291   ctobj.i  = NULL;
6292   ctobj.cn = NULL;
6293   ctobj.un = NULL;
6294   /*	Process command arguments
6295   */
6296   pc = job->argptr;
6297   while (NULL != pc) {
6298     pn = dk4str8_next(pc, NULL);
6299 
6300     pv = dk4str8_chr(pc, '=');
6301     if (NULL != pv) {
6302       *(pv++) = '\0';
6303       pv = dk4str8_start(pv, NULL);
6304     }
6305 
6306     if (NULL != pv) {
6307       switch ( dk4str8_abbr_index(control_arg_names, '$', pc, 0) ) {
6308         case 0 : {
6309 	  ctobj.cn = pv;
6310 	} break;
6311 	case 1 : {
6312 	  ctobj.un = pv;
6313 	} break;
6314 	default : {
6315 
6316 	} break;
6317       }
6318     }
6319     pc = pn;
6320   }
6321 
6322   if (NULL != ctobj.cn) {
6323     if (0 == dk4str8_cmp(printqd_kw[2], ctobj.cn)) { ctobj.cn = NULL; }
6324   }
6325   if (NULL != ctobj.un) {
6326     if (0 == dk4str8_cmp(printqd_kw[2], ctobj.un)) { ctobj.un = NULL; }
6327   }
6328   ctobj.s = dk4sto_open(NULL);
6329   if (NULL != ctobj.s) {
6330     dk4sto_set_comp(ctobj.s, db_entry_compare, 0);
6331     ctobj.i = dk4sto_it_open(ctobj.s, NULL);
6332     if (NULL != ctobj.i) {
6333       (void)dk4dbi_c8_traverse(db, (void *)(&ctobj), rq_c_reset_traverse);
6334 
6335       dk4sto_it_reset(ctobj.i);
6336       do {
6337         pc = (char *)dk4sto_it_next(ctobj.i);
6338         if (NULL != pc) {
6339           if (0 != can_continue(0, 0)) {
6340             (void)dbi_del(db, pc, NULL);
6341           }
6342           dk4mem_free(pc);
6343         }
6344       } while (NULL != pc);
6345       dk4sto_it_close(ctobj.i);
6346     }
6347 #if TRACE_DEBUG
6348     else {
6349     }
6350 #endif
6351     dk4sto_close(ctobj.s);
6352   }
6353 #if TRACE_DEBUG
6354   else {
6355   }
6356 #endif
6357 
6358 }
6359 
6360 
6361 
6362 /**	Process control add request.
6363 	@param	job	Arguments for request.
6364 */
6365 static
6366 void
rq_c_add(pqd_rq_t * job)6367 rq_c_add(pqd_rq_t *job)
6368 {
6369   pqd_account_t	 oldacc;
6370   pqd_account_t	 newacc;
6371   pqd_class_t	*cl	= NULL;
6372   const char	*ep	= NULL;
6373   char		*clname	= NULL;
6374   char		*uname	= NULL;
6375   char		*ptext	= NULL;
6376   char		*pc;
6377   char		*pn;
6378   char		*pv;
6379   dk4_um_t	 pages	= (dk4_um_t)0UL;
6380 
6381   /*	Process command arguments
6382   */
6383   pc = job->argptr;
6384   while (NULL != pc) {
6385     pn = dk4str8_next(pc, NULL);
6386     pv = dk4str8_chr(pc, '=');
6387     if (NULL != pv) {
6388       *(pv++) = '\0';
6389       pv = dk4str8_start(pv, NULL);
6390     }
6391     if (NULL != pv) {
6392       switch ( dk4str8_abbr_index(control_arg_names, '$', pc, 0) ) {
6393         case 0 : {
6394 	  clname = pv;
6395 	} break;
6396 	case 1 : {
6397 	  uname = pv;
6398 	} break;
6399 	case 2 : {
6400 	  ptext = pv;
6401 	} break;
6402       }
6403     }
6404     pc = pn;
6405   }
6406   if ((NULL != clname) && (NULL != uname) && (NULL != ptext)) {
6407     if (0 != dk4ma_input_c8_dec_dk4_um_t(&pages, ptext, &ep, 1, NULL)) {
6408       cl = (pqd_class_t *)dk4sto_it_find_like(conf.i_c, clname, 1);
6409       if (NULL != cl) {
6410         if (0 != retrieve_account_for_user_and_class(&oldacc, uname, cl, 1)) {
6411 	  DK4_MEMCPY(&newacc, &oldacc, sizeof(pqd_account_t));
6412 	  if ((DK4_UM_MAX - pages) >= newacc.account) {
6413 	    newacc.account += pages;
6414 	  } else {
6415 	    newacc.account =  DK4_UM_MAX;
6416 	  }
6417 	  log_old_and_new_account(uname, cl, &oldacc, &newacc, pages, 1);
6418 	  if (0 == save_account_for_user_and_class(&oldacc,&newacc,uname,cl)) {
6419 	    /* ERROR: Failed to save new account */
6420 	    log_5(NULL, 0UL, LOG_EMERG, 1, 156, 157, 158, uname, cl->name);
6421 	  }
6422 	} else {
6423 	  /* ERROR: Failed to retrieve account data */
6424 	  log_5(NULL, 0UL, LOG_EMERG, 1, 161, 162, 163, uname, cl->name);
6425 	}
6426       } else {
6427         /* ERROR: No such class */
6428 	log_3(NULL, 0UL, LOG_EMERG, 1, 164, 165, clname);
6429       }
6430     } else {
6431       /* ERROR: ptext not numeric */
6432       log_3(NULL, 0UL, LOG_EMERG, 1, 166, 167, ptext);
6433     }
6434   }
6435 }
6436 
6437 
6438 
6439 /**	Process control database-cleanup request.
6440 	@param	job	Arguments for request.
6441 */
6442 static
6443 void
rq_c_dbcl(void)6444 rq_c_dbcl(void)
6445 {
6446   pqd_control_t		 ctobj;
6447   char			*ptr;
6448 
6449   DK4_MEMRES(&ctobj, sizeof(pqd_control_t));
6450   ctobj.s  = NULL;
6451   ctobj.i  = NULL;
6452   ctobj.cn = NULL;
6453   ctobj.un = NULL;
6454 
6455   ctobj.s = dk4sto_open(NULL);
6456   if (NULL != ctobj.s) {
6457     dk4sto_set_comp(ctobj.s, db_entry_compare, 0);
6458     ctobj.i = dk4sto_it_open(ctobj.s, NULL);
6459     if (NULL != ctobj.i) {
6460       (void)dk4dbi_c8_traverse(db, (void *)(&ctobj), rc_c_dbcl_traverse);
6461       dk4sto_it_reset(ctobj.i);
6462       do {
6463         ptr = (char *)dk4sto_it_next(ctobj.i);
6464 	if (NULL != ptr) {
6465 	  if (0 != can_continue(0, 0)) {
6466 	    dbi_del(db, ptr, NULL);
6467 	  }
6468 	  dk4mem_free(ptr);
6469 	}
6470       } while(NULL != ptr);
6471       dk4sto_it_close(ctobj.i);
6472     }
6473     dk4sto_close(ctobj.s);
6474   }
6475 }
6476 
6477 
6478 
6479 /**	Process control request.
6480 	@param	job	Data for one request to process.
6481 */
6482 static
6483 void
rq_control(pqd_rq_t * job)6484 rq_control(pqd_rq_t *job)
6485 {
6486   char	*subcmd;
6487   int	 sc;
6488 
6489   subcmd = job->argptr;
6490   job->argptr = dk4str8_next(subcmd, NULL);
6491 
6492   switch ( (sc = dk4str8_abbr_index(control_sub_cmds, '$', subcmd, 0)) ) {
6493     case 0 : {
6494       rq_c_reset(job);
6495     } break;
6496     case 1 : {
6497       rq_c_add(job);
6498     } break;
6499     case 2 : {
6500       rq_c_dbcl();
6501     } break;
6502     default : {
6503       /* ERROR: Illegal sub-command */
6504       log_3(NULL, 0UL, LOG_EMERG, 1, 168, 169, subcmd);
6505     } break;
6506   }
6507 
6508 }
6509 
6510 
6511 
6512 /**	Process contents of the inbuf buffer, send response if necessary.
6513 	@param	job	Data for one request to process.
6514 */
6515 static
6516 void
process_data(pqd_rq_t * job)6517 process_data(pqd_rq_t *job)
6518 {
6519   const char *	msgs[3];
6520 
6521   job->cmdptr = dk4str8_start(inbuf, NULL);
6522   if (NULL != job->cmdptr) {
6523     dk4str8_delnl(job->cmdptr);
6524     /* LOG request */
6525     if (0 == conf.linf) {
6526       if ('i' == (job->cmdptr)[0]) {
6527         if ('n' == (job->cmdptr)[1]) {
6528 	  if ('f' == (job->cmdptr)[2]) {
6529 	    if ('o' == (job->cmdptr)[3]) {
6530 	      job->logthis = 0;
6531 	    }
6532 	  }
6533 	}
6534       }
6535     }
6536     if (0 != job->logthis) {
6537       msgs[0] = printqd_kw[87];
6538       msgs[1] = job->cmdptr;
6539       msgs[2] = NULL;
6540       log_multipart_message(NULL, 0UL, LOG_EMERG, 0, msgs, 2);
6541     }
6542     /* Process request */
6543     job->argptr = dk4str8_next(job->cmdptr, NULL);
6544     job->action = dk4str8_array_index(pqd_command_names, job->cmdptr, 0);
6545     if (0 != protocol_level_check(job->action, job->protlev)) {
6546       switch (job->action) {
6547         case PQD_CMD_INFO : {
6548 	  rq_info(job);
6549 	} break;
6550         case PQD_CMD_JOBSTART : {
6551 	  rq_jobstart(job);
6552 	} break;
6553 	case PQD_CMD_FILESTART : {
6554 	  rq_filestart(job);
6555 	} break;
6556 	case PQD_CMD_FILEEND : {
6557 	  rq_fileend(job);
6558 	} break;
6559 	case PQD_CMD_ACCT_CHECK : {
6560 	  rq_acct_check(job);
6561 	} break;
6562 	case PQD_CMD_ACCT_START : {
6563 	  rq_acct_start(job);
6564 	} break;
6565 	case PQD_CMD_ACCT_END : {
6566 	  rq_acct_end(job);
6567 	} break;
6568 	case PQD_CMD_ACCT_CHARGE : {
6569 	  rq_acct_charge(job);
6570 	} break;
6571 	case PQD_CMD_CONTROL : {
6572 	  rq_control(job);
6573 	} break;
6574       }
6575     } else {
6576       /*	Close connection if request is denied.
6577       */
6578       if ((NULL == job->soa) && (0 == job->szsoa)) {
6579         close_stream_conn(job->sock, job->sto, job->connptr, job->pnconn);
6580       }
6581     }
6582   }
6583 
6584 }
6585 
6586 
6587 
6588 /**	Run one pass within inner loop.
6589 */
6590 static
6591 void
one_pass(void)6592 one_pass(void)
6593 {
6594   fd_set			 rfds;		/* Read file desc set */
6595   dk4_sockaddr_storage_t	 soa_sto;	/* Remote address */
6596   pqd_rq_t			 job;		/* Job structure */
6597   struct sockaddr		*soa;		/* Remote address */
6598 #if VERSION_BEFORE_20160329
6599   struct sockaddr_in		*soa4;		/* Remote IPv4 address */
6600 #if DK4_HAVE_STRUCT_SOCKADDR_IN6
6601   struct sockaddr_in6		*soa6;		/* Remote IPv6 address */
6602 #endif
6603 #endif
6604   pqd_l_conn_t			*pconnloc;	/* UNIX connection record */
6605   pqd_n_conn_t			*pconntcp;	/* TCP connection record */
6606   size_t			 sz_soa_sto;	/* Address size */
6607   size_t			 rdbytes;	/* Number of bytes read */
6608   size_t			 i;		/* Traverse socket set */
6609   dk4_socket_t			 sock;		/* Current new socket */
6610   int				 maxfd  = 0;	/* Maximum fd number */
6611   int				 l_conn	= 0;	/* Flag: Local connection */
6612   int				 l_proc	= 0;	/* Flag: Local processing */
6613   int				 res	= 0;	/* Operation result */
6614   int				 addrok;	/* Flag: Address size ok */
6615   int				 protlev;	/* Procotol level for conn */
6616 
6617 
6618   /*	Create file descriptor set for select.
6619   */
6620   FD_ZERO(&rfds);
6621   /*	Check for incoming UNIX conn rq only if maximum not yet reached.
6622   */
6623   if ((0 == conf.m_loc) || (con_loc < conf.m_loc)) {
6624     FD_SET(so_unix,&rfds);
6625     if (maxfd < so_unix) { maxfd = so_unix; }
6626   }
6627 
6628   /*	Check for incoming TCP conn rq only if maximum not yet reached.
6629   */
6630   if ((NULL != ss_tcp) && ((0 == conf.m_tcp) || (con_tcp < conf.m_tcp))) {
6631     for (i = 0; i < ss_tcp->szUsed; i++) {
6632       FD_SET((ss_tcp->pSockets)[i],&rfds);
6633       if (maxfd < (ss_tcp->pSockets)[i]) { maxfd = (ss_tcp->pSockets)[i]; }
6634     }
6635   }
6636 
6637   /*	Check for data on existing UNIX connections.
6638   */
6639   dk4sto_it_reset(i_c_unix);
6640   do {
6641     pconnloc = (pqd_l_conn_t *)dk4sto_it_next(i_c_unix);
6642     if (NULL != pconnloc) {
6643       FD_SET(pconnloc->sock,&rfds);
6644       if (maxfd < pconnloc->sock) { maxfd = pconnloc->sock; }
6645     }
6646   } while (NULL != pconnloc);
6647 
6648   /*	Check for data on existing TCP connections.
6649   */
6650   dk4sto_it_reset(i_c_tcp);
6651   do {
6652     pconntcp = (pqd_n_conn_t *)dk4sto_it_next(i_c_tcp);
6653     if (NULL != pconntcp) {
6654       FD_SET(pconntcp->sock,&rfds);
6655       if (maxfd < pconntcp->sock) { maxfd = pconntcp->sock; }
6656     }
6657   } while (NULL != pconntcp);
6658 
6659   /*	Check for data on UDP sockets.
6660   */
6661   if (NULL != ss_udp) {
6662     for (i = 0; i < ss_udp->szUsed; i++) {
6663       FD_SET((ss_udp->pSockets)[i],&rfds);
6664       if (maxfd < (ss_udp->pSockets)[i]) { maxfd = (ss_udp->pSockets)[i]; }
6665     }
6666   }
6667 
6668   /*	Check for signal meanwhile.
6669   */
6670   if (0 == can_continue(1, 0)) {
6671     goto finished;
6672   }
6673 
6674   /*	Run select().
6675   */
6676   errno = 0;
6677   res = select((1+maxfd), &rfds, NULL, NULL, NULL);
6678   if (-1 == res) {
6679     switch (errno) {
6680       case EINTR: {
6681         goto finished;
6682       } break;
6683       default: {
6684         /* ERROR: Serious error from select() function */
6685 	log_1(NULL, 0UL, LOG_EMERG, 1, 119);
6686 	ccouter = -1;
6687 	ccinner = -1;
6688 	goto finished;
6689       } break;
6690     }
6691   }
6692   if (0 == res) {
6693     goto finished;
6694   }
6695 
6696   /*	Check for new connection attempts on local socket.
6697   */
6698   if ((0 == conf.m_loc) || (con_loc < conf.m_loc)) {
6699     if (0 != (FD_ISSET(so_unix,&rfds))) {
6700       sock = dk4socket_accept(so_unix, NULL, NULL, NULL);
6701       if (INVALID_SOCKET != sock) {
6702         pconnloc = dk4mem_new(pqd_l_conn_t,1,NULL);
6703 	if (NULL != pconnloc) {
6704 	  pconnloc->sock = sock;
6705 	  if (dk4sto_add(s_c_unix, pconnloc, NULL)) {
6706 	    con_loc++;
6707 	    l_conn = 1;
6708 	  } else {
6709 	    dk4mem_free(pconnloc);
6710 	    (void)dk4socket_close(sock, NULL);
6711 	  }
6712 	} else {
6713 	  (void)dk4socket_close(sock, NULL);
6714 	  /* ERROR: Memory */
6715 	  log_1(NULL, 0UL, LOG_EMERG, 1, 120);
6716 	  ccouter = -1;
6717 	  ccinner = -1;
6718 	}
6719       }
6720     }
6721   }
6722 
6723   /*	Process data from local socket connections.
6724   */
6725   dk4sto_it_reset(i_c_unix);
6726   do {
6727     if (0 != can_continue(1, 0)) {
6728       pconnloc = (pqd_l_conn_t *)dk4sto_it_next(i_c_unix);
6729       if (NULL != pconnloc) {
6730         if (0 != (FD_ISSET(pconnloc->sock,&rfds))) {
6731 	  l_proc = 1;
6732 	  rdbytes = sizeof(inbuf);
6733 	  res = dk4socket_recv(
6734 	    pconnloc->sock, inbuf, &rdbytes, 0, 0L, 0L, NULL
6735 	  );
6736 	  if (0 != can_continue(0, 0)) {
6737 	    if (DK4_SOCKET_RESULT_SUCCESS == res) {
6738 	      if (0 < rdbytes) {
6739 	        if (sizeof(inbuf) > rdbytes) {
6740 	          inbuf[rdbytes] = '\0';
6741 		  job_init(&job);
6742 		  job.sock    = pconnloc->sock;
6743 		  job.protlev = PQD_PROTO_ADMIN;
6744 		  job.connptr = pconnloc;
6745 		  job.sto     = s_c_unix;
6746 		  job.pnconn  = &con_loc;
6747 		  process_data(&job);
6748 	        }
6749 	      } else {
6750 	        close_stream_conn(pconnloc->sock, s_c_unix, pconnloc, &con_loc);
6751 	      }
6752 	    } else {
6753 	      close_stream_conn(pconnloc->sock, s_c_unix, pconnloc, &con_loc);
6754 	    }
6755 	  } else {
6756 	    pconnloc = NULL;
6757 	  }
6758         }
6759       }
6760     } else {
6761       pconnloc = NULL;
6762     }
6763   } while (NULL != pconnloc);
6764 
6765   /*	Skip TCP and UDP data if activity on higher priorized local sockets.
6766   */
6767   if ((0 != l_conn) || (0 != l_proc) || (0 == can_continue(1, 0))) {
6768 
6769     goto finished;
6770   }
6771 
6772   /*	Check for new connection attempts on TCP.
6773   */
6774   if ((NULL != ss_tcp) && ((0 == conf.m_tcp) || (con_tcp < conf.m_tcp))) {
6775     for (i = 0; ((i < ss_tcp->szUsed) && (0 != can_continue(1, 0))); i++) {
6776       if (0 != (FD_ISSET((ss_tcp->pSockets)[i],&rfds))) {
6777 
6778         DK4_MEMRES(&soa_sto, sizeof(soa_sto));
6779 	sz_soa_sto = sizeof(soa_sto);
6780 	sock = dk4socket_accept(
6781 	  (ss_tcp->pSockets)[i],
6782 	  (struct sockaddr *)(&soa_sto), &sz_soa_sto, NULL
6783 	);
6784 	if (INVALID_SOCKET != sock) {
6785 #if VERSION_BEFORE_20160329
6786 #if DK4_HAVE_STRUCT_SOCKADDR_IN6
6787 	  soa6 = (struct sockaddr_in6 *)(&soa_sto);
6788 #endif
6789 	  soa4 = (struct sockaddr_in  *)(&soa_sto);
6790 #endif
6791 	  soa  = (struct sockaddr     *)(&soa_sto);
6792 	  addrok = 0;
6793 	  if (AF_INET == soa->sa_family) {
6794 	    if (sizeof(struct sockaddr_in) == sz_soa_sto) {
6795 	      addrok = 1;
6796 	    }
6797 	  }
6798 #if DK4_HAVE_STRUCT_SOCKADDR_IN6
6799 	  if (AF_INET6 == soa->sa_family) {
6800 	    if (sizeof(struct sockaddr_in6) == sz_soa_sto) {
6801 	      addrok = 1;
6802 	    }
6803 	  }
6804 #endif
6805 	  if (0 != addrok) {
6806 	    protlev = protocol_level_for_address(soa);
6807 	    if (PQD_PROTO_NONE < protlev) {
6808 	      pconntcp = dk4mem_new(pqd_n_conn_t,1,NULL);
6809 	      if (NULL != pconntcp) {
6810 	        pconntcp->sock = sock;
6811 		if (0 != dk4sto_add(s_c_tcp, pconntcp, NULL)) {
6812 #if VERSION_BEFORE_20160811
6813 		  DK4_MEMCPY(&(pconntcp->raddr),&soa_sto,sizeof(&soa_sto));
6814 #else
6815 		  DK4_MEMCPY(&(pconntcp->raddr),&soa_sto,sizeof(soa_sto));
6816 #endif
6817 		  pconntcp->pqdpl = protlev;
6818 		} else {
6819 		  dk4mem_free(pconntcp);
6820 		  (void)dk4socket_close(sock, NULL);
6821 		  /* ERROR: Memory */
6822 		  log_1(NULL, 0UL, LOG_EMERG, 1, 120);
6823 		  ccouter = -1;
6824 		  ccinner = -1;
6825 		}
6826 	      } else {
6827 	        (void)dk4socket_close(sock, NULL);
6828 	        /* ERROR: Memory */
6829 		log_1(NULL, 0UL, LOG_EMERG, 1, 120);
6830 		ccouter = -1;
6831 		ccinner = -1;
6832 	      }
6833 	    } else {
6834 	      (void)dk4socket_close(sock, NULL);
6835 	    }
6836 	  } else {
6837 	    (void)dk4socket_close(sock, NULL);
6838 	  }
6839 	}
6840       }
6841     }
6842   }
6843   if (0 == can_continue(1, 0)) {
6844 
6845     goto finished;
6846   }
6847 
6848   /*	Process data from TCP connections.
6849   */
6850   dk4sto_it_reset(i_c_tcp);
6851   do {
6852     if (0 != can_continue(1, 0)) {
6853       pconntcp = (pqd_n_conn_t *)dk4sto_it_next(i_c_tcp);
6854       if (NULL != pconntcp) {
6855         if (0 != (FD_ISSET(pconntcp->sock,&rfds))) {
6856 
6857 	  rdbytes = sizeof(inbuf);
6858 	  res = dk4socket_recv(
6859 	    pconntcp->sock, inbuf, &rdbytes, 0, 0L, 0L, NULL
6860 	  );
6861 	  if (0 != can_continue(0, 0)) {
6862 	    if (DK4_SOCKET_RESULT_SUCCESS == res) {
6863 	      if (0 < rdbytes) {
6864 	        if (sizeof(inbuf) > rdbytes) {
6865 	          inbuf[rdbytes] = '\0';
6866 		  job_init(&job);
6867 		  job.sock    = pconntcp->sock;
6868 		  job.protlev = pconntcp->pqdpl;
6869 		  job.connptr = pconntcp;
6870 		  job.sto     = s_c_tcp;
6871 		  job.pnconn  = &con_tcp;
6872 		  process_data(&job);
6873 	        }
6874 	      } else {
6875 	        close_stream_conn(pconntcp->sock, s_c_tcp, pconntcp, &con_tcp);
6876 	      }
6877 	    } else {
6878 	      close_stream_conn(pconntcp->sock, s_c_tcp, pconntcp, &con_tcp);
6879 	    }
6880 	  } else {
6881 	  }
6882 	}
6883       }
6884     } else {
6885       pconntcp = NULL;
6886     }
6887   } while (NULL != pconntcp);
6888   if (0 == can_continue(1, 0)) {
6889 
6890     goto finished;
6891   }
6892 
6893   /*	Process UDP data.
6894   */
6895   if (NULL != ss_udp) {
6896     for (i = 0; ((i < ss_udp->szUsed) && (0 != can_continue(1, 0))); i++) {
6897       if (0 != (FD_ISSET((ss_udp->pSockets)[i],&rfds))) {
6898 
6899         rdbytes = sizeof(inbuf);
6900         sz_soa_sto = sizeof(soa_sto);
6901         res = dk4socket_recvfrom(
6902           (ss_udp->pSockets)[i], inbuf, &rdbytes, 0,
6903 	  (struct sockaddr *)(&soa_sto), &sz_soa_sto, 0L, 0L, NULL
6904         );
6905         if ((DK4_SOCKET_RESULT_SUCCESS == res) && (0 < rdbytes)) {
6906           if ((0 != can_continue(1, 0)) && (sizeof(inbuf) > rdbytes)) {
6907 	    inbuf[rdbytes] = '\0';
6908 #if VERSION_BEFORE_20160329
6909 #if DK4_HAVE_STRUCT_SOCKADDR_IN6
6910 	    soa6 = (struct sockaddr_in6 *)(&soa_sto);
6911 #endif
6912 	    soa4 = (struct sockaddr_in  *)(&soa_sto);
6913 #endif
6914 	    soa  = (struct sockaddr     *)(&soa_sto);
6915 	    addrok = 0;
6916 	    if (AF_INET == soa->sa_family) {
6917 	      if (sizeof(struct sockaddr_in) == sz_soa_sto) {
6918 	        addrok = 1;
6919 	      }
6920 	    }
6921 #if DK4_HAVE_STRUCT_SOCKADDR_IN6
6922 	    if (AF_INET6 == soa->sa_family) {
6923 	      if (sizeof(struct sockaddr_in6) == sz_soa_sto) {
6924 	        addrok = 1;
6925 	      }
6926 	    }
6927 #endif
6928 	    if (0 != addrok) {
6929 	      protlev = protocol_level_for_address(soa);
6930 	      if (PQD_PROTO_NONE < protlev) {
6931 	        job_init(&job);
6932 	        job.sock    = (ss_udp->pSockets)[i];
6933 	        job.protlev = PQD_PROTO_INFO;
6934 	        job.soa     = (struct sockaddr *)(&soa_sto);
6935 	        job.szsoa   = sz_soa_sto;
6936 	        process_data(&job);
6937 	      }
6938 	    }
6939 	  }
6940         }
6941       }
6942     }
6943   }
6944 
6945   finished:
6946 
6947   if (0 == dbi_sync(db, NULL)) {
6948     /* ERROR: Failed to synchronize database */
6949     log_1(NULL, 0UL, LOG_EMERG, 1, 121);
6950   }
6951   if (0 == can_continue(1, 0)) {
6952     ccinner = 0;
6953     if (0 == can_continue(0, 0)) {
6954       ccouter = 0;
6955     }
6956   }
6957 
6958 }
6959 
6960 
6961 
6962 
6963 /**	Run two nested loops: The outer loop is only finished
6964 	by SIGTERM or SIGINT to exit the program, the inner loop
6965 	is also finished by SIGHUP to re-read the configuration.
6966 */
6967 static
6968 void
service_loops(void)6969 service_loops(void)
6970 {
6971 
6972 
6973   /* LOG: Daemon running */
6974   log_1(NULL, 0UL, LOG_INFO, 0, 73);
6975   if (outer_allocate_resources()) {
6976     /*	Outer loop is left on SIGTERM or SIGINT.
6977     */
6978     while(1 == ccouter) {
6979       if (1 == can_continue(0, 0)) {
6980         config_init();
6981         if (0 != config_read()) {
6982           if (inner_allocate_resources()) {
6983 	    if (0 != change_group_and_user()) {
6984 	      /*	Inner loop is left on SIGHUP, SIGTERM or SIGINT.
6985 	      */
6986               ccinner = 1;
6987 	      *sig_pass_pointer(&sig_had_hup) = 0;
6988 	      prev_filelog_failed = 0;
6989 	      /* LOG: Entering service mode */
6990 	      log_1(NULL, 0UL, LOG_INFO, 0, 75);
6991               while(1 == ccinner) {
6992                 if (1 == can_continue(1, 0)) {
6993 		  one_pass();
6994 	        } else {
6995 	          ccinner = 0;
6996 	          if (0 == can_continue(0, 0)) {
6997 		    ccouter = 0;
6998 		    /* LOG: Exiting service mode */
6999 		    log_1(NULL, 0UL, LOG_INFO, 0, 76);
7000 		  } else {
7001 		    /* LOG: Exiting service mode for reconfiguration */
7002 		    log_1(NULL, 0UL, LOG_INFO, 0, 77);
7003 		  }
7004 	        }
7005               }
7006 	      /* LOG: Exited service mode */
7007 	      log_1(NULL, 0UL, LOG_INFO, 0, 78);
7008 	    } else {
7009 	      ccouter = -1;
7010 	    }
7011 	  } else {
7012 	    ccouter = -1;
7013 	  }
7014 	  if (0 == inner_release_resources()) {
7015 	    ccouter = -1;
7016 	  }
7017         } else {
7018           ccouter = -1;
7019         }
7020 	config_release();
7021       } else {
7022         ccouter = 0;
7023       }
7024     }
7025   }
7026 #if TRACE_DEBUG
7027   else {
7028   }
7029 #endif
7030   outer_release_resources();
7031   /* LOG: Daemon exiting */
7032   log_1(
7033     NULL, 0UL,
7034     ((0 == ccouter) ? (LOG_INFO) : (LOG_ERR)),
7035     ((0 == ccouter) ? (0) : (1)),
7036     ((0 == ccouter) ? (74) : (187))
7037   );
7038 
7039 
7040 }
7041 
7042 
7043 
7044 /**	Run service in debug mode or normal mode.
7045 */
7046 static
7047 void
set_signal_handlers_and_run_service(void)7048 set_signal_handlers_and_run_service(void)
7049 {
7050   int			loop_was_running	= 0;
7051 #ifdef	DK4_HAVE_SIGACTION
7052 #ifdef SIGHUP
7053   struct sigaction	ohup;
7054   struct sigaction	nhup;
7055 #endif
7056 #ifdef SIGPIPE
7057   struct sigaction	opipe;
7058   struct sigaction	npipe;
7059 #endif
7060   struct sigaction	oint;
7061   struct sigaction	nint;
7062   struct sigaction	oterm;
7063   struct sigaction	nterm;
7064 #else
7065 #ifdef SIGPIPE
7066   dk4_sig_handler_t	*opipe	= NULL;
7067 #endif
7068 #ifdef SIGHUP
7069   dk4_sig_handler_t	*ohup	= NULL;
7070 #endif
7071   dk4_sig_handler_t	*oterm	= NULL;
7072   dk4_sig_handler_t	*oint	= NULL;
7073 #endif
7074 #ifdef	DK4_HAVE_SIGACTION
7075 #ifdef SIGHUP
7076   int			shup	= 0;
7077 #endif
7078 #ifdef SIGPIPE
7079   int			spipe	= 0;
7080 #endif
7081   int			sint	= 0;
7082   int			sterm	= 0;
7083   int			s_f_i	= 0;
7084   int			s_f_r	= 0;
7085 #endif
7086 
7087   /*	Set signal handlers
7088   */
7089 #if DK4_HAVE_SIGACTION
7090 #ifdef	SIGPIPE
7091   DK4_MEMRES(&npipe, sizeof(npipe));
7092   npipe.sa_handler = sig_handler_pipe;
7093   npipe.sa_flags = 0;
7094   if (0 != sigemptyset(&npipe.sa_mask)) {
7095     s_f_i = 1;
7096     goto finished;
7097   }
7098   if (0 != sigaddset(&npipe.sa_mask, SIGPIPE)) {
7099     s_f_i = 1;
7100     goto finished;
7101   }
7102   if (0 != sigaction(SIGPIPE, &npipe, &opipe)) {
7103     s_f_i = 1;
7104     goto finished;
7105   }
7106   spipe = 1;
7107 #endif
7108 #ifdef	SIGHUP
7109   DK4_MEMRES(&nhup, sizeof(nhup));
7110   nhup.sa_handler = sig_handler_hup;
7111   nhup.sa_flags = 0;
7112   if (0 != sigemptyset(&nhup.sa_mask)) {
7113     s_f_i = 1;
7114     goto finished;
7115   }
7116   if (0 != sigaddset(&nhup.sa_mask, SIGHUP)) {
7117     s_f_i = 1;
7118     goto finished;
7119   }
7120   if (0 != sigaction(SIGHUP, &nhup, &ohup)) {
7121     s_f_i = 1;
7122     goto finished;
7123   }
7124   shup = 1;
7125 #endif
7126   DK4_MEMRES(&nterm, sizeof(nterm));
7127   nterm.sa_handler = sig_handler_term;
7128   nterm.sa_flags = 0;
7129   if (0 != sigemptyset(&nterm.sa_mask)) {
7130     s_f_i = 1;
7131     goto finished;
7132   }
7133   if (0 != sigaddset(&nterm.sa_mask, SIGTERM)) {
7134     s_f_i = 1;
7135     goto finished;
7136   }
7137   if (0 != sigaction(SIGTERM, &nterm, &oterm)) {
7138     s_f_i = 1;
7139     goto finished;
7140   }
7141   sterm = 1;
7142   DK4_MEMRES(&nint, sizeof(nint));
7143   nint.sa_handler = sig_handler_int;
7144   nint.sa_flags = 0;
7145   if (0 != sigemptyset(&nint.sa_mask)) {
7146     s_f_i = 1;
7147     goto finished;
7148   }
7149   if (0 != sigaddset(&nint.sa_mask, SIGINT)) {
7150     s_f_i = 1;
7151     goto finished;
7152   }
7153   if (0 != sigaction(SIGINT, &nint, &oint)) {
7154     s_f_i = 1;
7155     goto finished;
7156   }
7157   sint = 1;
7158 #else
7159 #ifdef	SIGPIPE
7160   opipe = sigset(SIGPIPE, sig_handler_pipe);
7161 #endif
7162 #ifdef	SIGHUP
7163   ohup = sigset(SIGHUP, sig_handler_hup);
7164 #endif
7165   oint  = sigset(SIGINT,  sig_handler_int);
7166   oterm = sigset(SIGTERM, sig_handler_term);
7167 #endif
7168 
7169 
7170   service_loops();
7171   loop_was_running = 1;
7172 
7173   finished:
7174 
7175   /*
7176   */
7177   if (0 == loop_was_running) {
7178     log_1(NULL, 0UL, LOG_ERR, 1, 72);
7179   }
7180 
7181   /*	Restore signal handlers
7182   */
7183 #if DK4_HAVE_SIGACTION
7184   if (0 != s_f_i) {
7185     /* ERROR: Failed to install signal handlers */
7186     log_1(NULL, 0UL, LOG_EMERG, 1, 68);
7187     dk4dmt_error_sysfct(&dmt);
7188   }
7189   if (0 != sint) {
7190   if (0 != sigaction(SIGINT, &oint, NULL)) {
7191     s_f_r = 1;
7192   }
7193   }
7194   if (0 != sterm) {
7195   if (0 != sigaction(SIGTERM, &oterm, NULL)) {
7196     s_f_r = 1;
7197   }
7198   }
7199 #ifdef	SIGHUP
7200   if (0 != shup) {
7201   if (0 != sigaction(SIGHUP, &ohup, NULL)) {
7202     s_f_r = 1;
7203   }
7204   }
7205 #endif
7206 #ifdef	SIGPIPE
7207   if (0 != spipe) {
7208   if (0 != sigaction(SIGPIPE, &opipe, NULL)) {
7209     s_f_r = 1;
7210   }
7211   }
7212 #endif
7213   if (0 != s_f_r) {
7214     /* ERROR: Failed to restore signal handlers */
7215     log_1(NULL, 0UL, LOG_EMERG, 1, 69);
7216     dk4dmt_error_sysfct(&dmt);
7217   }
7218 #else
7219   if (NULL != oterm) { sigset(SIGTERM, oterm); }
7220   if (NULL != oint ) { sigset(SIGINT,  oint ); }
7221 #ifdef	SIGHUP
7222   if (NULL != ohup) { sigset(SIGHUP, ohup); }
7223 #endif
7224 #ifdef	SIGPIPE
7225   if (NULL != opipe) { sigset(SIGPIPE, opipe); }
7226 #endif
7227 #endif
7228 
7229 }
7230 
7231 
7232 
7233 /**	Program entry point.
7234 	@param	argc
7235 	@param	argv
7236 	@return	0 on success, any other value indicates an error.
7237 */
7238 int
main(int argc,char * argv[])7239 main(int argc, char *argv[])
7240 {
7241   pid_t		 cpid;		/* Child process PID */
7242   int		 res;		/* Operation result */
7243 
7244   /*	Initialize daemon tool structure
7245   */
7246   dk4dmt_init(&dmt);
7247   dk4dmt_set_program(&dmt, printqd_kw[0]);
7248   dk4dmt_set_pidfile(&dmt, pid_file_name);
7249   dk4dmt_set_syslog_feature(&dmt, syslogf);
7250   /*
7251   	Process command line arguments.
7252   */
7253   res = dk4opt_process_argv(
7254     options, szoptions, argc, argv, NULL, NULL, 1, 1, NULL
7255   );
7256   if (0 == res) {
7257     dk4dmt_error_usage(&dmt);	/* Invalid or excess arguments */
7258     fputs("printqd: ERROR: Invalid command line arguments!\n", stderr);
7259     fflush(stderr);
7260     goto finished;
7261   }
7262 
7263   /*	Must be started as root.
7264   */
7265   if (0 != geteuid()) {
7266     dk4dmt_error_usage(&dmt);
7267     fputs("printqd: ERROR: Must be run as root!\n", stderr);
7268     fflush(stderr);
7269     goto finished;
7270   }
7271 
7272   /*	Check used command line arguments.
7273   */
7274   if (0 != options[0].found) { debug = 1; }
7275 
7276   /*	Run in debug mode.
7277   */
7278   if (0 != debug) {
7279     dk4dmt_set_log_stderr(&dmt, 1);
7280     dk4dmt_success(&dmt);
7281     set_signal_handlers_and_run_service();
7282     goto finished;
7283   }
7284 
7285   /*	PREPARE TO RUN AS DAEMON
7286   */
7287   dk4dmt_set_program(&dmt, printqd_kw[0]);
7288   dk4dmt_set_pidfile(&dmt, pid_file_name);
7289   dk4dmt_set_syslog_feature(&dmt, syslogf);
7290   if (0 == dk4dmt_parent_before_fork(&dmt)) {
7291     goto finished;
7292   }
7293 
7294   /*	Create first background process
7295   */
7296   cpid = fork();
7297   if ((pid_t)0 < cpid) {
7298     /* In the parent process */
7299     dk4dmt_parent_after_fork(&dmt);
7300     goto finished;
7301   } else {
7302     if ((pid_t)0 == cpid) {
7303       /* In the child process, continue below */
7304     } else {
7305       /* Failed to create process */
7306       /* ERROR: fork() failed */
7307       fputs(printqd_kw[0], stderr);
7308       fputs(printqd_kw[70], stderr);
7309       fflush(stderr);
7310       dk4dmt_parent_fork_failed(&dmt);
7311       goto finished;
7312     }
7313   }
7314 
7315   /*	Intermediate process and daemon process should indicate success.
7316   */
7317   dk4dmt_success(&dmt);		/* Intermediate process */
7318 
7319   /*	Decouple from terminals.
7320   */
7321   if (0 == dk4dmt_intermediate_before_fork(&dmt)) {
7322     goto finished;
7323   }
7324 
7325   /*	Create daemon background process from within first background process
7326   */
7327   cpid = fork();
7328   if ((pid_t)0 < cpid) {
7329     /* In the intermediate process */
7330     dk4dmt_intermediate_after_fork(&dmt);
7331     goto finished;
7332   } else {
7333     if ((pid_t)0 == cpid) {
7334       /* In the daemon process, continue below */
7335     } else {
7336       /* Failed to create process */
7337       /* ERROR: fork() failed */
7338       log_1(NULL, 0UL, LOG_ERR, 1, 71);
7339       dk4dmt_intermediate_fork_failed(&dmt);
7340       goto finished;
7341     }
7342   }
7343 
7344   /*	In the daemon process
7345   */
7346   if (0 != dk4dmt_daemon_start(&dmt)) {
7347     set_signal_handlers_and_run_service();
7348   }
7349   dk4dmt_daemon_end(&dmt);
7350 
7351   /*	Exit the program.
7352   */
7353   finished:
7354   exval = dk4dmt_get_exit_status(&dmt);
7355   exit(exval); return exval;
7356 }
7357 
7358 #else
7359 
7360 /**	Program entry point.
7361 	@param	argc
7362 	@param	argv
7363 	@return	0 on success, any other value indicates an error.
7364 */
7365 int
main(int argc,char * argv[])7366 main(int argc, char *argv[])
7367 {
7368   fputs("printqd: ERROR: Build requirements violation!\n", stderr);
7369 #if DK4_CHAR_SIZE > 1
7370   fputs("Default character size is larger than 1!\n", stderr);
7371 #endif
7372 #if	!((DK4_HAVE_SIGACTION) || (DK4_HAVE_SIGSET))
7373   fputs("Neither sigaction() nor sigset() are available!\n", stderr);
7374 #endif
7375 #if	!(DK4_HAVE_PWD_H)
7376   fputs("Include file \"pwd.h\" not found!\n", stderr);
7377 #endif
7378 #if	!(DK4_HAVE_UID_T)
7379   fputs("Data type uid_t not available!\n", stderr);
7380 #endif
7381 #if	!(DK4_HAVE_GRP_H)
7382   fputs("Include file \"grp.h\" not found!\n", stderr);
7383 #endif
7384 #if	!(DK4_HAVE_GID_T)
7385   fputs("Data type gid_t not available!\n", stderr);
7386 #endif
7387 #if	!(DK4_HAVE_MODE_T)
7388   fputs("Data type mode_t not available!\n", stderr);
7389 #endif
7390 #if	!(DK4_HAVE_GETPWNAM)
7391   fputs("Function getpwnam() is not available!\n", stderr);
7392 #endif
7393 #if	!(DK4_HAVE_GETGRNAM)
7394   fputs("Function getgrnam() is not available!\n", stderr);
7395 #endif
7396 #if	!((DK4_HAVE_SETSID) || (DK4_HAVE_SETPGRP))
7397   fputs("Neither setsid() nor setpgrp() are available!\n", stderr);
7398 #endif
7399 #if	DK4_ON_WINDOWS
7400   fputs("On Windows platform!\n", stderr);
7401 #endif
7402   fflush(stderr);
7403   exit(EXIT_FAILURE); return EXIT_FAILURE;
7404 }
7405 
7406 
7407 #endif
7408