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(¤t);
1532 if (current != prev_log_time) {
1533 prev_log_time = current;
1534 if (0 != dk4time_as_text_c8(timebuf, sizeof(timebuf), ¤t, 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