/* WARNING: This file was generated by dkct. Changes you make here will be lost if dkct is run again! You should modify the original source and run dkct on it. Original source: printqd.ctr */ /* Copyright (C) 2016-2017, Dirk Krause Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above opyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the author nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #line 210 "printqd.ctr" /** @file printqd.c The printqd daemon. A print accounting and quota daemon for use with the LPRng print system. */ #include "dk4conf.h" #include "dk4types.h" /* CORRECT NEXT LINE AFTER REPLACING PRINTQD */ #include "printqd.h" #if (DK4_CHAR_SIZE == 1) \ && ((DK4_HAVE_SIGACTION) || (DK4_HAVE_SIGSET)) \ && DK4_HAVE_GETPWNAM && DK4_HAVE_GETGRNAM \ && ((DK4_HAVE_SETSID) || (DK4_HAVE_SETPGRP)) \ && ((DK4_HAVE_PWD_H) && (DK4_HAVE_GRP_H)) \ && DK4_HAVE_UID_T && DK4_HAVE_GID_T && DK4_HAVE_MODE_T && (!DK4_ON_WINDOWS) #include #if DK4_HAVE_SYS_TYPES_H #ifndef SYS_TYPES_H_INCLUDED #include #define SYS_TYPES_H_INCLUDED 1 #endif #endif #if DK4_HAVE_SYS_STAT_H #ifndef SYS_STAT_H_INCLUDED #include #define SYS_STAT_H_INCLUDED 1 #endif #endif #if DK4_HAVE_FCNTL_H #ifndef FCNTL_H_INCLUDED #include #define FCNTL_H_INCLUDED 1 #endif #endif #if DK4_HAVE_ERRNO_H #ifndef ERRNO_H_INCLUDED #include #define ERRNO_H_INCLUDED 1 #endif #endif #if DK4_HAVE_UNISTD_H #ifndef UNISTD_H_INCLUDED #include #define UNISTD_H_INCLUDED 1 #endif #endif #if DK4_HAVE_PWD_H #ifndef PWD_H_INCLUDED #include #define PWD_H_INCLUDED 1 #endif #endif #if DK4_HAVE_GRP_H #ifndef GRP_H_INCLUDED #include #define GRP_H_INCLUDED 1 #endif #endif #if DK4_HAVE_SYSLOG_H #ifndef SYSLOG_H_INCLUDED #include #define SYSLOG_H_INCLUDED 1 #endif #endif #include "dk4opt.h" #include "dk4dmt.h" #include "dk4inst.h" #include "dk4dmt.h" #include "dk4sto.h" #include "dk4sock.h" #include "dk4mem.h" #include "dk4str8.h" #include "dk4mai8dii.h" #include "dk4mai8dsz.h" #include "dk4mai8dus.h" #include "dk4mai8ddu.h" #include "dk4mao8d.h" #include "dk4fopc8.h" #include "dk4dbi.h" #include "dk4dbit8.h" #include "dk4time.h" #include "dk4time08.h" #include "dk4mkdh8.h" #include "dk4delfile08.h" #line 319 "printqd.ctr" #ifndef LOG_LPR /** Default log feature for printing. */ #define LOG_LPR (6 << 3) #endif #ifndef LOG_EMERG /** Log message level to ignore, printqd does not make system unusable. */ #define LOG_EMERG (0) #endif #ifndef LOG_ERR /** Log message level error. */ #define LOG_ERR (3) #endif #ifndef LOG_INFO /** Log message level info. */ #define LOG_INFO (6) #endif /** Input buffer, used * for configuration file reading and * for reading requests. */ static char inbuf[1024]; /** Buffer to construct key for database entries. */ static char kb[sizeof(inbuf)]; /** Buffer to construct/convert values for database entries. */ static char vb[sizeof(inbuf)]; /** Options used by the program. */ static dk4_option_t options[] = { /* Debug mode. */ { { dkT('d'), dkT("debug"), DK4_OPT_ARG_NONE }, { NULL }, 0 }, /* Configuration file. */ { { dkT('c'), dkT("config"), DK4_OPT_ARG_STRING }, { NULL }, 0 } }; /** Default configuration file name. */ static const char def_conf_file_name[] = { DK4_INST_DIR_ETC "/printqd/printqd.conf" }; /** Default socket file name. */ static const char def_sock_file_name[] = { DK4_INST_DIR_VAR "/run/printqd/printqd.sock" }; /** Default database file name. */ static const char def_db_file_name[] = { #if DK4_HAVE_DB_H "bdb::" DK4_INST_DIR_VAR "/lib/printqd/printqd.db" #else #if DK4_HAVE_NDBM_H "ndbm::" DK4_INST_DIR_VAR "/lib/printqd/printqd" #else "mem::" DK4_INST_DIR_VAR "/lib/printqd/printqd.db" #endif #endif }; /** Default log file name. */ static const char def_log_file_name[] = { DK4_INST_DIR_VAR "/log/printqd/printqd.log" }; /** PID file name. */ static const char pid_file_name[] = { DK4_INST_DIR_VAR "/run/printqd/printqd.pid" }; /** Constant texts used by the module. */ static const char * const printqd_kw[] = { /* 0 */ "printqd", /* 1 */ "r", /* 2 */ "*", /* 3 */ "unlimited", /* 4 */ "denied", /* 5 */ "\n", /* 6 */ "# ", /* 7 */ ": ", /* 8 */ ":", /* 9 */ "ERROR: ", /* 10 */ "a", /* 11 */ "", /* 12 */ "Not an integer number:\n\"", /* 13 */ "\", reading stoppend at \"", /* 14 */ "\"!", /* 15 */ "Positive number required!", /* 16 */ "Not a size specification:\n\"", /* 17 */ "\", reading stopped at \"", /* 18 */ "\"!", /* 19 */ "Not a 16 bit unsigned number:\n\"", /* 20 */ "\", reading stopped at \"", /* 21 */ "\"!", /* 22 */ "Port number must not be 0!", /* 23 */ "Too much text, unexpected:\n\"", /* 24 */ "\"!", /* 25 */ "Not a peer definition:\n\"", /* 26 */ "\"!", /* 27 */ "Not enough memory (allocation failed)!", /* 28 */ "Not an unsigned number:\n\"", /* 29 */ "\", reading stopped at \"", /* 30 */ "\"!", /* 31 */ "Missing limit text!", /* 32 */ "Limit redefinition for: \"", /* 33 */ "\"!", /* 34 */ "Redefinition of default limit!", /* 35 */ "Redefinition of deny action!", /* 36 */ "Printer already exists: \"", /* 37 */ "\"!", /* 38 */ "Printer alias already exists: \"", /* 39 */ "\"!", /* 40 */ "Class not found: \"", /* 41 */ "\"!", /* 42 */ "Redefinition of printers class!", /* 43 */ "Class already exists: \"", /* 44 */ "\"!", /* 45 */ "Missing class name!", /* 46 */ "Printer or alias already exists: \"", /* 47 */ "\"!", /* 48 */ "Missing printer name!", /* 49 */ "Illegal section type name: \"", /* 50 */ "\"!", /* 51 */ "Missing section type!", /* 52 */ "Redefinition of user ID to run as!", /* 53 */ "User not found: \"", /* 54 */ "\"!", /* 55 */ "Only allowed in options section!", /* 56 */ "Redefinition of group ID to run as!", /* 57 */ "Group not found: \"", /* 58 */ "\"!", /* 59 */ "Redefinition of database name!", /* 60 */ "Redefinition of socket name!", /* 61 */ "Only allowed in class section!", /* 62 */ "Only allowed in printer section!", /* 63 */ "Redefinition of log file name!", /* 64 */ "Value missing!", /* 65 */ "Failed to open file for reading!", /* 66 */ "User to run as was changed!", /* 67 */ "Group to run as was changed!", /* 68 */ "Failed to install signal handlers!", /* 69 */ "Failed to restore signal handlers!", /* 70 */ ": ERROR: Failed to create new process!\n", /* 71 */ "Failed to create new process!", /* 72 */ "Service start prevented by errors!", /* 73 */ "Daemon starting.", /* 74 */ "Daemon exited.", /* 75 */ "Entering service mode.", /* 76 */ "Exiting service mode.", /* 77 */ "Exiting service mode for reconfiguration.", /* 78 */ "Exited service mode.", /* 79 */ "o:test", /* 80 */ "ACCEPT", /* 81 */ "REMOVE", /* 82 */ "HOLD", /* 83 */ "0 0 0 0", /* 84 */ "-1", /* 85 */ " ", /* 86 */ "<- ", /* 87 */ "-> ", /* 88 */ "p:", /* 89 */ "a:", /* 90 */ "j:", /* 91 */ "No class configured for printer: \"", /* 92 */ "\"!", /* 93 */ "Warning: No default limit configured for class: \"", /* 94 */ "\"!", /* 95 */ "Failed to create directory hierarchy for log file:\n\"", /* 96 */ "\"!", /* 97 */ "Failed to create directory hierarchy for database:\n\"", /* 98 */ "\"!", /* 99 */ "Failed to create directory hierarchy for socket:\n\"", /* 100 */ "\"!", /* 101 */ "Failed to listen on local socket:\n\"", /* 102 */ "\"!", /* 103 */ "Failed to create TCP listener socket set!", /* 104 */ "Failed to create UDP socket set!", /* 105 */ "Failed to open database:\n\"", /* 106 */ "\"!", /* 107 */ "Failed to write initial entry to database!", /* 108 */ "Failed to synchronize database to disk!", /* 109 */ "Failed to change log file ownership!", /* 110 */ "Failed to change log file permissions!", /* 111 */ "Failed to change database ownership and/or permissions!", /* 112 */ "Failed to change local socket ownership!", /* 113 */ "Failed to change local socket permissions!", /* 114 */ "Failed to switch group!", /* 115 */ "Failed to switch user!", /* 116 */ "Response text too long (bug)!", /* 117 */ "Failed to write database entry!", /* 118 */ "Failed to delete database entry!", /* 119 */ "The select() function failed!", /* 120 */ "Insufficient memory!", /* 121 */ "Failed to synchronize database to disk!", /* 122 */ "DB SET \"", /* 123 */ "\"=\"", /* 124 */ "\" ok.", /* 125 */ "\" FAILED (invalid arguments)!", /* 126 */ "\" FAILED (syntax)!", /* 127 */ "\" FAILED (numeric overflow in size calculation)!", /* 128 */ "\" FAILED (unsupported db backend)!", /* 129 */ "\" FAILED (no such entry)!", /* 130 */ "\" FAILED (insufficient memory)!", /* 131 */ "\" FAILED (can not write)!", /* 132 */ "\" FAILED (reason unknown)!", /* 133 */ "DB GET \"", /* 134 */ "\" FAILED (buffer too small)!", /* 135 */ "DB DEL \"", /* 136 */ "DB SYN ok.", /* 137 */ "DB SYN FAILED (invalid arguments)!", /* 138 */ "DB SYN FAILED (unsupported db backend)!", /* 139 */ "DB SYN FAILED (syntax)!", /* 140 */ "DB SYN FAILED (security checks for file failed)!", /* 141 */ "DB SYN FAILED (can not open file for writing)!", /* 142 */ "DB SYN FAILED (can not write)!", /* 143 */ "DB SYN FAILED (can not close file)!", /* 144 */ "DB SYN FAILED (unknown reason)!", /* 145 */ "(l=", /* 146 */ ",u=", /* 147 */ ",a=", /* 148 */ ") + u=", /* 149 */ " => (l=", /* 150 */ ")", /* 151 */ "unlimited", /* 152 */ "p", /* 153 */ ") + a=", /* 154 */ "Illegal log feature name: \"", /* 155 */ "\"!", /* 156 */ "Failed to update account data for user \"", /* 157 */ "\" in class \"", /* 158 */ "\"!", /* 159 */ "Missing class name in reset request!", /* 160 */ "Missing user name in reset request!", /* 161 */ "Failed to update account data for user \"", /* 162 */ "\" in class \"", /* 163 */ "\"!", /* 164 */ "No such class: \"", /* 165 */ "\"!", /* 166 */ "Not a number: \"", /* 167 */ "\"!", /* 168 */ "Illegal sub-command: \"", /* 169 */ "\"!", /* 170 */ "Logging to file \"", /* 171 */ "\" failed!", /* 172 */ "Database modification failed!", /* 173 */ "Database synchronization to disk failed!", /* 174 */ "Failed to change ownership on database file:\n\"", /* 175 */ "\"!", /* 176 */ "Failed to change permissions on database file:\n\"", /* 177 */ "\"!", /* 178 */ "\" (name too long)!", /* 179 */ "\" (file exists, but no socket)!", /* 180 */ "\" (failed to remove old socket)!", /* 181 */ "\" (failed to create socket: ", /* 182 */ ")!", /* 183 */ "\" (failed to bind local ", /* 184 */ "\" (failed to listen ", /* 185 */ "\" (failed to change ownership)!", /* 186 */ "\" (failed to change permissions)!", /* 187 */ "Daemon exited due to errors, see log file!", /* 188 */ "Failed to create TCP socket set (math overflow)!", /* 189 */ "Failed to create TCP socket set (memory)!", /* 190 */ "Failed to create TCP socket set (socket(): ", /* 191 */ ")!", /* 192 */ "Failed to create TCP socket set (bind(): ", /* 193 */ "Failed to create TCP socket set (listen(): ", /* 194 */ "Failed to create TCP socket set (getaddrinfo(): ", /* 195 */ "Failed to create UDP socket set (math overflow)!", /* 196 */ "Failed to create UDP socket set (memory)!", /* 197 */ "Failed to create UDP socket set (socket(): ", /* 198 */ ")!", /* 199 */ "Failed to create UDP socket set (bind(): ", /* 200 */ "Failed to create UDP socket set (listen(): ", /* 201 */ "Failed to create UDP socket set (getaddrinfo(): ", /* 202 */ "\" (backend type not supported)!", /* 203 */ "\" (overflow in size calculation)!", /* 204 */ "\" (insufficient memory)!", /* 205 */ "\"\n(not a regular file / not a database / key or value size too large)!", /* 206 */ "\" (denied by security check)!", /* 207 */ "\" (failed to open for reading)!", /* 208 */ "\" (failed to write to file)!", /* 209 */ "\" (failed to synchronize to disk)!", /* 210 */ "Failed to write initial entry to database (key or value too long)!", /* 211 */ "Failed to write initial entry to database (unsupported backend type)!", /* 212 */ "Failed to write initial entry to database (insufficient memory)!", /* 213 */ "Failed to write initial entry to database (can not open file for writing)!", /* 214 */ "Failed to write initial entry to database (can not write to file)!", /* 215 */ "Failed to write initial entry to database (can not synchronize to disk)!", /* 216 */ "Failed to write initial entry to database (denied by security check)!", /* 217 */ "Failed to change PID file ownership!", /* 218 */ "Failed to change PID file permissions!", NULL #line 1013 "printqd.ctr" }; /** Choices for deny action. */ static const char * const deny_action_names[] = { /* 0 */ "remove", /* 1 */ "hold", NULL #line 1024 "printqd.ctr" }; /** Section names in configuration files. */ static const char * const config_section_names[] = { /* 0 */ "options", /* 1 */ "class", /* 2 */ "printer", NULL #line 1036 "printqd.ctr" }; /** Option names in configuration file. */ static const char * const config_option_names[] = { /* 0 */ "run as user", /* 1 */ "run as group", /* 2 */ "database", /* 3 */ "local socket", /* 4 */ "local socket backlog", /* 5 */ "max local connections", /* 6 */ "udp port", /* 7 */ "tcp port", /* 8 */ "tcp port backlog", /* 9 */ "max tcp connections", /* 10 */ "info allow", /* 11 */ "data allow", /* 12 */ "admin allow", /* 13 */ "user limit", /* 14 */ "group limit", /* 15 */ "default limit", /* 16 */ "deny action", /* 17 */ "alias", /* 18 */ "class", /* 19 */ "log file", /* 20 */ "log features", /* 21 */ "local socket owner", /* 22 */ "local socket group", NULL #line 1101 "printqd.ctr" }; /** Command names in the printqd protocol. */ static const char * const pqd_command_names[] = { /* 0 */ "jobstart", /* 1 */ "jobend", /* 2 */ "start", /* 3 */ "end", /* 4 */ "filestart", /* 5 */ "fileend", /* 6 */ "info", /* 7 */ "acct-check", /* 8 */ "acct-start", /* 9 */ "acct-end", /* 10 */ "acct-charge", /* 11 */ "control", NULL #line 1122 "printqd.ctr" }; /** Sub-commands of control. */ static const char * const control_sub_cmds[] = { /* 0 */ "r$eset", /* 1 */ "a$dd", /* 2 */ "d$atabase-cleanup", NULL #line 1134 "printqd.ctr" }; /** Argument names for control requests. */ static const char * const control_arg_names[] = { /* 0 */ "c$lass", /* 1 */ "u$ser", /* 2 */ "p$ages", NULL #line 1146 "printqd.ctr" }; /** Log feature names. */ static const char * const log_feature_names[] = { /* 0 */ "db", /* 1 */ "info", /* 2 */ "all", /* 3 */ "*", /* 4 */ "none", /* 5 */ "-", NULL #line 1161 "printqd.ctr" }; static const char * const db_type_names[] = { /* 0 */ "p", /* 1 */ "a", /* 2 */ "j", NULL #line 1171 "printqd.ctr" }; /** Daemon configuration. */ static pqd_conf_t conf; /** Connections over local socket, stores pqd_l_conn_t. Not NULL in service (service is not run if allocation fails). */ static dk4_sto_t *s_c_unix = NULL; /** Iterator through s_c_unix container. Not NULL in service (service is not run if allocation failes). */ static dk4_sto_it_t *i_c_unix = NULL; /** Container for TCP connections, stores pqd_n_conn_t. Not NULL in service (service is not run if allocation fails). */ static dk4_sto_t *s_c_tcp = NULL; /** Iterator through s_c_tcp container. Not NULL in service (service is not run if allocation fails). */ static dk4_sto_it_t *i_c_tcp = NULL; /** To accept TCP connections. May be NULL in service, if no TCP port number is conigured. */ static dk4_socket_set_t *ss_tcp = NULL; /** For info requests. May be NULL in service, if no UDP port number is configured. */ static dk4_socket_set_t *ss_udp = NULL; /** Database. Not NULL in service (service is not run if allocation fails). */ static dk4_dbi_t *db = NULL; /** Number of options in the options array. */ static const size_t szoptions = sizeof(options)/sizeof(dk4_option_t); /** Current connections on local socket. */ static size_t con_loc = 0; /** Current connections on TCP socket. */ static size_t con_tcp = 0; /** Timestamp of previous log message. */ static dk4_time_t prev_log_time = (dk4_time_t)0UL; /** Listen for incoming UNIX connection requests. Always set in service, service exits when failed to bind local address. */ static dk4_socket_t so_unix = INVALID_SOCKET; /** Program exit code, either EXIT_FAILURE or EXIT_SUCCESS. */ static int exval = EXIT_FAILURE; /** Flag: can continue outer (and inner) loop, 1=yes, 0=no, -1=abort. */ static int ccouter = 1; /** Flag: can continue inner loop, 1=yes, 0=no, -1=abort. */ static int ccinner = 1; /** Flag: User and group switching was already done. */ static int user_switched = 0; /** Syslog feature to use. */ static int syslogf = LOG_LPR; /** Flag: Modified since last synchronization. */ static int db_modified = 0; /** Flag: Debug mode, process runs in foreground and logs to stderr. */ static int debug = 0; /** Flag: Previous attempt to log to file failed. */ static int prev_filelog_failed = 0; /** Flag: Previous database modification failed. */ static int prev_dbmod_failed = 0; /** Flag: Previous database synchronization to disk failed. */ static int prev_dbsync_failed = 0; /** UID in previous pass. */ static uid_t prev_uid = (uid_t)0; /** GID in previous pass. */ static gid_t prev_gid = (gid_t)0; #ifdef SIGPIPE /** Indicator: SIGPIPE signal received. */ static DK4_VOLATILE dk4_sig_atomic_t sig_had_pipe = 0; #endif #ifdef SIGHUP /** Indicator: SIGHUP signal received. */ static DK4_VOLATILE dk4_sig_atomic_t sig_had_hup = 0; #endif /** Indicator: SIGINT signal received. */ static DK4_VOLATILE dk4_sig_atomic_t sig_had_int = 0; /** Indicator: SIGTERM signal received. */ static DK4_VOLATILE dk4_sig_atomic_t sig_had_term = 0; /** Pass pointer through. Use of this function is recommended by CERT C coding standard to avoid optimizing out. @param ptr Pointer to pass through. @return The ptr argument. */ static DK4_VOLATILE dk4_sig_atomic_t * sig_pass_pointer(DK4_VOLATILE dk4_sig_atomic_t *ptr) { return ptr; } #ifdef SIGPIPE /** Handler for SIGPIPE signal. @param signo Signal number (always SIGPIPE, ignored). */ static void sig_handler_pipe(int signo) { *sig_pass_pointer(&sig_had_pipe) = 1; } #endif #ifdef SIGHUP /** Handler for SIGHUP signal. @param signo Signal number (always SIGHUP, ignored). */ static void sig_handler_hup(int signo) { *sig_pass_pointer(&sig_had_hup) = 1; } #endif /** Handler for SIGINT signal. @param signo Signal number (always SIGINT, ignored). */ static void sig_handler_int(int signo) { *sig_pass_pointer(&sig_had_int) = 1; } /** Handler for SIGTERM signal. @param signo Signal number (always SIGTERM, ignored). */ static void sig_handler_term(int signo) { *sig_pass_pointer(&sig_had_term) = 1; } /** Read value from volatile atomic type. This function is necessary as some compilers mis-optimize direct access to volatile variables (at least if you believe one of the coding standards). @param ap Pointer to volatile atomic variable. @return Contents of the variable. */ static dk4_sig_atomic_t sig_read_atomic(DK4_VOLATILE dk4_sig_atomic_t *ap) { return (*ap); } /** Check whether we can continue or must abort due to signal. @param dopipe Flag: Check for SIGPIPE too. @return 1 if we can continue, 0 otherwise. */ static int can_continue(int dohup, int dopipe) { int back = 1; #line 1451 "printqd.ctr" if (0 != sig_read_atomic(&sig_had_term)) { back = 0; } if (0 != sig_read_atomic(&sig_had_int)) { back = 0; } #ifdef SIGHUP if (0 != dohup) { if (0 != sig_read_atomic(&sig_had_hup)) { back = 0; } if (1 > ccinner) { back = 0; } } #endif #ifdef SIGPIPE if (0 != dopipe) { if (0 != sig_read_atomic(&sig_had_pipe)) { back = 0; } } #endif if (1 > ccouter) { back = 0; } #line 1466 "printqd.ctr" return back; } /** Log a multi part message to file, either stderr or log file. @param fipo Output file. @param timebuf Text buffer containing timestamp. @param sourcefile Source file name. @param linebuf Text buffer containing source file line number. @param error Flag: Insert keyword "ERROR:" @param shtime Flag: Show timestamp from buffer. @param shline Flag: Show line number from buffer. @param msgs Array containing the message parts. @param szmsgs Number of elements in msgs array. */ static 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 ) { size_t i; #line 1499 "printqd.ctr" if (0 != shtime) { fputs(printqd_kw[6], fipo); fputs(timebuf, fipo); fputs(printqd_kw[5], fipo); } if (NULL != sourcefile) { fputs(sourcefile, fipo); if (0 != shline) { fputs(printqd_kw[8], fipo); fputs(linebuf, fipo); } fputs(printqd_kw[7], fipo); } if (0 != error) { fputs(printqd_kw[9], fipo); } for (i = 0; i < szmsgs; i++) { if (NULL != msgs[i]) { fputs(msgs[i], fipo); } } fputs(printqd_kw[5], fipo); fflush(fipo); #line 1523 "printqd.ctr" } /** Write a log message consisting of multiple parts. @param sourcefile Configuration file name. @param sourceline Configuration file line number. @param sll Syslog level. @param msgs Array containing the message parts. @param szmsgs Number of elements in msgs array. */ static void log_multipart_message( const char *sourcefile, unsigned long sourceline, int sll, int error, char const * const *msgs, size_t szmsgs ) { char timebuf[64]; char linebuf[64]; FILE *fipo; const char *lfn; dk4_time_t current; int stests = DK4_FOPEN_SC_PRIVILEGED; int shtime = 0; int shline = 0; #line 1554 "printqd.ctr" /* Check whether to prepend a timestamp line. */ dk4time_get(¤t); if (current != prev_log_time) { prev_log_time = current; if (0 != dk4time_as_text_c8(timebuf, sizeof(timebuf), ¤t, NULL)) { shtime = 1; } } /* Check whether to prepend source file name and line number. */ if ((NULL != sourcefile) && ((dk4_um_t)0UL != sourceline)) { shline = dk4ma_write_c8_decimal_unsigned( linebuf, sizeof(linebuf), (dk4_um_t)sourceline, 0, NULL ); } /* Output to log file. */ lfn = conf.lname; if (NULL == lfn) { lfn = def_log_file_name; } fipo = dk4fopen_c8(lfn, printqd_kw[10], stests, NULL); if (NULL != fipo) { prev_filelog_failed = 0; log_file_multipart_message( fipo, timebuf, sourcefile, linebuf, error, shtime, shline, msgs, szmsgs ); fclose(fipo); } else { #if DK4_HAVE_SYSLOG if (0 == prev_filelog_failed) { openlog(printqd_kw[0], LOG_PID, syslogf); syslog(LOG_ERR, "%s%s%s", printqd_kw[170], lfn, printqd_kw[171]); closelog(); } #endif prev_filelog_failed = 1; } /* Output to stderr when debugging. */ if (0 != debug) { log_file_multipart_message( stderr, timebuf, sourcefile, linebuf, error, shtime, shline, msgs, szmsgs ); } /* Output to syslog. */ if (LOG_EMERG != sll) { #if DK4_HAVE_SYSLOG openlog(printqd_kw[0], LOG_PID, syslogf); if (1 < szmsgs) { if (2 < szmsgs) { if (3 < szmsgs) { if (4 < szmsgs) { if (5 < szmsgs) { if (6 < szmsgs) { if (7 < szmsgs) { if (8 < szmsgs) { syslog( sll, "%s%s%s%s%s%s%s%s%s", ((NULL != msgs[0]) ? (msgs[0]) : (printqd_kw[11])), ((NULL != msgs[1]) ? (msgs[1]) : (printqd_kw[11])), ((NULL != msgs[2]) ? (msgs[2]) : (printqd_kw[11])), ((NULL != msgs[3]) ? (msgs[3]) : (printqd_kw[11])), ((NULL != msgs[4]) ? (msgs[4]) : (printqd_kw[11])), ((NULL != msgs[5]) ? (msgs[5]) : (printqd_kw[11])), ((NULL != msgs[6]) ? (msgs[6]) : (printqd_kw[11])), ((NULL != msgs[7]) ? (msgs[7]) : (printqd_kw[11])), ((NULL != msgs[8]) ? (msgs[8]) : (printqd_kw[11])) ); } else { syslog( sll, "%s%s%s%s%s%s%s%s", ((NULL != msgs[0]) ? (msgs[0]) : (printqd_kw[11])), ((NULL != msgs[1]) ? (msgs[1]) : (printqd_kw[11])), ((NULL != msgs[2]) ? (msgs[2]) : (printqd_kw[11])), ((NULL != msgs[3]) ? (msgs[3]) : (printqd_kw[11])), ((NULL != msgs[4]) ? (msgs[4]) : (printqd_kw[11])), ((NULL != msgs[5]) ? (msgs[5]) : (printqd_kw[11])), ((NULL != msgs[6]) ? (msgs[6]) : (printqd_kw[11])), ((NULL != msgs[7]) ? (msgs[7]) : (printqd_kw[11])) ); } } else { syslog( sll, "%s%s%s%s%s%s%s", ((NULL != msgs[0]) ? (msgs[0]) : (printqd_kw[11])), ((NULL != msgs[1]) ? (msgs[1]) : (printqd_kw[11])), ((NULL != msgs[2]) ? (msgs[2]) : (printqd_kw[11])), ((NULL != msgs[3]) ? (msgs[3]) : (printqd_kw[11])), ((NULL != msgs[4]) ? (msgs[4]) : (printqd_kw[11])), ((NULL != msgs[5]) ? (msgs[5]) : (printqd_kw[11])), ((NULL != msgs[6]) ? (msgs[6]) : (printqd_kw[11])) ); } } else { syslog( sll, "%s%s%s%s%s%s", ((NULL != msgs[0]) ? (msgs[0]) : (printqd_kw[11])), ((NULL != msgs[1]) ? (msgs[1]) : (printqd_kw[11])), ((NULL != msgs[2]) ? (msgs[2]) : (printqd_kw[11])), ((NULL != msgs[3]) ? (msgs[3]) : (printqd_kw[11])), ((NULL != msgs[4]) ? (msgs[4]) : (printqd_kw[11])), ((NULL != msgs[5]) ? (msgs[5]) : (printqd_kw[11])) ); } } else { syslog( sll, "%s%s%s%s%s", ((NULL != msgs[0]) ? (msgs[0]) : (printqd_kw[11])), ((NULL != msgs[1]) ? (msgs[1]) : (printqd_kw[11])), ((NULL != msgs[2]) ? (msgs[2]) : (printqd_kw[11])), ((NULL != msgs[3]) ? (msgs[3]) : (printqd_kw[11])), ((NULL != msgs[4]) ? (msgs[4]) : (printqd_kw[11])) ); } } else { syslog( sll, "%s%s%s%s", ((NULL != msgs[0]) ? (msgs[0]) : (printqd_kw[11])), ((NULL != msgs[1]) ? (msgs[1]) : (printqd_kw[11])), ((NULL != msgs[2]) ? (msgs[2]) : (printqd_kw[11])), ((NULL != msgs[3]) ? (msgs[3]) : (printqd_kw[11])) ); } } else { syslog( sll, "%s%s%s", ((NULL != msgs[0]) ? (msgs[0]) : (printqd_kw[11])), ((NULL != msgs[1]) ? (msgs[1]) : (printqd_kw[11])), ((NULL != msgs[2]) ? (msgs[2]) : (printqd_kw[11])) ); } } else { syslog( sll, "%s%s", ((NULL != msgs[0]) ? (msgs[0]) : (printqd_kw[11])), ((NULL != msgs[1]) ? (msgs[1]) : (printqd_kw[11])) ); } } else { syslog( sll, "%s", ((NULL != msgs[0]) ? (msgs[0]) : (printqd_kw[11])) ); } closelog(); #endif } #line 1707 "printqd.ctr" } static void log_1( const char *sourcefile, unsigned long sourceline, int sll, int error, size_t i1 ) { const char *msgs[2]; #line 1723 "printqd.ctr" msgs[0] = printqd_kw[i1]; msgs[1] = NULL; log_multipart_message(sourcefile, sourceline, sll, error, msgs, 1); #line 1727 "printqd.ctr" } static void log_3( const char *sourcefile, unsigned long sourceline, int sll, int error, size_t i1, size_t i2, const char *s1 ) { const char *msgs[4]; #line 1745 "printqd.ctr" msgs[0] = printqd_kw[i1]; msgs[1] = s1; msgs[2] = printqd_kw[i2]; msgs[3] = NULL; log_multipart_message(sourcefile, sourceline, sll, error, msgs, 3); #line 1751 "printqd.ctr" } static 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 ) { const char *msgs[6]; #line 1771 "printqd.ctr" msgs[0] = printqd_kw[i1]; msgs[1] = s1; msgs[2] = printqd_kw[i2]; msgs[3] = s2; msgs[4] = printqd_kw[i3]; msgs[5] = NULL; log_multipart_message(sourcefile, sourceline, sll, error, msgs, 5); #line 1779 "printqd.ctr" } /** Set database entry (create or modify). @param db Database to modify. @param k Key. @param v Value. @param erp Error report, may be NULL. @return 1 on success, 0 on error. */ static int dbi_set( dk4_dbi_t *db, const char *k, const char *v, dk4_er_t *erp ) { dk4_er_t er; int back = 0; dk4error_init(&er); back = dk4dbi_c8_set(db, k, v, &er); dk4error_copy(erp, &er); db_modified = 1; if (0 != back) { prev_dbmod_failed = 0; if (0 != conf.ldb) { log_5(NULL, 0UL, LOG_EMERG, 0, 122, 123, 124, k, v); } } else { #if DK4_HAVE_SYSLOG if (0 == prev_dbmod_failed) { openlog(printqd_kw[0], LOG_PID, syslogf); syslog(LOG_ERR, "%s", printqd_kw[172]); closelog(); } #endif prev_dbmod_failed = 1; switch (er.ec) { case DK4_E_INVALID_ARGUMENTS : { log_5(NULL, 0UL, LOG_EMERG, 1, 122, 123, 125, k, v); } break; case DK4_E_SYNTAX : { log_5(NULL, 0UL, LOG_EMERG, 1, 122, 123, 126, k, v); } break; case DK4_E_MATH_OVERFLOW : { log_5(NULL, 0UL, LOG_EMERG, 1, 122, 123, 127, k, v); } break; case DK4_E_NOT_SUPPORTED : { log_5(NULL, 0UL, LOG_EMERG, 1, 122, 123, 128, k, v); } break; case DK4_E_NOT_FOUND : { log_5(NULL, 0UL, LOG_EMERG, 1, 122, 123, 129, k, v); } break; case DK4_E_MEMORY_ALLOCATION_FAILED : { log_5(NULL, 0UL, LOG_EMERG, 1, 122, 123, 130, k, v); } break; case DK4_E_WRITE_FAILED : { log_5(NULL, 0UL, LOG_EMERG, 1, 122, 123, 131, k, v); } break; default : { log_5(NULL, 0UL, LOG_EMERG, 1, 122, 123, 132, k, v); } break; } } return back; } /** Retrieve database entry. @param db Database to retrieve data from. @param k Key text. @param vbuf Buffer for text value. @param vsz Size of buffer. @param erp Error report, may be NULL. @return 1 on success, 0 on error. */ static int dbi_get( dk4_dbi_t *db, const char *k, char *vbuf, size_t vsz, dk4_er_t *erp ) { dk4_er_t er; int back = 0; dk4error_init(&er); back = dk4dbi_c8_get(db, k, vbuf, vsz, &er); dk4error_copy(erp, &er); if (0 != back) { if (0 != conf.ldb) { log_5(NULL, 0UL, LOG_EMERG, 0, 133, 123, 124, k, vbuf); } } else { switch (er.ec) { case DK4_E_INVALID_ARGUMENTS : { log_3(NULL, 0UL, LOG_EMERG, 1, 133, 125, k); } break; case DK4_E_MATH_OVERFLOW : { log_3(NULL, 0UL, LOG_EMERG, 1, 133, 127, k); } break; case DK4_E_NOT_SUPPORTED : { log_3(NULL, 0UL, LOG_EMERG, 1, 133, 128, k); } break; case DK4_E_NOT_FOUND : { if (0 != conf.ldb) { log_3(NULL, 0UL, LOG_EMERG, 1, 133, 129, k); } } break; case DK4_E_BUFFER_TOO_SMALL : { log_3(NULL, 0UL, LOG_EMERG, 1, 133, 134, k); } break; default : { log_3(NULL, 0UL, LOG_EMERG, 1, 133, 132, k); } break; } } return back; } /** Delete DB entry if it exists. @param db Database to modify. @param k Key. @param erp Error report, may be NULL. @return 1 on success, 0 on error. */ static int dbi_del( dk4_dbi_t *db, const char *k, dk4_er_t *erp ) { dk4_er_t er; int back = 0; dk4error_init(&er); back = dk4dbi_c8_del(db, k, &er); dk4error_copy(erp, &er); db_modified = 1; if (0 != back) { prev_dbmod_failed = 0; if (0 != conf.ldb) { log_3(NULL, 0UL, LOG_EMERG, 0, 135, 124, k); } } else { if (DK4_E_NOT_FOUND != er.ec) { #if DK4_HAVE_SYSLOG if (0 == prev_dbmod_failed) { openlog(printqd_kw[0], LOG_PID, syslogf); syslog(LOG_ERR, "%s", printqd_kw[172]); closelog(); } #endif prev_dbmod_failed = 1; } switch (er.ec) { case DK4_E_INVALID_ARGUMENTS : { log_3(NULL, 0UL, LOG_EMERG, 1, 135, 125, k); } break; case DK4_E_SYNTAX : { log_3(NULL, 0UL, LOG_EMERG, 1, 135, 126, k); } break; case DK4_E_MATH_OVERFLOW : { log_3(NULL, 0UL, LOG_EMERG, 1, 135, 127, k); } break; case DK4_E_NOT_SUPPORTED : { log_3(NULL, 0UL, LOG_EMERG, 1, 135, 128, k); } break; case DK4_E_WRITE_FAILED : { log_3(NULL, 0UL, LOG_EMERG, 1, 135, 131, k); } break; case DK4_E_NOT_FOUND : { if (0 != conf.ldb) { log_3(NULL, 0UL, LOG_EMERG, 1, 135, 129, k); } } break; default : { log_3(NULL, 0UL, LOG_EMERG, 1, 135, 132, k); } break; } } return back; } /** Synchronize database modifications to disk, if any. @param db Database. @param erp Error report, may be NULL. @return 1 on success, 0 on error. */ static int dbi_sync(dk4_dbi_t *db, dk4_er_t *erp) { dk4_er_t er; int back = 0; if (0 != db_modified) { dk4error_init(&er); back = dk4dbi_sync(db, &er); dk4error_copy(erp, &er); if (0 != back) { db_modified = 0; prev_dbsync_failed = 0; if (0 != conf.ldb) { log_1(NULL, 0UL, LOG_EMERG, 0, 136); } } else { #if DK4_HAVE_SYSLOG if (0 == prev_dbsync_failed) { openlog(printqd_kw[0], LOG_PID, syslogf); syslog(LOG_ERR, "%s", printqd_kw[173]); closelog(); } #endif prev_dbsync_failed = 1; switch (er.ec) { case DK4_E_INVALID_ARGUMENTS : { log_1(NULL, 0UL, LOG_EMERG, 1, 137); } break; case DK4_E_NOT_SUPPORTED : { log_1(NULL, 0UL, LOG_EMERG, 1, 138); } break; case DK4_E_SYNTAX : { log_1(NULL, 0UL, LOG_EMERG, 1, 139); } break; case DK4_E_SEC_CHECK : { log_1(NULL, 0UL, LOG_EMERG, 1, 140); } break; case DK4_E_OPEN_WRITE_FAILED : { log_1(NULL, 0UL, LOG_EMERG, 1, 141); } break; case DK4_E_WRITE_FAILED : { log_1(NULL, 0UL, LOG_EMERG, 1, 142); } break; case DK4_E_CLOSE_FAILED : { log_1(NULL, 0UL, LOG_EMERG, 1, 143); } break; default : { log_1(NULL, 0UL, LOG_EMERG, 1, 144); } break; } } } else { back = 1; } return back; } /** Compare two pqd_l_conn_t structures. @param l Left object. @param r Right object. @param cr Comparison criteria, ignored. @return Comparison result. */ static int compare_pqd_l_conn_t(const void *l, const void *r, int cr) { const pqd_l_conn_t *pl; const pqd_l_conn_t *pr; int back = 0; #line 2056 "printqd.ctr" if (NULL != l) { if (NULL != r) { pl = (const pqd_l_conn_t *)l; pr = (const pqd_l_conn_t *)r; if (pl->sock > pr->sock) { back = 1; } else { if (pl->sock < pr->sock) { back = -1; } } } else { back = 1; } } else { if (NULL != r) { back = -1; } } #line 2074 "printqd.ctr" return back; } /** Compare two pqd_n_conn_t structures. @param l Left object. @param r Right object. @param cr Comparison criteria, ignored. @return Comparison result. */ static int compare_pqd_n_conn_t(const void *l, const void *r, int cr) { const pqd_n_conn_t *pl; const pqd_n_conn_t *pr; int back = 0; #line 2093 "printqd.ctr" if (NULL != l) { if (NULL != r) { pl = (const pqd_n_conn_t *)l; pr = (const pqd_n_conn_t *)r; if (pl->sock > pr->sock) { back = 1; } else { if (pl->sock < pr->sock) { back = -1; } } } else { back = 1; } } else { if (NULL != r) { back = -1; } } #line 2111 "printqd.ctr" return back; } /** Delete a limit structure (release memory). @param ptr Limit to delete. */ static void limit_delete(pqd_limit_t *ptr) { #line 2124 "printqd.ctr" if (NULL != ptr) { #line 2125 "printqd.ctr" dk4mem_release(ptr->name); ptr->limit = (dk4_um_t)0UL; dk4mem_free(ptr); } #line 2130 "printqd.ctr" } /** Create limit structure (allocate memory). @param name User or group name. @param max Maximum page number. @return Valid pointer on success, NULL on error. */ static pqd_limit_t * limit_new(const char *name, dk4_um_t max) { pqd_limit_t *back = NULL; #line 2145 "printqd.ctr" if (NULL != name) { #line 2146 "printqd.ctr" back = dk4mem_new(pqd_limit_t,1,NULL); if (NULL != back) { #line 2148 "printqd.ctr" back->limit = max; back->name = dk4str8_dup(name, NULL); if (NULL == back->name) { #line 2151 "printqd.ctr" limit_delete(back); back = NULL; } } #if TRACE_DEBUG else { #line 2157 "printqd.ctr" } #endif } #line 2160 "printqd.ctr" return back; } /** Compare limit structures. @param l Left object. @param r Right object. @param cr Comparison criteria (0=limit/limit, 1=limit/name). @return Comparison result. */ static int limit_compare(const void *l, const void *r, int cr) { const pqd_limit_t *pl; const pqd_limit_t *pr; #line 2178 "printqd.ctr" int back = 0; if (NULL != l) { if (NULL != r) { pl = (const pqd_limit_t *)l; switch (cr) { case 1: { if (NULL != pl->name) { back = strcmp(pl->name, (const char *)r); if (-1 > back) { back = -1; } if ( 1 < back) { back = 1; } } else { back = -1; } } break; default: { pr = (const pqd_limit_t *)r; if (NULL != pl->name) { if (NULL != pr->name) { back = strcmp(pl->name, pr->name); if (-1 > back) { back = -1; } if ( 1 < back) { back = 1; } } else { back = 1; } } else { if (NULL != pr->name) { back = -1; } } } break; } } else { back = 1; } } else { if (NULL != r) { back = -1; } } #line 2207 "printqd.ctr" return back; } /** Delete all limits in a storage. @param it Storage iterator. */ static void limit_all_delete(dk4_sto_it_t *it) { pqd_limit_t *ptr; #line 2222 "printqd.ctr" dk4sto_it_reset(it); do { ptr = (pqd_limit_t *)dk4sto_it_next(it); if (NULL != ptr) { limit_delete(ptr); } } while (NULL != ptr); dk4sto_it_close(it); #line 2231 "printqd.ctr" } /** Delete a class structure (release memory). @param ptr Class to delete. */ static void class_delete(pqd_class_t *ptr) { #line 2243 "printqd.ctr" if (NULL != ptr) { #line 2244 "printqd.ctr" dk4mem_release(ptr->name); if (NULL != ptr->i_u) { limit_all_delete(ptr->i_u); } ptr->i_u = NULL; if (NULL != ptr->s_u) { dk4sto_close(ptr->s_u); } ptr->s_u = NULL; if (NULL != ptr->i_g) { limit_all_delete(ptr->i_g); } ptr->i_g = NULL; if (NULL != ptr->s_g) { dk4sto_close(ptr->s_g); } ptr->s_g = NULL; ptr->dl = (dk4_um_t)0UL; ptr->da = 0; dk4mem_free(ptr); } #if TRACE_DEBUG else { #line 2263 "printqd.ctr" } #endif #line 2266 "printqd.ctr" } /** Delete all classes from a containter. @param it Container iterator. */ static void class_all_delete(dk4_sto_it_t *it) { pqd_class_t *ptr; #line 2279 "printqd.ctr" dk4sto_it_reset(it); do { ptr = (pqd_class_t *)dk4sto_it_next(it); if (NULL != ptr) { class_delete(ptr); } } while (NULL != ptr); dk4sto_it_close(it); #line 2288 "printqd.ctr" } /** Create a class structure (allocate memory). @param n Class name. @return Valid pointer on success, NULL on error. */ static pqd_class_t * class_new(const char *n) { pqd_class_t *back = NULL; int ok = 0; #line 2303 "printqd.ctr" if (NULL != n) { #line 2304 "printqd.ctr" back = dk4mem_new(pqd_class_t,1,NULL); if (NULL != back) { back->s_u = NULL; back->i_u = NULL; back->s_g = NULL; back->i_g = NULL; back->dl = (dk4_um_t)0UL; back->da = 0; back->hdl = 0; back->name = dk4str8_dup(n, NULL); if (NULL != back->name) { back->s_u = dk4sto_open(NULL); if (NULL != back->s_u) { dk4sto_set_comp(back->s_u, limit_compare, 0); back->i_u = dk4sto_it_open(back->s_u, NULL); if (NULL != back->i_u) { back->s_g = dk4sto_open(NULL); if (NULL != back->s_g) { dk4sto_set_comp(back->s_g, limit_compare, 0); back->i_g = dk4sto_it_open(back->s_g, NULL); if (NULL != back->i_g) { ok = 1; #line 2326 "printqd.ctr" } #if TRACE_DEBUG else { #line 2329 "printqd.ctr" } #endif } #if TRACE_DEBUG else { #line 2334 "printqd.ctr" } #endif } #if TRACE_DEBUG else { #line 2339 "printqd.ctr" } #endif } #if TRACE_DEBUG else { #line 2344 "printqd.ctr" } #endif } #if TRACE_DEBUG else { #line 2349 "printqd.ctr" } #endif if (0 == ok) { #line 2352 "printqd.ctr" class_delete(back); back = NULL; } } #if TRACE_DEBUG else { #line 2358 "printqd.ctr" } #endif } #if TRACE_DEBUG else { #line 2363 "printqd.ctr" } #endif #line 2366 "printqd.ctr" return back; } /** Compare classes. @param l Left object. @param r Right object. @param cr Comparison criteria (0=class/class, 1=class/name). @return Comparison result. */ static int class_compare(const void *l, const void *r, int cr) { const pqd_class_t *pl; const pqd_class_t *pr; int back = 0; #line 2385 "printqd.ctr" if (NULL != l) { if (NULL != r) { pl = (const pqd_class_t *)l; switch (cr) { case 1: { if (NULL != pl->name) { back = strcmp(pl->name, (const char *)r); if (-1 > back) { back = -1; } if ( 1 < back) { back = 1; } } else { back = -1; } } break; default: { pr = (const pqd_class_t *)r; if (NULL != pl->name) { if (NULL != pr->name) { back = strcmp(pl->name, pr->name); if (-1 > back) { back = -1; } if ( 1 < back) { back = 1; } } else { back = 1; } } else { if (NULL != pr->name) { back = -1; } } } break; } } else { back = 1; } } else { if (NULL != r) { back = -1; } } #line 2413 "printqd.ctr" return back; } /** Delete a printer structure (release memory). @param ptr Printer structure to delete. */ static void printer_delete(pqd_printer_t *ptr) { #line 2426 "printqd.ctr" if (NULL != ptr) { #line 2427 "printqd.ctr" dk4mem_release(ptr->name); ptr->cl = NULL; dk4mem_free(ptr); } #line 2432 "printqd.ctr" } /** Create printer structure (allocate memory). @param n Printer name. @return Valid pointer on success, NULL on error. */ static pqd_printer_t * printer_new(const char *n) { pqd_printer_t *back = NULL; #line 2446 "printqd.ctr" if (NULL != n) { back = dk4mem_new(pqd_printer_t,1,NULL); if (NULL != back) { back->cl = NULL; back->name = dk4str8_dup(n,NULL); if (NULL == back->name) { #line 2452 "printqd.ctr" printer_delete(back); back = NULL; } } #if TRACE_DEBUG else { #line 2458 "printqd.ctr" } #endif } #if TRACE_DEBUG else { #line 2463 "printqd.ctr" } #endif #line 2466 "printqd.ctr" return back; } /** Compare two printers. @param l Left object. @param r Right object. @param cr Comparison criteria (0=printer/printer, 1=printer/name). @return Comparison result. */ static int printer_compare(const void *l, const void *r, int cr) { const pqd_printer_t *pl; const pqd_printer_t *pr; int back = 0; #line 2485 "printqd.ctr" if (NULL != l) { if (NULL != r) { pl = (const pqd_printer_t *)l; switch (cr) { case 1: { if (NULL != pl->name) { back = strcmp(pl->name, (const char *)r); if (-1 > back) { back = -1; } if ( 1 < back) { back = 1; } } else { back = -1; } } break; default: { pr = (const pqd_printer_t *)r; if (NULL != pl->name) { if (NULL != pr->name) { back = strcmp(pl->name, pr->name); if (-1 > back) { back = -1; } if ( 1 < back) { back = 1; } } else { back = 1; } } else { if (NULL != pr->name) { back = -1; } } } break; } } else { back = 1; } } else { if (NULL != r) { back = -1; } } #line 2513 "printqd.ctr" return back; } /** Delete all printers from a container. @param it Container iterator. */ static void printer_all_delete(dk4_sto_it_t *it) { pqd_printer_t *ptr; #line 2527 "printqd.ctr" dk4sto_it_reset(it); do { ptr = (pqd_printer_t *)dk4sto_it_next(it); if (NULL != ptr) { printer_delete(ptr); } } while (NULL != ptr); dk4sto_it_close(it); #line 2536 "printqd.ctr" } /** Delete printer alias structure (release memory). @param ptr Structure to delete. */ static void printer_alias_delete(pqd_printer_alias_t *ptr) { #line 2548 "printqd.ctr" if (NULL != ptr) { #line 2549 "printqd.ctr" dk4mem_release(ptr->name); ptr->pr = NULL; dk4mem_free(ptr); } #line 2554 "printqd.ctr" } /** Create printer alias structure (allocate memory). @param n Alias name. @param pr Printer for alias. @return Valid pointer on success, NULL on error. */ static pqd_printer_alias_t * printer_alias_new(const char *n, pqd_printer_t *pr) { pqd_printer_alias_t *back = NULL; #line 2569 "printqd.ctr" if ((NULL != n) && (NULL != pr)) { back = dk4mem_new(pqd_printer_alias_t,1,NULL); if (NULL != back) { back->pr = pr; back->name = dk4str8_dup(n,NULL); if (NULL == back->name) { printer_alias_delete(back); back = NULL; } #if TRACE_DEBUG else { #line 2580 "printqd.ctr" } #endif } #if TRACE_DEBUG else { #line 2585 "printqd.ctr" } #endif } #if TRACE_DEBUG else { #line 2590 "printqd.ctr" } #endif #line 2593 "printqd.ctr" return back; } /** Compare printer alias structures. @param l Left object. @param r Right object. @param cr Comparison criteria (0=alias/alias, 1=alias/name). @return Comparison result. */ static int printer_alias_compare(const void *l, const void *r, int cr) { const pqd_printer_alias_t *pl; const pqd_printer_alias_t *pr; int back = 0; #line 2612 "printqd.ctr" if (NULL != l) { if (NULL != r) { pl = (const pqd_printer_alias_t *)l; switch (cr) { case 1: { if (NULL != pl->name) { back = strcmp(pl->name, (const char *)r); if (-1 > back) { back = -1; } if ( 1 < back) { back = 1; } } else { back = -1; } } break; default: { pr = (const pqd_printer_alias_t *)r; if (NULL != pl->name) { if (NULL != pr->name) { back = strcmp(pl->name, pr->name); if (-1 > back) { back = -1; } if ( 1 < back) { back = 1; } } else { back = 1; } } else { if (NULL != pr->name) { back = -1; } } } break; } } else { back = 1; } } else { if (NULL != r) { back = -1; } } #line 2640 "printqd.ctr" return back; } /** Delete all printer alias structures in a container. @param it Container iterator. */ static void printer_alias_all_delete(dk4_sto_it_t *it) { pqd_printer_alias_t *ptr; #line 2654 "printqd.ctr" dk4sto_it_reset(it); do { ptr = (pqd_printer_alias_t *)dk4sto_it_next(it); if (NULL != ptr) { printer_alias_delete(ptr); } } while (NULL != ptr); dk4sto_it_close(it); #line 2663 "printqd.ctr" } /** Initialize configuration before reading configuration file. */ static void config_init(void) { #line 2674 "printqd.ctr" DK4_MEMRES(&conf, sizeof(conf)); conf.sname = NULL; conf.dname = NULL; conf.lname = NULL; conf.s_c = NULL; conf.i_c = NULL; conf.s_p = NULL; conf.i_p = NULL; conf.s_a = NULL; conf.i_a = NULL; conf.s_ai = NULL; conf.i_ai = NULL; conf.s_ad = NULL; conf.i_ad = NULL; conf.s_aa = NULL; conf.i_aa = NULL; conf.m_loc = 0; /* Maximum 0 means unlimited number of connections. */ conf.m_tcp = 0; /* Maximum 0 means unlimited number of connections. */ conf.uid = 0; conf.gid = 0; conf.suid = 0; conf.sgid = 0; conf.slbl = 5; conf.snbl = 5; conf.iglo = 0; conf.dglo = 0; conf.aglo = 0; conf.ptcp = 0; conf.pudp = 0; conf.linf = 0; conf.ldb = 0; #line 2706 "printqd.ctr" } /** Allocate internal structures for configuration. @return 1 on success, 0 on error. */ static int config_allocate(void) { int back = 0; #line 2719 "printqd.ctr" conf.s_c = dk4sto_open(NULL); conf.s_p = dk4sto_open(NULL); conf.s_a = dk4sto_open(NULL); conf.s_ai = dk4sto_open(NULL); conf.s_ad = dk4sto_open(NULL); conf.s_aa = dk4sto_open(NULL); if ((NULL != conf.s_ai) && (NULL != conf.s_ad) && (NULL != conf.s_aa)) { if ((NULL != conf.s_c) && (NULL != conf.s_p) && (NULL != conf.s_a)) { dk4sto_set_comp(conf.s_c, class_compare, 0); dk4sto_set_comp(conf.s_p, printer_compare, 0); dk4sto_set_comp(conf.s_a, printer_alias_compare, 0); dk4sto_set_comp(conf.s_ai, dk4socket_allowed_peer_compare, 0); dk4sto_set_comp(conf.s_ad, dk4socket_allowed_peer_compare, 0); dk4sto_set_comp(conf.s_aa, dk4socket_allowed_peer_compare, 0); conf.i_c = dk4sto_it_open(conf.s_c, NULL); conf.i_p = dk4sto_it_open(conf.s_p, NULL); conf.i_a = dk4sto_it_open(conf.s_a, NULL); conf.i_ai = dk4sto_it_open(conf.s_ai, NULL); conf.i_ad = dk4sto_it_open(conf.s_ad, NULL); conf.i_aa = dk4sto_it_open(conf.s_aa, NULL); if ((NULL != conf.i_ai) && (NULL != conf.i_ad) && (NULL != conf.i_aa)) { if ((NULL != conf.i_c) && (NULL != conf.i_p) && (NULL != conf.i_a)) { back = 1; } #if TRACE_DEBUG else { #line 2745 "printqd.ctr" } #endif } #if TRACE_DEBUG else { #line 2750 "printqd.ctr" } #endif } #if TRACE_DEBUG else { #line 2755 "printqd.ctr" } #endif } #if TRACE_DEBUG else { #line 2760 "printqd.ctr" } #endif #line 2763 "printqd.ctr" return back; } /** Set backlog variable. @param iptr Address of backlog number variable. @param pv Text containing the number. @param fn File name for diagnostics. @param lineno Line number. @return 1 on success, 0 on error. */ static int set_backlog(int *iptr, char *pv, const char *fn, unsigned long lineno) { const char *ep = NULL; int i = 0; int back = 0; int res = 0; #line 2784 "printqd.ctr" res = dk4ma_input_c8_dec_int(&i, pv, &ep, 1, NULL); if (0 != res) { if (0 < i) { *iptr = i; back = 1; } else { #line 2790 "printqd.ctr" /* ERROR: Must be positive */ log_1(fn, lineno, LOG_EMERG, 1, 15); } } else { #line 2794 "printqd.ctr" /* ERROR: Not an integer number */ log_5(fn, lineno, LOG_EMERG, 1, 12, 13, 14, pv, ep); } #line 2797 "printqd.ctr" return back; } /** Set maximum number of connections. @param pmaxconn Address of result variable. @param pv Text containing the number. @param fn File name for diagnostics. @param lineno Line number. @return 1 on success, 0 on error. */ static int set_max_connections( size_t *pmaxconn, char *pv, const char *fn, unsigned long lineno ) { const char *ep = NULL; size_t sz = 0; int back = 0; int res = 0; #line 2823 "printqd.ctr" res = dk4ma_input_c8_dec_size_t(&sz, pv, &ep, 1, NULL); if (0 != res) { *pmaxconn = sz; back = 1; } else { #line 2828 "printqd.ctr" /* ERROR: Not a size specification */ log_5(fn, lineno, LOG_EMERG, 1, 16, 17, 18, pv, ep); } #line 2832 "printqd.ctr" return back; } /** Set port number from text. @param ppn Address of port number variable. @param pv Text containing the number. @return 1 on success, 0 on error. */ static int set_port_number( unsigned short *ppn, char *pv, const char *fn, unsigned long lineno ) { const char *ep = NULL; unsigned short pn = 0; int back = 0; int res = 0; #line 2856 "printqd.ctr" res = dk4ma_input_c8_dec_ushort(&pn, pv, &ep, 1, NULL); if (0 != res) { if (0 < pn) { *ppn = pn; back = 1; } else { #line 2862 "printqd.ctr" /* ERROR: Port number must not be 0 */ log_1(fn, lineno, LOG_EMERG, 1, 22); } } else { #line 2866 "printqd.ctr" /* ERROR: Not a 16 bit unsigned number */ log_5(fn, lineno, LOG_EMERG, 1, 19, 20, 21, pv, ep); } #line 2870 "printqd.ctr" return back; } /** Add address to list of allowed hosts. @param s Containter of allowed peers. @param i Iterator through container. @param iptr Address of global flag variable. @param str Text containing the address. @return 1 on success, 0 on error. */ static int allow_hosts( dk4_sto_t *s, dk4_sto_it_t *i, int *iptr, char *str, const char *filename, unsigned long lineno ) { dk4_allowed_peer_t ap; dk4_allowed_peer_t *pap; char *px = NULL; int res = 0; int back = 0; #line 2899 "printqd.ctr" px = dk4str8_next(str, NULL); if (NULL == px) { if (0 == strcmp(str, printqd_kw[2])) { *iptr = 1; back = 1; } else { DK4_MEMRES(&ap, sizeof(ap)); res = dk4socket_c8_get_allowed_peer(&ap, str, NULL); if (DK4_SOCKET_RESULT_SUCCESS == res) { pap = dk4mem_new(dk4_allowed_peer_t,1,NULL); if (NULL != pap) { DK4_MEMCPY(pap, &ap, sizeof(ap)); if (0 != dk4sto_add(s, pap, NULL)) { back = 1; } else { #line 2914 "printqd.ctr" dk4mem_free(pap); /* ERROR: Memory */ log_1(filename, lineno, LOG_EMERG, 1, 27); } } else { #line 2919 "printqd.ctr" /* ERROR: Memory */ log_1(filename, lineno, LOG_EMERG, 1, 27); } } else { #line 2923 "printqd.ctr" /* ERROR: Syntax, not a peer definition */ log_3(filename, lineno, LOG_EMERG, 1, 25, 26, str); } } } else { #line 2928 "printqd.ctr" /* ERROR: Unexpected text */ log_3(filename, lineno, LOG_EMERG, 1, 23, 24, px); } #line 2932 "printqd.ctr" return back; } /** Obtain limit value from text. @param plim Address of limit variable to set. @param src Text containing the limit. @return 1 on success, 0 on error. */ static int get_limit_value(dk4_um_t *plim, char *src, const char *fn, unsigned long lineno) { const char *ep = NULL; dk4_um_t value = (dk4_um_t)0UL; int back = 0; int res = 0; #line 2951 "printqd.ctr" if (0 == strcmp(src, printqd_kw[3])) { *plim = DK4_UM_MAX; back = 1; } else { if (0 == strcmp(src, printqd_kw[4])) { *plim = value; back = 1; } else { res = dk4ma_input_c8_dec_dk4_um_t(&value, src, &ep, 1, NULL); if (0 != res) { *plim = value; back = 1; } else { #line 2964 "printqd.ctr" /* ERROR: Syntax, not an unsigned number */ log_5(fn, lineno, LOG_EMERG, 1, 28, 29, 30, src, ep); } } } #line 2970 "printqd.ctr" return back; } /** Add a user or group limit to a class. @param pcl Class to modify. @param s Container for limits. @param i Container iterator. @param str Text containing name and limit. @param fn File name. @param lineno Line number. @return 1 on success, 0 on error. */ static int add_limit( pqd_class_t *pcl, dk4_sto_t *s, dk4_sto_it_t *i, char *str, const char *fn, dk4_um_t lineno ) { pqd_limit_t *plim; char *pnum; char *px; dk4_um_t limval = (dk4_um_t)0UL; int back = 0; #line 3001 "printqd.ctr" pnum = dk4str8_next(str, NULL); if (NULL != pnum) { px = dk4str8_next(pnum, NULL); if (NULL == px) { if (0 != get_limit_value(&limval, pnum, fn, lineno)) { plim = (pqd_limit_t *)dk4sto_it_find_like(i, str, 1); if (NULL == plim) { plim = limit_new(str, limval); if (NULL != plim) { if (0 != dk4sto_add(s, plim, NULL)) { back = 1; } else { #line 3013 "printqd.ctr" /* ERROR: Memory */ log_1(fn, lineno, LOG_EMERG, 1, 27); limit_delete(plim); } } else { #line 3018 "printqd.ctr" /* ERROR: Memory */ log_1(fn, lineno, LOG_EMERG, 1, 27); } } else { #line 3022 "printqd.ctr" /* ERROR: Limit redefinition */ log_3(fn, lineno, LOG_EMERG, 1, 32, 33, str); } } } else { #line 3027 "printqd.ctr" /* ERROR: Syntax, no further text expected */ log_3(fn, lineno, LOG_EMERG, 1, 23, 24, px); } } else { #line 3031 "printqd.ctr" /* ERROR: Missing limit. */ log_1(fn, lineno, LOG_EMERG, 1, 31); } #line 3035 "printqd.ctr" return back; } /** Set default limit for class. @param pcl Class to modify. @param pv String containing the limit. @return 1 on success, 0 on error. */ static int set_default_limit( pqd_class_t *pcl, char *pv, const char *fn, unsigned long lineno ) { char *px; dk4_um_t value = (dk4_um_t)0UL; int back = 0; #line 3058 "printqd.ctr" px = dk4str8_next(pv, NULL); if (NULL == px) { if (0 != get_limit_value(&value, pv, fn, lineno)) { if ((0 == (1 & (pcl->hdl))) || (value == pcl->dl) ) { pcl->hdl |= 1; pcl->dl = value; back = 1; } else { #line 3066 "printqd.ctr" /* ERROR: Syntax, default limit redefined */ log_1(fn, lineno, LOG_EMERG, 1, 34); } } } else { #line 3071 "printqd.ctr" /* ERROR: No further text expected */ log_3(fn, lineno, LOG_EMERG, 1, 23, 24, px); } #line 3075 "printqd.ctr" return back; } /** Set deny action for printer class. @param pcl Class to modify. @param pv String containing the action. @return 1 on success, 0 on error. */ static int set_deny_action( pqd_class_t *pcl, char *pv, const char *fn, unsigned long lineno ) { char *px = NULL; int back = 0; int res = 0; #line 3098 "printqd.ctr" px = dk4str8_next(pv, NULL); if (NULL == px) { switch ( (res = dk4str8_array_index(deny_action_names, pv, 0)) ) { case 0: case 1: { if (0 == (2 & pcl->hdl)) { pcl->da = res; pcl->hdl |= 2; back = 1; } else { #line 3107 "printqd.ctr" /* ERROR: Redefinition of deny action */ log_1(fn, lineno, LOG_EMERG, 1, 35); } } break; default: { } break; } } else { #line 3115 "printqd.ctr" /* ERROR: Syntax, no further text expected */ log_3(fn, lineno, LOG_EMERG, 1, 23, 24, px); } #line 3119 "printqd.ctr" return back; } /** Add an alias for the current printer to list. @param ppr Printer to add alias for. @param pv Alias name. @return 1 on success, 0 on error. */ static int add_alias(pqd_printer_t *ppr, char *pv, const char *fn, unsigned long lineno) { pqd_printer_alias_t *ppa; pqd_printer_t *pp; char *px; int back = 0; #line 3138 "printqd.ctr" px = dk4str8_next(pv, NULL); if (NULL == px) { ppa = (pqd_printer_alias_t *)dk4sto_it_find_like(conf.i_a, pv, 1); if (NULL == ppa) { pp = (pqd_printer_t *)dk4sto_it_find_like(conf.i_p, pv, 1); if (NULL == pp) { ppa = printer_alias_new(pv, ppr); if (NULL != ppa) { if (0 != dk4sto_add(conf.s_a, ppa, NULL)) { back = 1; } else { #line 3149 "printqd.ctr" /* ERROR: Memory */ log_1(fn, lineno, LOG_EMERG, 1, 27); printer_alias_delete(ppa); } } else { #line 3154 "printqd.ctr" /* ERROR: Memory */ log_1(fn, lineno, LOG_EMERG, 1, 27); } } else { #line 3158 "printqd.ctr" /* ERROR: Printer exists */ log_3(fn, lineno, LOG_EMERG, 1, 36, 37, pv); } } else { #line 3162 "printqd.ctr" /* ERROR: Alias already exists */ log_3(fn, lineno, LOG_EMERG, 1, 38, 39, pv); } } else { #line 3166 "printqd.ctr" /* ERROR: Syntax, unexpected text */ log_3(fn, lineno, LOG_EMERG, 1, 23, 24, px); } #line 3170 "printqd.ctr" return back; } /** Assign a class to a printer. @param ppr Printer to modify. @param pv Class name. @return 1 on success, 0 on error. */ static int assign_class(pqd_printer_t *ppr, char *pv, const char *fn, unsigned long lineno) { pqd_class_t *pcl; char *px; int back = 0; #line 3188 "printqd.ctr" px = dk4str8_next(pv, NULL); if (NULL == px) { if (NULL == ppr->cl) { pcl = (pqd_class_t *)dk4sto_it_find_like(conf.i_c, pv, 1); if (NULL != pcl) { ppr->cl = pcl; back = 1; } else { #line 3196 "printqd.ctr" /* ERROR: Syntax, class not found */ log_3(fn, lineno, LOG_EMERG, 1, 40, 41, pv); } } else { #line 3200 "printqd.ctr" /* ERROR: Syntax, redefinition of printer class */ log_1(fn, lineno, LOG_EMERG, 1, 42); } } else { #line 3204 "printqd.ctr" /* ERROR: Syntax, unexpected text */ log_3(fn, lineno, LOG_EMERG, 1, 23, 24, px); } #line 3208 "printqd.ctr" return back; } /** Check configuration for errors. @return 1 if configuration is usable, 0 on errors. */ static int config_check(const char *filename, unsigned long lineno) { pqd_printer_t *pr = NULL; pqd_class_t *cl = NULL; int back = 1; #line 3225 "printqd.ctr" /* Each printer must have a class assigned. */ dk4sto_it_reset(conf.i_p); do { pr = (pqd_printer_t *)dk4sto_it_next(conf.i_p); if (NULL != pr) { if (NULL == pr->cl) { back = 0; #line 3233 "printqd.ctr" /* ERROR: No class for printer */ log_3(filename, lineno, LOG_EMERG, 1, 91, 92, pr->name); } } } while(NULL != pr); /* Each class should have a default limit */ dk4sto_it_reset(conf.i_c); do { cl = (pqd_class_t *)dk4sto_it_next(conf.i_c); if (NULL != cl) { if (0 == cl->hdl) { #line 3247 "printqd.ctr" /* WARNING: Default limit missing for class */ log_3(filename, lineno, LOG_EMERG, 0, 93, 94, cl->name); } } } while (NULL != cl); #line 3254 "printqd.ctr" return back; } /** Set additional features to log. @param pv Text containing the feature names. @param fn File name for diagnostics. @param lineno Line numbers for diagnostics. @return 1 on success, 0 on errors. */ static int set_log_features(char *pv, const char *fn, unsigned long lineno) { char *pc; char *pn; int back = 0; if (NULL != pv) { back = 1; pc = dk4str8_start(pv, NULL); while (NULL != pc) { pn = strchr(pc, ','); if (NULL != pn) { *(pn++) = '\0'; pn = dk4str8_start(pn, NULL); } dk4str8_normalize(pc, NULL); switch ( dk4str8_array_index(log_feature_names, pc, 0) ) { case 0 : { conf.ldb = 1; } break; case 1 : { conf.linf = 1; } break; case 2 : case 3 : { conf.ldb = 1; conf.linf = 1; } break; case 4 : case 5 : { conf.ldb = 0; conf.linf = 0; } break; default : { /* ERROR: Unknown log feature name */ log_3(NULL, 0UL, LOG_EMERG, 0, 154, 155, pc); back = 0; } break; } pc = pn; } } else { /* ERROR: Value required */ conf.ldb = 0; conf.linf = 0; } return back; } /** Read configuration file. @return 1 on success (can continue), 0 on error (must exit). */ static int config_read(void) { const char *fn = NULL; /* Input file name */ FILE *fipo = NULL; /* Input file */ pqd_class_t *pcl = NULL; /* Current class to modify */ pqd_printer_t *ppr = NULL; /* Current printer to modify */ pqd_printer_alias_t *ppa = NULL; /* Printer alias */ char *pk = NULL; /* Key text */ char *pv = NULL; /* Value text */ char *px = NULL; /* Text after value */ unsigned long lineno = 0UL; /* Current line number */ int back = 0; /* Result */ int sectt = 0; /* Section type: 0=opt, 1=class, 2=pr */ int myres = 0; /* Internal operation result */ #line 3336 "printqd.ctr" if (0 != config_allocate()) { if (0 != options[1].found) { fn = options[1].val.t; } if (NULL == fn) { fn = def_conf_file_name; } fipo = dk4fopen_c8(fn, printqd_kw[1], DK4_FOPEN_SC_IS_REGULAR, NULL); if (NULL != fipo) { back = 1; sectt = 0; while ((1 == back) && (NULL != fgets(inbuf, sizeof(inbuf), fipo))) { lineno++; dk4str8_delnl(inbuf); #line 3346 "printqd.ctr" pk = dk4str8_start(inbuf, NULL); if (NULL != pk) { if ('#' != *pk) { if ('[' == *pk) { #line 3350 "printqd.ctr" /* Opening a new section. */ pk = dk4str8_start(++pk, NULL); if (NULL != pk) { #line 3355 "printqd.ctr" sectt = -1; pcl = NULL; ppr = NULL; pv = dk4str8_chr(pk, ']'); if (NULL != pv) { *pv = '\0'; } #line 3360 "printqd.ctr" pv = dk4str8_next(pk, NULL); switch ( dk4str8_array_index(config_section_names, pk, 0) ) { /* Opening options section. */ case 0 : { #line 3365 "printqd.ctr" sectt = 0; } break; /* Opening class section. */ case 1 : { #line 3370 "printqd.ctr" sectt = 1; if (NULL != pv) { if (NULL == (px = dk4str8_next(pv, NULL))) { pcl = (pqd_class_t *)dk4sto_it_find_like( conf.i_c, pv, 1 ); if (NULL == pcl) { pcl = class_new(pv); if (NULL != pcl) { if (0 == dk4sto_add(conf.s_c, pcl, NULL)) { /* ERROR: Memory */ log_1(fn, lineno, LOG_EMERG, 1, 27); class_delete(pcl); pcl = NULL; #line 3384 "printqd.ctr" back = 0; } } else { #line 3387 "printqd.ctr" /* ERROR: MEMORY */ log_1(fn, lineno, LOG_EMERG, 1, 27); back = 0; } } else { #line 3392 "printqd.ctr" /* ERROR: Syntax, class already exists */ log_3(fn, lineno, LOG_EMERG, 1, 43, 44, pv); back = 0; } } else { #line 3397 "printqd.ctr" /* ERROR: Syntax, only one component allowed */ log_3(fn, lineno, LOG_EMERG, 1, 23, 24, px); back = 0; } } else { #line 3402 "printqd.ctr" /* ERROR: Syntax, missing class name */ log_1(fn, lineno, LOG_EMERG, 1, 45); back = 0; } } break; /* Opening printer section. */ case 2 : { #line 3410 "printqd.ctr" sectt = 2; if (NULL != pv) { if (NULL == (px = dk4str8_next(pv, NULL))) { ppr = (pqd_printer_t *)dk4sto_it_find_like( conf.i_p,pv,1 ); ppa = (pqd_printer_alias_t *)dk4sto_it_find_like( conf.i_a,pv,1 ); if ((NULL == ppr) && (NULL == ppa)) { ppr = printer_new(pv); if (NULL != ppr) { if (0 == dk4sto_add(conf.s_p, ppr, NULL)) { /* ERROR: Memory */ log_1(fn, lineno, LOG_EMERG, 1, 27); printer_delete(ppr); ppr = NULL; back = 0; #line 3428 "printqd.ctr" } } else { #line 3430 "printqd.ctr" /* ERROR: Memory */ log_1(fn, lineno, LOG_EMERG, 1, 27); back = 0; } } else { #line 3435 "printqd.ctr" /* ERROR: Syntax, pr/al already exists */ log_3(fn, lineno, LOG_EMERG, 1, 46, 47, pv); back = 0; } } else { #line 3440 "printqd.ctr" /* ERROR: Syntax, just one component allowed */ log_3(fn, lineno, LOG_EMERG, 1, 23, 24, px); back = 0; } } else { #line 3445 "printqd.ctr" /* ERROR: Syntax, name required */ log_1(fn, lineno, LOG_EMERG, 1, 48); back = 0; } } break; default : { #line 3451 "printqd.ctr" /* ERROR: Syntax, illegal section name */ log_3(fn, lineno, LOG_EMERG, 1, 49, 50, pk); back = 0; } break; } } else { #line 3457 "printqd.ctr" /* ERROR: Syntax, empty section */ log_1(fn, lineno, LOG_EMERG, 1, 51); back = 0; } } else { #line 3462 "printqd.ctr" /* Data line for existing section. */ pv = dk4str8_chr(pk, '='); if (NULL != pv) { *(pv++) = '\0'; pv = dk4str8_start(pv, NULL); if (NULL != pv) { dk4str8_normalize(pk, NULL); #line 3471 "printqd.ctr" switch ( dk4str8_array_index(config_option_names, pk, 0) ) { case 0 : { #line 3474 "printqd.ctr" if (0 == sectt) { struct passwd *pw; if (NULL == (px = dk4str8_next(pv, NULL))) { pw = getpwnam(pv); if (NULL != pw) { if ((0 == conf.uid) || (conf.uid == pw->pw_uid)) { conf.uid = pw->pw_uid; } else { /* ERROR: Redefinition */ log_1(fn, lineno, LOG_EMERG, 1, 52); back = 0; #line 3485 "printqd.ctr" } } else { #line 3487 "printqd.ctr" /* ERROR: User not found */ log_3(fn, lineno, LOG_EMERG, 1, 53, 54, pv); back = 0; } } else { #line 3492 "printqd.ctr" /* ERROR: Syntax, just one component allowed */ log_3(fn, lineno, LOG_EMERG, 1, 23, 24, px); back = 0; } } else { #line 3497 "printqd.ctr" /* ERROR: Only allwowed in options section */ log_1(fn, lineno, LOG_EMERG, 1, 55); back = 0; } } break; case 1 : { #line 3503 "printqd.ctr" if (0 == sectt) { struct group *pgr; if (NULL == (px = dk4str8_next(pv, NULL))) { pgr = getgrnam(pv); if (NULL != pgr) { if ((0 == conf.gid) || (conf.gid == pgr->gr_gid)) { conf.gid = pgr->gr_gid; } else { /* ERROR: Syntax, group redefinition */ log_1(fn, lineno, LOG_EMERG, 1, 56); back = 0; #line 3514 "printqd.ctr" } } else { #line 3516 "printqd.ctr" /* ERROR: Syntax, group not found */ log_3(fn, lineno, LOG_EMERG, 1, 57, 58, pv); back = 0; } } else { #line 3521 "printqd.ctr" /* ERROR: Syntax, just one component allowed */ log_3(fn, lineno, LOG_EMERG, 1, 23, 24, px); back = 0; } } else { #line 3526 "printqd.ctr" /* ERROR: Syntax, only allowed in options */ log_1(fn, lineno, LOG_EMERG, 1, 55); back = 0; } } break; case 2 : { #line 3532 "printqd.ctr" if (0 == sectt) { if (NULL == conf.dname) { conf.dname = dk4str8_dup(pv, NULL); if (NULL == conf.dname) { /* ERROR: Memory */ log_1(fn, lineno, LOG_EMERG, 1, 27); back = 0; #line 3539 "printqd.ctr" } } else { /* ERROR: Redefinition */ log_1(fn, lineno, LOG_EMERG, 1, 59); back = 0; #line 3544 "printqd.ctr" } } else { #line 3546 "printqd.ctr" /* ERROR: Syntax, only allowed in options */ log_1(fn, lineno, LOG_EMERG, 1, 55); back = 0; } } break; case 3 : { #line 3552 "printqd.ctr" if (0 == sectt) { if (NULL == conf.sname) { conf.sname = dk4str8_dup(pv, NULL); if (NULL == conf.sname) { /* ERROR: Memory */ log_1(fn, lineno, LOG_EMERG, 1, 27); back = 0; #line 3559 "printqd.ctr" } } else { #line 3561 "printqd.ctr" /* ERROR: Redefinition */ log_1(fn, lineno, LOG_EMERG, 1, 60); back = 0; } } else { #line 3566 "printqd.ctr" /* ERROR: Syntax, only allowed in options */ log_1(fn, lineno, LOG_EMERG, 1, 55); back = 0; } } break; case 4 : { #line 3572 "printqd.ctr" if (0 == sectt) { if (0 == set_backlog(&(conf.slbl), pv, fn, lineno)) { back = 0; #line 3575 "printqd.ctr" } } else { #line 3577 "printqd.ctr" /* ERROR: Syntax, only allowed in options */ log_1(fn, lineno, LOG_EMERG, 1, 55); back = 0; } } break; case 5 : { #line 3583 "printqd.ctr" if (0 == sectt) { if(0 == set_max_connections(&(conf.m_loc),pv,fn,lineno)) { back = 0; #line 3587 "printqd.ctr" } } else { #line 3589 "printqd.ctr" /* ERROR: Syntax, only allowed in options */ log_1(fn, lineno, LOG_EMERG, 1, 55); back = 0; } } break; case 6 : { #line 3595 "printqd.ctr" if (0 == sectt) { if (0 == set_port_number(&(conf.pudp),pv,fn,lineno)) { back = 0; #line 3598 "printqd.ctr" } } else { #line 3600 "printqd.ctr" /* ERROR: Syntax, only allowed in options */ log_1(fn, lineno, LOG_EMERG, 1, 55); back = 0; } } break; case 7 : { #line 3606 "printqd.ctr" if (0 == sectt) { if (0 == set_port_number(&(conf.ptcp),pv,fn,lineno)) { back = 0; #line 3609 "printqd.ctr" } } else { #line 3611 "printqd.ctr" /* ERROR: Syntax, only allowed in options */ log_1(fn, lineno, LOG_EMERG, 1, 55); back = 0; } } break; case 8 : { #line 3617 "printqd.ctr" if (0 == sectt) { if (0 == set_backlog(&(conf.snbl), pv, fn, lineno)) { back = 0; #line 3620 "printqd.ctr" } } else { #line 3622 "printqd.ctr" /* ERROR: Syntax, only allowed in options */ log_1(fn, lineno, LOG_EMERG, 1, 55); back = 0; } } break; case 9 : { #line 3628 "printqd.ctr" if (0 == sectt) { if(0 == set_max_connections(&(conf.m_tcp),pv,fn,lineno)) { back = 0; #line 3632 "printqd.ctr" } } else { #line 3634 "printqd.ctr" /* ERROR: Syntax, only allowed in options */ log_1(fn, lineno, LOG_EMERG, 1, 55); back = 0; } } break; case 10 : { #line 3640 "printqd.ctr" if (0 == sectt) { myres = allow_hosts( conf.s_ai, conf.i_ai, &(conf.iglo), pv, fn, lineno ); if (0 == myres) { #line 3646 "printqd.ctr" back = 0; } } else { #line 3649 "printqd.ctr" /* ERROR: Syntax, only allowed in options */ log_1(fn, lineno, LOG_EMERG, 1, 55); back = 0; } } break; case 11 : { #line 3655 "printqd.ctr" if (0 == sectt) { myres = allow_hosts( conf.s_ad, conf.i_ad, &(conf.dglo), pv, fn, lineno ); if (0 == myres) { #line 3661 "printqd.ctr" back = 0; } } else { #line 3664 "printqd.ctr" /* ERROR: Syntax, only allowed in options */ log_1(fn, lineno, LOG_EMERG, 1, 55); back = 0; } } break; case 12 : { #line 3670 "printqd.ctr" if (0 == sectt) { myres = allow_hosts( conf.s_aa, conf.i_aa, &(conf.aglo), pv, fn, lineno ); if (0 == myres) { #line 3676 "printqd.ctr" back = 0; } } else { #line 3679 "printqd.ctr" /* ERROR: Syntax, only allowed in options */ log_1(fn, lineno, LOG_EMERG, 1, 55); back = 0; } } break; case 13 : { #line 3685 "printqd.ctr" if ((1 == sectt) && (NULL != pcl)) { myres = add_limit( pcl, pcl->s_u, pcl->i_u, pv, fn, lineno ); if (0 == myres) { #line 3690 "printqd.ctr" back = 0; } } else { #line 3693 "printqd.ctr" /* ERROR: Syntax, only allowed in class */ log_1(fn, lineno, LOG_EMERG, 1, 61); back = 0; } } break; case 14 : { #line 3699 "printqd.ctr" if ((1 == sectt) && (NULL != pcl)) { myres = add_limit( pcl, pcl->s_g, pcl->i_g, pv, fn, lineno ); if (0 == myres) { #line 3704 "printqd.ctr" back = 0; } } else { #line 3707 "printqd.ctr" /* ERROR: Syntax, only allowed in class */ log_1(fn, lineno, LOG_EMERG, 1, 61); back = 0; } } break; case 15 : { #line 3713 "printqd.ctr" if ((1 == sectt) && (NULL != pcl)) { myres = set_default_limit(pcl, pv, fn, lineno); if (0 == myres) { #line 3716 "printqd.ctr" back = 0; } } else { #line 3719 "printqd.ctr" /* ERROR: Syntax, only allowed in class */ log_1(fn, lineno, LOG_EMERG, 1, 61); back = 0; } } break; case 16 : { #line 3725 "printqd.ctr" if ((1 == sectt) && (NULL != pcl)) { myres = set_deny_action(pcl, pv, fn, lineno); if (0 == myres) { #line 3728 "printqd.ctr" back = 0; } } else { #line 3731 "printqd.ctr" /* ERROR: Syntax, only allowed in class */ log_1(fn, lineno, LOG_EMERG, 1, 61); back = 0; } } break; case 17 : { #line 3737 "printqd.ctr" if ((2 == sectt) && (NULL != ppr)) { myres = add_alias(ppr, pv, fn, lineno); if (0 == myres) { #line 3740 "printqd.ctr" back = 0; } } else { #line 3743 "printqd.ctr" /* ERROR: Syntax, only allowed in printer */ log_1(fn, lineno, LOG_EMERG, 1, 62); back = 0; } } break; case 18 : { #line 3749 "printqd.ctr" if ((2 == sectt) && (NULL != ppr)) { myres = assign_class(ppr, pv, fn, lineno); if (0 == myres) { #line 3752 "printqd.ctr" back = 0; } } else { #line 3755 "printqd.ctr" /* ERROR: Syntax, only allowed in printer */ log_1(fn, lineno, LOG_EMERG, 1, 62); back = 0; } } break; case 19 : { #line 3761 "printqd.ctr" if (0 == sectt) { if (NULL == conf.lname) { conf.lname = dk4str8_dup(pv, NULL); if (NULL == conf.lname) { /* ERROR: Memory */ log_1(fn, lineno, LOG_EMERG, 1, 27); back = 0; #line 3768 "printqd.ctr" } } else { #line 3770 "printqd.ctr" /* ERROR: Redefinition */ log_1(fn, lineno, LOG_EMERG, 1, 63); back = 0; } } else { #line 3775 "printqd.ctr" /* ERROR: Only in options */ log_1(fn, lineno, LOG_EMERG, 1, 55); back = 0; } } break; case 20 : { #line 3781 "printqd.ctr" back = set_log_features(pv, fn, lineno); } break; case 21 : { #line 3784 "printqd.ctr" if (0 == sectt) { struct passwd *pw; if (NULL == (px = dk4str8_next(pv, NULL))) { pw = getpwnam(pv); if (NULL != pw) { if ((0 == conf.suid) || (conf.suid == pw->pw_uid)) { conf.suid = pw->pw_uid; } else { /* ERROR: Redefinition */ log_1(fn, lineno, LOG_EMERG, 1, 52); back = 0; #line 3795 "printqd.ctr" } } else { #line 3797 "printqd.ctr" /* ERROR: User not found */ log_3(fn, lineno, LOG_EMERG, 1, 53, 54, pv); back = 0; } } else { #line 3802 "printqd.ctr" /* ERROR: Syntax, just one component allowed */ log_3(fn, lineno, LOG_EMERG, 1, 23, 24, px); back = 0; } } else { #line 3807 "printqd.ctr" /* ERROR: Only allwowed in options section */ log_1(fn, lineno, LOG_EMERG, 1, 55); back = 0; } } break; case 22 : { #line 3813 "printqd.ctr" if (0 == sectt) { struct group *pgr; if (NULL == (px = dk4str8_next(pv, NULL))) { pgr = getgrnam(pv); if (NULL != pgr) { if((0 == conf.sgid) || (conf.sgid == pgr->gr_gid)) { conf.sgid = pgr->gr_gid; } else { /* ERROR: Syntax, group redefinition */ log_1(fn, lineno, LOG_EMERG, 1, 56); back = 0; #line 3824 "printqd.ctr" } } else { #line 3826 "printqd.ctr" /* ERROR: Syntax, group not found */ log_3(fn, lineno, LOG_EMERG, 1, 57, 58, pv); back = 0; } } else { #line 3831 "printqd.ctr" /* ERROR: Syntax, just one component allowed */ log_3(fn, lineno, LOG_EMERG, 1, 23, 24, px); back = 0; } } else { #line 3836 "printqd.ctr" /* ERROR: Syntax, only allowed in options */ log_1(fn, lineno, LOG_EMERG, 1, 55); back = 0; } } break; } } else { #line 3843 "printqd.ctr" /* ERROR: Syntax, missing value */ log_1(fn, lineno, LOG_EMERG, 1, 64); back = 0; } } else { #line 3848 "printqd.ctr" /* ERROR: Syntax, missing value */ log_1(fn, lineno, LOG_EMERG, 1, 64); back = 0; } } } #if TRACE_DEBUG else { #line 3856 "printqd.ctr" } #endif } #if TRACE_DEBUG else { #line 3861 "printqd.ctr" } #endif } fclose(fipo); if (1 == back) { back = config_check(fn, lineno); } } else { #line 3869 "printqd.ctr" /* ERROR: Failed to open file */ log_1(fn, 0UL, LOG_EMERG, 1, 65); } } else { /* ERROR: Memory */ log_1(NULL, 0UL, LOG_EMERG, 1, 27); } #line 3877 "printqd.ctr" return back; } static void release_allowed_peers(dk4_sto_it_t *it) { dk4_allowed_peer_t *peer; #line 3888 "printqd.ctr" dk4sto_it_reset(it); do { peer = (dk4_allowed_peer_t *)dk4sto_it_next(it); if (NULL != peer) { dk4mem_free(peer); } } while (NULL != peer); dk4sto_it_close(it); #line 3897 "printqd.ctr" } /** Release resources used to save configuration data. */ static void config_release(void) { #line 3908 "printqd.ctr" prev_uid = conf.uid; prev_gid = conf.gid; if (NULL != conf.i_aa) { /* Allowed peers for administration */ release_allowed_peers(conf.i_aa); } conf.i_aa = NULL; if (NULL != conf.s_aa) { dk4sto_close(conf.s_aa); } conf.s_aa = NULL; if (NULL != conf.i_ad) { /* Allowed peers for data */ release_allowed_peers(conf.i_ad); } conf.i_ad = NULL; if (NULL != conf.s_ad) { dk4sto_close(conf.s_ad); } conf.s_ad = NULL; if (NULL != conf.i_ai) { /* Allowed peers for information */ release_allowed_peers(conf.i_ai); } conf.i_ai = NULL; if (NULL != conf.s_ai) { dk4sto_close(conf.s_ai); } conf.s_ai = NULL; if (NULL != conf.i_a) { /* Aliases */ printer_alias_all_delete(conf.i_a); } conf.i_a = NULL; if (NULL != conf.s_a) { dk4sto_close(conf.s_a); } conf.s_a = NULL; if (NULL != conf.i_p) { /* Printers */ printer_all_delete(conf.i_p); } conf.i_p = NULL; if (NULL != conf.s_p) { dk4sto_close(conf.s_p); } conf.s_p = NULL; if (NULL != conf.i_c) { /* Classes */ class_all_delete(conf.i_c); } conf.i_c = NULL; if (NULL != conf.s_c) { dk4sto_close(conf.s_c); } conf.s_c = NULL; dk4mem_release(conf.dname); dk4mem_release(conf.sname); dk4mem_release(conf.lname); conf.m_loc = 0; conf.m_tcp = 0; conf.uid = 0; conf.gid = 0; conf.slbl = 0; conf.snbl = 0; conf.ptcp = 9100; conf.pudp = 9100; #line 3959 "printqd.ctr" } /** Allocate resources before starting outer loop. @return 1 on success (can enter loop), 0 on error (exit). */ static int outer_allocate_resources(void) { int back = 0; #line 3972 "printqd.ctr" /* Initialize variables to NULL. */ s_c_unix = NULL; i_c_unix = NULL; s_c_tcp = NULL; i_c_tcp = NULL; /* Allocate resources. */ s_c_unix = dk4sto_open(NULL); if (NULL == s_c_unix) { #line 3984 "printqd.ctr" /* ERROR: Memory */ log_1(NULL, 0UL, LOG_EMERG, 1, 27); goto finished; } dk4sto_set_comp(s_c_unix, compare_pqd_l_conn_t, 0); i_c_unix = dk4sto_it_open(s_c_unix, NULL); if (NULL == i_c_unix) { #line 3991 "printqd.ctr" /* ERROR: Memory */ log_1(NULL, 0UL, LOG_EMERG, 1, 27); goto finished; } s_c_tcp = dk4sto_open(NULL); if (NULL == s_c_tcp) { #line 3997 "printqd.ctr" /* ERROR: Memory */ log_1(NULL, 0UL, LOG_EMERG, 1, 27); goto finished; } dk4sto_set_comp(s_c_tcp, compare_pqd_n_conn_t, 0); i_c_tcp = dk4sto_it_open(s_c_tcp, NULL); if (NULL == i_c_tcp) { #line 4004 "printqd.ctr" /* ERROR: Memory */ log_1(NULL, 0UL, LOG_EMERG, 1, 27); goto finished; } /* Indicate success. */ back = 1; finished: #line 4015 "printqd.ctr" return back; } /** Release resources after finishing outer loop. */ static void outer_release_resources(void) { pqd_n_conn_t *pnc; pqd_l_conn_t *plc; #line 4029 "printqd.ctr" if (NULL != i_c_tcp) { dk4sto_it_reset(i_c_tcp); do { pnc = (pqd_n_conn_t *)dk4sto_it_next(i_c_tcp); if (NULL != pnc) { /* Release pnc */ if (INVALID_SOCKET != pnc->sock) { (void)dk4socket_close(pnc->sock, NULL); } dk4mem_free(pnc); } } while(NULL != pnc); dk4sto_it_close(i_c_tcp); } i_c_tcp = NULL; if (NULL != s_c_tcp) { dk4sto_close(s_c_tcp); } s_c_tcp = NULL; if (NULL != i_c_unix) { dk4sto_it_reset(i_c_unix); do { plc = (pqd_l_conn_t *)dk4sto_it_next(i_c_unix); if (NULL != plc) { /* Release plc */ if (INVALID_SOCKET != plc->sock) { (void)dk4socket_close(plc->sock, NULL); } dk4mem_free(plc); } } while (NULL != plc); dk4sto_it_close(i_c_unix); } i_c_unix = NULL; if (NULL != s_c_unix) { dk4sto_close(s_c_unix); } s_c_unix = NULL; #line 4069 "printqd.ctr" } static void pqd_dbi_open_error(const char *fn, dk4_er_t *erp) { switch (erp->ec) { case DK4_E_NOT_SUPPORTED : { log_3(NULL, 0UL, LOG_EMERG, 1, 105, 202, fn); } break; case DK4_E_MATH_OVERFLOW : { log_3(NULL, 0UL, LOG_EMERG, 1, 105, 203, fn); } break; case DK4_E_MEMORY_ALLOCATION_FAILED : { log_3(NULL, 0UL, LOG_EMERG, 1, 105, 204, fn); } break; case DK4_E_SYNTAX : { log_3(NULL, 0UL, LOG_EMERG, 1, 105, 205, fn); } break; case DK4_E_SEC_CHECK : { log_3(NULL, 0UL, LOG_EMERG, 1, 105, 206, fn); } break; case DK4_E_OPEN_READ_FAILED : { log_3(NULL, 0UL, LOG_EMERG, 1, 105, 207, fn); } break; case DK4_E_OPEN_WRITE_FAILED : { log_3(NULL, 0UL, LOG_EMERG, 1, 105, 208, fn); } break; case DK4_E_CLOSE_FAILED : { log_3(NULL, 0UL, LOG_EMERG, 1, 105, 209, fn); } break; default : { log_3(NULL, 0UL, LOG_EMERG, 1, 105, 106, fn); } break; } } /** Allocate resources before starting inner loop. * Create log directory and log file. * Open database. * Log message for starting service. @return 1 on success (can enter loop), 0 on error (exit). */ static int inner_allocate_resources(void) { char necbuf[16*sizeof(dk4_um_t)]; dk4_er_t er; const char *fn; uid_t sockuid; gid_t sockgid; int res; int back = 0; #line 4127 "printqd.ctr" /* Log file directory hierarchy. */ fn = conf.lname; if (NULL == fn) { fn = def_log_file_name; } if (0 != user_switched) { res = dk4mkdir_hierarchy_c8(fn, 0, NULL); } else { res = dk4mkdir_hierarchy_ugm_c8(fn, 0, conf.uid, conf.gid, 0750, NULL); } if (0 == res) { #line 4138 "printqd.ctr" /* ERROR: Failed to create directory hierachy for log file */ log_3(NULL, 0UL, LOG_EMERG, 1, 95, 96, fn); goto finished; } /* Database directory hierarchy */ fn = conf.dname; if (NULL == fn) { fn = def_db_file_name; } fn = dk4dbi_filename_part(fn); if (0 != user_switched) { res = dk4mkdir_hierarchy_c8(fn, 0, NULL); } else { res = dk4mkdir_hierarchy_ugm_c8(fn, 0, conf.uid, conf.gid, 0750, NULL); } if (0 == res) { #line 4154 "printqd.ctr" /* ERROR: Failed to create directory hierarchy for db file */ log_3(NULL, 0UL, LOG_EMERG, 1, 97, 98, fn); goto finished; } /* Socket directory hierarchy */ fn = conf.sname; if (NULL == fn) { fn = def_sock_file_name; } sockuid = conf.suid; if (0 == sockuid) { sockuid = conf.uid; } sockgid = conf.sgid; if (0 == sockgid) { sockgid = conf.gid; } if ((0 != user_switched) && (0 != conf.uid)) { res = dk4mkdir_hierarchy_c8(fn, 0, NULL); } else { /* In contrast to the db and log directories the non-privileged user needs write access to the directory as the socket is deleted and newly created. */ res = dk4mkdir_hierarchy_ugm_c8(fn, 0, sockuid, sockgid, 0770, NULL); } if (0 == res) { #line 4178 "printqd.ctr" /* ERROR: Failed to create directory hierarchy for socket */ log_3(NULL, 0UL, LOG_EMERG, 1, 99, 100, fn); goto finished; } /* UNIX listener socket. */ fn = conf.sname; if (NULL == fn) { fn = def_sock_file_name; } #line 4188 "printqd.ctr" dk4error_init(&er); if ( ((0 != sockuid) || (0 != sockgid)) && ((0 == user_switched) || (0 == conf.uid)) ) { so_unix = dk4socket_c8_unix_listener_owner_group_mode( fn, ((0 < conf.slbl) ? (conf.slbl) : 5), sockuid, sockgid, 0660, &er ); } else { so_unix = dk4socket_c8_unix_listener( fn, ((0 < conf.slbl) ? (conf.slbl) : 5), &er ); } if (INVALID_SOCKET == so_unix) { #line 4203 "printqd.ctr" /* ERROR: Failed to create listener socket */ res = dk4ma_write_c8_decimal_signed( necbuf, sizeof(necbuf), (dk4_im_t)(er.dt.iDetails1), 0, NULL ); if (0 != res) { switch (er.ec) { case DK4_E_SYNTAX : { log_3(NULL, 0UL, LOG_EMERG, 1, 101, 178, fn); } break; case DK4_E_NON_SOCKET : { log_3(NULL, 0UL, LOG_EMERG, 1, 101, 179, fn); } break; case DK4_E_UNLINK_FAILED : { log_3(NULL, 0UL, LOG_EMERG, 1, 101, 180, fn); } break; case DK4_E_SOCKET_SOCKET : { log_5(NULL, 0UL, LOG_EMERG, 1, 101, 181, 182, fn, necbuf); } break; case DK4_E_SOCKET_BIND : { log_5(NULL, 0UL, LOG_EMERG, 1, 101, 183, 182, fn, necbuf); } break; case DK4_E_SOCKET_LISTEN : { log_5(NULL, 0UL, LOG_EMERG, 1, 101, 184, 182, fn, necbuf); } break; case DK4_E_CHOWN_FAILED : { log_3(NULL, 0UL, LOG_EMERG, 1, 101, 185, fn); } break; case DK4_E_CHMOD_FAILED : { log_3(NULL, 0UL, LOG_EMERG, 1, 101, 186, fn); } break; default : { log_3(NULL, 0UL, LOG_EMERG, 1, 101, 102, fn); } break; } } else { log_3(NULL, 0UL, LOG_EMERG, 1, 101, 102, fn); } goto finished; } #line 4242 "printqd.ctr" /* TCP listener socket set. */ if (0 < conf.ptcp) { dk4error_init(&er); ss_tcp = dk4socket_c8_set_server( conf.ptcp, ((0 < conf.snbl) ? (conf.snbl) : 5), 0, &er ); if (NULL == ss_tcp) { #line 4251 "printqd.ctr" /* ERROR: Failed to create TCP listener socket */ res = dk4ma_write_c8_decimal_signed( necbuf, sizeof(necbuf), (dk4_im_t)(er.dt.iDetails1), 0, NULL ); if (0 != res) { switch (er.ec) { case DK4_E_MATH_OVERFLOW : { log_1(NULL, 0UL, LOG_EMERG, 1, 188); } break; case DK4_E_MEMORY_ALLOCATION_FAILED : { log_1(NULL, 0UL, LOG_EMERG, 1, 189); } break; case DK4_E_SOCKET_SOCKET : { log_3(NULL, 0UL, LOG_EMERG, 1, 190, 191, necbuf); } break; case DK4_E_SOCKET_BIND : { log_3(NULL, 0UL, LOG_EMERG, 1, 192, 191, necbuf); } break; case DK4_E_SOCKET_LISTEN : { log_3(NULL, 0UL, LOG_EMERG, 1, 193, 191, necbuf); } break; case DK4_E_SOCKET_GETADDRLOC : { log_3(NULL, 0UL, LOG_EMERG, 1, 194, 191, necbuf); } break; default : { log_1(NULL, 0UL, LOG_EMERG, 1, 103); } break; } } else { log_1(NULL, 0UL, LOG_EMERG, 1, 103); } goto finished; } } /* UDP socket set. */ if (0 < conf.pudp) { dk4error_init(&er); ss_udp = dk4socket_c8_set_udp(conf.pudp, 0, 0, &er); if (NULL == ss_udp) { #line 4292 "printqd.ctr" /* ERROR: Failed to create UDP socket set */ res = dk4ma_write_c8_decimal_signed( necbuf, sizeof(necbuf), (dk4_im_t)(er.dt.iDetails1), 0, NULL ); if (0 != res) { switch (er.ec) { case DK4_E_MATH_OVERFLOW : { log_1(NULL, 0UL, LOG_EMERG, 1, 195); } break; case DK4_E_MEMORY_ALLOCATION_FAILED : { log_1(NULL, 0UL, LOG_EMERG, 1, 196); } break; case DK4_E_SOCKET_SOCKET : { log_3(NULL, 0UL, LOG_EMERG, 1, 197, 198, necbuf); } break; case DK4_E_SOCKET_BIND : { log_3(NULL, 0UL, LOG_EMERG, 1, 199, 198, necbuf); } break; case DK4_E_SOCKET_LISTEN : { log_3(NULL, 0UL, LOG_EMERG, 1, 200, 198, necbuf); } break; case DK4_E_SOCKET_GETADDRLOC : { log_3(NULL, 0UL, LOG_EMERG, 1, 201, 198, necbuf); } break; } } else { log_1(NULL, 0UL, LOG_EMERG, 1, 104); } goto finished; } } fn = conf.dname; if (NULL == fn) { fn = def_db_file_name; } #line 4327 "printqd.ctr" dk4error_init(&er); db = dk4dbi_open(fn, 1, 0, 1024, 1024, &er); if (NULL != db) { #line 4330 "printqd.ctr" db_modified = 0; res = 1; dk4error_init(&er); if (0 == dbi_set(db, printqd_kw[79],printqd_kw[79],&er)) { res = 0; } if (0 == dk4dbi_close(db, &er)) { res = 0; } db = NULL; db_modified = 0; if (0 != res) { #line 4339 "printqd.ctr" dk4error_init(&er); db = dk4dbi_open(fn, 1, 0, 1024, 1024, &er); if (NULL != db) { #line 4342 "printqd.ctr" db_modified = 0; } else { #line 4344 "printqd.ctr" /* ERROR: Failed to open database */ pqd_dbi_open_error(fn, &er); goto finished; } } else { #line 4349 "printqd.ctr" /* ERROR: Failed to write initial entry to database */ log_1(NULL, 0UL, LOG_EMERG, 1, 107); switch (er.ec) { case DK4_E_SYNTAX : { log_1(NULL, 0UL, LOG_EMERG, 1, 210); } break; case DK4_E_NOT_SUPPORTED : { log_1(NULL, 0UL, LOG_EMERG, 1, 211); } break; case DK4_E_MEMORY_ALLOCATION_FAILED : { log_1(NULL, 0UL, LOG_EMERG, 1, 212); } break; case DK4_E_OPEN_WRITE_FAILED : { log_1(NULL, 0UL, LOG_EMERG, 1, 213); } break; case DK4_E_WRITE_FAILED : { log_1(NULL, 0UL, LOG_EMERG, 1, 214); } break; case DK4_E_CLOSE_FAILED : { log_1(NULL, 0UL, LOG_EMERG, 1, 215); } break; case DK4_E_SEC_CHECK : { log_1(NULL, 0UL, LOG_EMERG, 1, 216); } break; default : { log_1(NULL, 0UL, LOG_EMERG, 1, 107); } break; } goto finished; } } else { #line 4380 "printqd.ctr" /* ERROR: Failed to open database */ pqd_dbi_open_error(fn, &er); goto finished; } /* Finally indicate success. */ back = 1; finished: #line 4391 "printqd.ctr" return back; } /** Release resources after finishing inner loop. * Log message for finishing service. * Synchronize and close database. * Close log file. */ static int inner_release_resources(void) { const char *fn; int back = 1; #line 4408 "printqd.ctr" /* Database */ if (NULL != db) { if (0 == dk4dbi_close(db, NULL)) { #line 4413 "printqd.ctr" /* ERROR: Failed to synchronize database to disk */ log_1(NULL, 0UL, LOG_EMERG, 1, 108); back = 0; } db = NULL; db_modified = 0; } /* UDP socket set. */ if (NULL != ss_udp) { #line 4424 "printqd.ctr" dk4socket_set_close(ss_udp, NULL); } ss_udp = NULL; /* TCP listener socket set. */ if (NULL != ss_tcp) { #line 4431 "printqd.ctr" dk4socket_set_close(ss_tcp, NULL); } ss_tcp = NULL; /* Unix listener socket. */ if (INVALID_SOCKET != so_unix) { dk4socket_close(so_unix, NULL); } so_unix = INVALID_SOCKET; fn = conf.sname; if (NULL == fn) { fn = def_sock_file_name; } (void)dk4delete_file_c8(fn, NULL); #line 4444 "printqd.ctr" return back; } /** Switch to non-privileged user and group if configured to do so. @return 1 on success (can continue), 0 on error (exit). */ static int change_group_and_user(void) { const char *fn = NULL; uid_t myuid; gid_t mygid; int dbt = DK4_DB_BE_UNKNOWN; int back = 1; #line 4462 "printqd.ctr" if (0 != user_switched) { #line 4463 "printqd.ctr" if (conf.uid != prev_uid) { back = 0; #line 4465 "printqd.ctr" /* ERROR: User to run as was changed */ log_1(NULL, 0UL, LOG_EMERG, 1, 66); } else { if (conf.gid != prev_gid) { #line 4469 "printqd.ctr" back = 0; /* ERROR: Group to run as was changed */ log_1(NULL, 0UL, LOG_EMERG, 1, 67); } } } else { #line 4475 "printqd.ctr" user_switched = 1; myuid = geteuid(); mygid = getegid(); if ((myuid != conf.uid) || (mygid != conf.gid)) { #line 4479 "printqd.ctr" /* PID file ownership and permissions */ if (0 != chown(pid_file_name, conf.uid, conf.gid)) { back = 0; /* ERROR: Failed to change PID file ownership */ log_1(NULL, 0UL, LOG_EMERG, 1, 217); } if (0 != chmod(pid_file_name, 0660)) { back = 0; /* ERROR: Failed to change PID file permissions */ log_1(NULL, 0UL, LOG_EMERG, 1, 218); } /* Log file ownership and permissions */ fn = conf.lname; if (NULL == fn) { fn = def_log_file_name; } if (0 != chown(fn, conf.uid, conf.gid)) { back = 0; #line 4499 "printqd.ctr" /* ERROR: Failed to change log file ownership */ log_1(NULL, 0UL, LOG_EMERG, 1, 109); } if (0 != chmod(fn, 0660)) { back = 0; #line 4504 "printqd.ctr" /* ERROR: Failed to change log file permissions */ log_1(NULL, 0UL, LOG_EMERG, 1, 110); } /* Database ownership and permissions */ if (0 == dk4dbi_change_owner_and_mode(db,conf.uid,conf.gid,0660,NULL)) { back = 0; #line 4512 "printqd.ctr" /* ERROR: failed to change db ownership and permissions */ log_1(NULL, 0UL, LOG_EMERG, 1, 111); } switch ( (dbt = dk4dbi_get_type(db)) ) { case DK4_DB_BE_BDB : case DK4_DB_BE_NDBM : { #line 4518 "printqd.ctr" if (0 == dk4dbi_close(db, NULL)) { #line 4519 "printqd.ctr" /* ERROR: Failed to synchronize database to disk */ log_1(NULL, 0UL, LOG_EMERG, 1, 121); } db = NULL; db_modified = 0; if (DK4_DB_BE_BDB == dbt) { fn = ((NULL != conf.dname) ? (conf.dname) : (def_db_file_name)); fn = dk4dbi_filename_part(fn); if (0 != chown(fn, conf.uid, conf.gid)) { back = 0; log_3(NULL, 0UL, LOG_EMERG, 1, 174, 175, fn); } if (0 != chmod(fn, 0660)) { back = 0; log_3(NULL, 0UL, LOG_EMERG, 1, 176, 177, fn); } } } break; } /* Local UNIX socket ownership and permission */ if (INVALID_SOCKET != so_unix) { #line 4542 "printqd.ctr" #line 4543 "printqd.ctr" if (0 != fchown(so_unix, conf.uid, conf.gid)) { back = 0; #line 4545 "printqd.ctr" /* ERROR: Failed to change socket ownership */ log_1(NULL, 0UL, LOG_EMERG, 1, 112); } #line 4549 "printqd.ctr" if (0 != fchmod(so_unix, 0660)) { back = 0; #line 4551 "printqd.ctr" /* ERROR: Failed to change socket permissions */ log_1(NULL, 0UL, LOG_EMERG, 1, 113); } } else { #line 4555 "printqd.ctr" } /* Switch group */ if (0 != setgid(conf.gid)) { back = 0; #line 4561 "printqd.ctr" /* ERROR: Failed to switch group */ log_1(NULL, 0UL, LOG_EMERG, 1, 114); } /* Switch user */ if (0 != setuid(conf.uid)) { back = 0; #line 4569 "printqd.ctr" /* ERROR: Failed to switch user */ log_1(NULL, 0UL, LOG_EMERG, 1, 115); } /* Re-open database if closed. */ if (NULL == db) { #line 4576 "printqd.ctr" fn = conf.dname; if (NULL == fn) { fn = def_db_file_name; } db = dk4dbi_open(fn, 1, 0, 1024, 1024, NULL); if (NULL != db) { db_modified = 0; } else { #line 4582 "printqd.ctr" back = 0; /* ERROR: Failed to open database */ log_3(NULL, 0UL, LOG_EMERG, 1, 105, 106, fn); } } } else { #line 4588 "printqd.ctr" } } #line 4591 "printqd.ctr" return back; } static int protocol_level_for_address(struct sockaddr *so) { int back = PQD_PROTO_NONE; #line 4602 "printqd.ctr" if (0 != conf.aglo) { back = PQD_PROTO_ADMIN; } else { if (NULL != dk4sto_it_find_like(conf.i_aa, so, 1)) { back = PQD_PROTO_ADMIN; } else { if (0 != conf.dglo) { back = PQD_PROTO_DATA; } else { if (NULL != dk4sto_it_find_like(conf.i_ad, so, 1)) { back = PQD_PROTO_DATA; } else { if (0 != conf.iglo) { back = PQD_PROTO_INFO; } else { if (NULL != dk4sto_it_find_like(conf.i_ai, so, 1)) { back = PQD_PROTO_INFO; } } } } } } #line 4626 "printqd.ctr" return back; } /** Check whether the action is allowed in the protocol level. @param act Action to check. @param protlev Protocol level. @return 1 if action is allowed, 0 otherwise. */ static int protocol_level_check(int act, int protlev) { int back = 0; #line 4642 "printqd.ctr" switch (act) { case PQD_CMD_INFO : { if (PQD_PROTO_INFO <= protlev) { back = 1; } } break; case PQD_CMD_CONTROL : { if (PQD_PROTO_ADMIN <= protlev) { back = 1; } } break; default : { if (PQD_PROTO_DATA <= protlev) { back = 1; } } break; } #line 4654 "printqd.ctr" return back; } static void job_init(pqd_rq_t *ptr) { #line 4664 "printqd.ctr" DK4_MEMRES(ptr, sizeof(pqd_rq_t)); ptr->connptr = NULL; ptr->sto = NULL; ptr->soa = NULL; ptr->pnconn = NULL; ptr->cmdptr = NULL; ptr->argptr = NULL; ptr->szsoa = 0; ptr->sock = 0; ptr->action = 0; ptr->protlev = PQD_PROTO_NONE; ptr->logthis = 1; #line 4677 "printqd.ctr" } static void account_init(pqd_account_t *ptr) { #line 4686 "printqd.ctr" DK4_MEMRES(ptr, sizeof(pqd_account_t)); ptr->limit = (dk4_um_t)0UL; ptr->used = (dk4_um_t)0UL; ptr->account = (dk4_um_t)0UL; ptr->da = 0; #line 4692 "printqd.ctr" } /** Close a stream connection record. @param sock Socket to close. @param sto Container for the records. @param ptr Record to delete, containing the socket. @param pnconn Address of connection number variable to decrease. */ static void close_stream_conn( dk4_socket_t sock, dk4_sto_t *sto, void *ptr, size_t *pnconn ) { #line 4712 "printqd.ctr" if ((NULL != sto) && (NULL != ptr)) { dk4sto_remove(sto, ptr, NULL); } if (INVALID_SOCKET != sock) { (void)dk4socket_close(sock, NULL); } if (NULL != ptr) { dk4mem_free(ptr); } if (NULL != pnconn) { if (0 < *pnconn) { *pnconn -= 1; } } #line 4727 "printqd.ctr" } /** Send a text response. @param job Job structure. @param str Text to send (still without newline). */ static void send_text(pqd_rq_t *job, const char *str) { const char * msgs[3]; /* Log message text parts */ size_t sz; /* Number of bytes to send */ size_t wr; /* Number of bytes successfully sent */ int res; /* Operation result */ #line 4744 "printqd.ctr" if (0 != dk4str8_cpy_s(inbuf, sizeof(inbuf), str, NULL)) { if (0 != job->logthis) { msgs[0] = printqd_kw[86]; msgs[1] = str; msgs[2] = NULL; log_multipart_message(NULL, 0UL, LOG_EMERG, 0, msgs, 2); } if (0 != dk4str8_cat_s(inbuf, sizeof(inbuf), printqd_kw[5], NULL)) { sz = dk4str8_len(inbuf); wr = sz; if ((NULL != job->soa) && (0 < job->szsoa)) { #line 4755 "printqd.ctr" (void)dk4socket_sendto( job->sock, inbuf, &wr, 0, job->soa, job->szsoa, 0L, 0L, NULL ); } else { #line 4759 "printqd.ctr" res = dk4socket_send(job->sock, inbuf, &wr, 0, 0L, 0L, NULL); switch (res) { case DK4_SOCKET_RESULT_SUCCESS : case DK4_SOCKET_RESULT_IN_PROGRESS : { if (wr != sz) { #line 4764 "printqd.ctr" res = DK4_SOCKET_RESULT_FAILED; } } break; } if (DK4_SOCKET_RESULT_FAILED == res) { #line 4769 "printqd.ctr" close_stream_conn(job->sock, job->sto, job->connptr, job->pnconn); } } } else { #line 4773 "printqd.ctr" /* ERROR: Response text too long (BUG)! */ log_1(NULL, 0UL, LOG_EMERG, 1, 116); } } else { #line 4777 "printqd.ctr" /* ERROR: Response text too long (BUG)! */ log_1(NULL, 0UL, LOG_EMERG, 1, 116); } #line 4781 "printqd.ctr" } /** Send response for info or acct-check request. @param job Job structure. @param account Account structure containing limits and used pages. @param summary Summary: Allowed to print. @param how How to respond: 0=info, 1=acct-check/jobstart. */ static void send_response( pqd_rq_t *job, pqd_account_t *account, int summary, int how ) { char res[16+32*sizeof(dk4_um_t)]; char b1[16+8*sizeof(dk4_um_t)]; int ok = 0; #line 4804 "printqd.ctr" switch (how) { case 0: { /* Limit Used Account Summary */ if (DK4_UM_MAX == account->limit) { ok = dk4str8_cpy_s(res, sizeof(res), printqd_kw[84], NULL); } else { ok = dk4ma_write_c8_decimal_unsigned( b1, sizeof(b1), account->limit, 0, NULL ); if (0 != ok) { ok = dk4str8_cpy_s(res, sizeof(res), b1, NULL); } } if (0 != ok) { ok = dk4ma_write_c8_decimal_unsigned( b1, sizeof(b1), account->used, 0, NULL ); if (0 != ok) { ok = dk4str8_cat_s(res, sizeof(res), printqd_kw[85], NULL); if (0 != ok) { ok = dk4str8_cat_s(res, sizeof(res), b1, NULL); if (0 != ok) { ok = dk4ma_write_c8_decimal_unsigned( b1, sizeof(b1), account->account, 0, NULL ); if (0 != ok) { ok = dk4str8_cat_s(res, sizeof(res), printqd_kw[85], NULL); if (0 != ok) { ok = dk4str8_cat_s(res, sizeof(res), b1, NULL); if (0 != ok) { ok = dk4ma_write_c8_decimal_signed( b1, sizeof(b1), (dk4_im_t)summary, 0, NULL ); if (0 != ok) { ok = dk4str8_cat_s(res,sizeof(res),printqd_kw[85],NULL); if (0 != ok) { ok = dk4str8_cat_s(res, sizeof(res), b1, NULL); } } } } } } } } } if (0 != ok) { send_text(job, res); } else { send_text(job, printqd_kw[83]); } } break; default: { if (0 != summary) { send_text(job, printqd_kw[80]); } else { switch (account->da) { case 0: { send_text(job, printqd_kw[81]); } break; default: { send_text(job, printqd_kw[82]); } break; } } } break; } #line 4872 "printqd.ctr" } /** Get printer entry for name (printer or alias name). @param name Printer or alias name. @return Printer entry. */ static pqd_printer_t * get_printer_for_name(const char *name) { pqd_printer_t *back = NULL; pqd_printer_alias_t *al = NULL; #line 4887 "printqd.ctr" back = (pqd_printer_t *)dk4sto_it_find_like(conf.i_p, name, 1); if (NULL == back) { al = (pqd_printer_alias_t *)dk4sto_it_find_like(conf.i_a, name, 1); if (NULL != al) { back = al->pr; } } #line 4895 "printqd.ctr" return back; } /** Save one dk4_um_t value to database. @param kwi Keyword index for key start. @param un User name. @param cn Class name. @param val Value to store. @return 1 on success, 0 on error. */ static int save_one_number( size_t kwi, const char *un, const char *cn, dk4_um_t val ) { int back = 0; int strok = 0; #line 4919 "printqd.ctr" if (0 != dk4str8_cpy_s(kb, sizeof(kb), printqd_kw[kwi], NULL)) { if (0 != dk4str8_cat_s(kb, sizeof(kb), cn, NULL)) { if (0 != dk4str8_cat_s(kb, sizeof(kb), printqd_kw[8], NULL)) { if (0 != dk4str8_cat_s(kb, sizeof(kb), un, NULL)) { if ((dk4_um_t)0UL != val) { if(0 != dk4ma_write_c8_decimal_unsigned(vb,sizeof(vb),val,0,NULL)) { strok = 1; #line 4927 "printqd.ctr" if (0 != dbi_set(db, kb, vb, NULL)) { #line 4928 "printqd.ctr" back = 1; } else { #line 4931 "printqd.ctr" /* ERROR: Failed to set DB entry */ log_1(NULL, 0UL, LOG_EMERG, 1, 117); } } #if TRACE_DEBUG else { #line 4937 "printqd.ctr" } #endif } else { strok = 1; #line 4942 "printqd.ctr" if (0 != dbi_del(db, kb, NULL)) { #line 4943 "printqd.ctr" back = 1; } else { #line 4945 "printqd.ctr" /* ERROR: Failed to delete DB entry */ log_1(NULL, 0UL, LOG_EMERG, 1, 118); } } } } } } if (0 == strok) { /* ##### ERROR: Strings too long */ } #line 4957 "printqd.ctr" return back; } /** Save changes in account to database. @param oldacc Previous account information, may be NULL. @param newacc Updated account information, not NULL. @param un User name. @param cl Class structure. @return 1 on success, 0 on error. */ static int save_account_for_user_and_class( pqd_account_t *oldacc, pqd_account_t *newacc, const char *un, pqd_class_t *cl ) { int mustsave; /* Flag: Must save item */ int back = 1; #line 4981 "printqd.ctr" mustsave = 1; if (NULL != oldacc) { if (oldacc->used == newacc->used) { mustsave = 0; } } if (0 != mustsave) { #line 4988 "printqd.ctr" if (0 == save_one_number(88, un, cl->name, newacc->used)) { back = 0; } } mustsave = 1; if (NULL != oldacc) { if (oldacc->account == newacc->account) { mustsave = 0; } } if (0 != mustsave) { #line 4999 "printqd.ctr" if (0 == save_one_number(89, un, cl->name, newacc->account)) { back = 0; } } #line 5004 "printqd.ctr" return back; } /** Retrieve account data for a user in a specified printer class. @param account Data structure to fill. @param un User name. @param cl Printer class. @param mi Flag: Must initialize account before filling it. @return 1 on success, 0 on error. */ static int retrieve_account_for_user_and_class( pqd_account_t *account, const char *un, pqd_class_t *cl, int mi ) { char **grmem = NULL; const char *ep = NULL; /* End of data */ pqd_limit_t *lim = NULL; /* Limit set */ struct passwd *pw = NULL; /* Password struct */ struct group *gr = NULL; /* Group struct */ dk4_um_t um = (dk4_um_t)0UL; /* Value found in text */ gid_t pg = 0; /* Primary group */ int ingr = 0; /* Flag: User in group */ int back = 0; #line 5035 "printqd.ctr" /* Check arguments */ if (NULL == account) { goto finished; } if (0 != mi) { account_init(account); } if ((NULL == un) || (NULL == cl)) { goto finished; } if (NULL == cl->name) { goto finished; } /* Use default action from class */ account->da = cl->da; /* Find number of pages already printed */ if (0 != dk4str8_cpy_s(kb, sizeof(kb), printqd_kw[88], NULL)) { if (0 != dk4str8_cat_s(kb, sizeof(kb), cl->name, NULL)) { if (0 != dk4str8_cat_s(kb, sizeof(kb), printqd_kw[8], NULL)) { if (0 != dk4str8_cat_s(kb, sizeof(kb), un, NULL)) { #line 5062 "printqd.ctr" if (0 != dbi_get(db, kb, vb, sizeof(vb), NULL)) { if (0 != dk4ma_input_c8_dec_dk4_um_t(&um, vb, &ep, 1, NULL)) { account->used = um; } #if TRACE_DEBUG else { #line 5068 "printqd.ctr" } #endif } #if TRACE_DEBUG else { #line 5073 "printqd.ctr" } #endif } } } } /* Find number of pages in personal print account */ if (0 != dk4str8_cpy_s(kb, sizeof(kb), printqd_kw[89], NULL)) { if (0 != dk4str8_cat_s(kb, sizeof(kb), cl->name, NULL)) { if (0 != dk4str8_cat_s(kb, sizeof(kb), printqd_kw[8], NULL)) { if (0 != dk4str8_cat_s(kb, sizeof(kb), un, NULL)) { #line 5087 "printqd.ctr" if (0 != dbi_get(db, kb, vb, sizeof(vb), NULL)) { um = (dk4_um_t)0UL; ep = NULL; if (0 != dk4ma_input_c8_dec_dk4_um_t(&um, vb, &ep, 1, NULL)) { account->account = um; } #if TRACE_DEBUG else { #line 5094 "printqd.ctr" } #endif } #if TRACE_DEBUG else { #line 5099 "printqd.ctr" } #endif } } } } /* Find user limit */ #line 5109 "printqd.ctr" lim = (pqd_limit_t *)dk4sto_it_find_like(cl->i_u, un, 1); if (NULL != lim) { #line 5111 "printqd.ctr" account->limit = lim->limit; back = 1; goto finished; } /* Find group limit */ #line 5119 "printqd.ctr" pw = getpwnam(un); if (NULL != pw) { #line 5121 "printqd.ctr" pg = pw->pw_gid; dk4sto_it_reset(cl->i_g); do { #line 5125 "printqd.ctr" lim = dk4sto_it_next(cl->i_g); if (NULL != lim) { #line 5127 "printqd.ctr" if (lim->limit > account->limit) { #line 5128 "printqd.ctr" #line 5129 "printqd.ctr" gr = getgrnam(lim->name); if (NULL != gr) { #line 5131 "printqd.ctr" if (pg == gr->gr_gid) { #line 5132 "printqd.ctr" account->limit = lim->limit; back = 1; } else { #line 5135 "printqd.ctr" if (NULL != gr->gr_mem) { grmem = gr->gr_mem; ingr = 0; while ((0 == ingr) && (NULL != *grmem)) { #line 5140 "printqd.ctr" if (0 == strcmp(un, *grmem)) { ingr = 1; } grmem++; } if (0 != ingr) { #line 5146 "printqd.ctr" account->limit = lim->limit; back = 1; } #if TRACE_DEBUG else { #line 5151 "printqd.ctr" } #endif } #if TRACE_DEBUG else { #line 5156 "printqd.ctr" } #endif } } #if TRACE_DEBUG else { #line 5162 "printqd.ctr" } #endif } } #if TRACE_DEBUG else { #line 5168 "printqd.ctr" } #endif #line 5171 "printqd.ctr" } while(NULL != lim); if (0 != back) { goto finished; } } #if TRACE_DEBUG else { #line 5178 "printqd.ctr" } #endif /* Apply default limit */ #line 5184 "printqd.ctr" account->limit = cl->dl; back = 1; finished: #line 5189 "printqd.ctr" return back; } /** Retrieve user account data for a given user name and a given printer name. @param account Account structure to fill. @param printer_name Print queue name or alias. @param user_name User name. @return 1 on success, 0 on error. */ static int retrieve_account_data( pqd_account_t *account, const char *printer_name, const char *user_name ) { pqd_printer_t *pr = NULL; /* Printer */ pqd_class_t *cl = NULL; /* Class */ int back = 0; #line 5213 "printqd.ctr" /* Initialize account data */ account_init(account); /* Find printer */ pr = get_printer_for_name(printer_name); if (NULL == pr) { #line 5222 "printqd.ctr" goto finished; } /* Find class for printer */ cl = pr->cl; if (NULL == cl) { #line 5229 "printqd.ctr" goto finished; } if (NULL == cl->name) { #line 5232 "printqd.ctr" goto finished; } /* Search for data */ back = retrieve_account_for_user_and_class(account, user_name, cl, 0); /* Return result */ finished: #line 5243 "printqd.ctr" return back; } /** Add a number of pages for a print job to existing account data. @param account Account data for user. @param pages Number of pages used by print job. */ static void account_add_pages_from_job(pqd_account_t *account, dk4_um_t pages) { dk4_um_t available; /* The limit is used first. */ if (account->limit > account->used) { available = account->limit - account->used; if (available >= pages) { account->used += pages; pages = (dk4_um_t)0UL; } else { account->used = account->limit; pages -= available; } } /* The personal print account is used only if the limit is reached. */ if ((dk4_um_t)0UL < pages) { if (account->account >= pages) { account->account -= pages; } else { pages -= account->account; account->account = (dk4_um_t)0UL; } } /* Finally keep track of pages printed over limit. */ if ((dk4_um_t)0UL < pages) { if ((DK4_UM_MAX - pages) >= account->used) { account->used += pages; } else { account->used = DK4_UM_MAX; } } } /** Find summary (allowed to print) for account details. @param limit Limit (maximum number of pages) for user. @param used Number of used pages within the limit. @param account Number of pages in additional personal print account. @return 1 if printing is allowed, 0 otherwise. */ static int account_summary(dk4_um_t limit, dk4_um_t used, dk4_um_t account) { int back = 0; #line 5305 "printqd.ctr" if (DK4_UM_MAX == limit) { #line 5306 "printqd.ctr" back = 1; } else { if (used < limit) { #line 5309 "printqd.ctr" back = 1; } else { if ((dk4_um_t)0UL < account) { #line 5312 "printqd.ctr" back = 1; } } } #line 5317 "printqd.ctr" return back; } /** Process info or acct-check request, only retrieve data without modifying anything. @param job Data for one request to process. @param how Response type: 0=info, 1=acct-check. */ static void rq_retrieve_data(pqd_rq_t *job, int how) { pqd_account_t account; char *printer_name = NULL; char *user_name = NULL; int summary = 0; #line 5335 "printqd.ctr" printer_name = job->argptr; if (NULL != printer_name) { user_name = dk4str8_next(printer_name, NULL); if (NULL != user_name) { (void)dk4str8_next(user_name, NULL); } } if ((NULL != printer_name) && (NULL != user_name)) { if (0 != retrieve_account_data(&account, printer_name, user_name)) { #if VERSION_BEFORE_20160329 if ((account.used < account.limit) || ((dk4_um_t)0UL < account.account)) { summary = 1; } #else summary = account_summary(account.limit, account.used, account.account); #endif } send_response(job, &account, summary, how); } else { /* Close connection on malformed request. */ if ((NULL == job->soa) && (0 == job->szsoa)) { close_stream_conn(job->sock, job->sto, job->connptr, job->pnconn); } } #line 5361 "printqd.ctr" } /** Process info request. @param job Data for one request to process. */ static void rq_info(pqd_rq_t *job) { #line 5373 "printqd.ctr" rq_retrieve_data(job, 0); #line 5375 "printqd.ctr" } /** Find final quote for current word. @param str String to find quote in. @param quote Quote character. @return Pointer to found quote on success, NULL on error. */ static char * lprng_final_quote(char *str, char quote) { char *back = NULL; #line 5390 "printqd.ctr" while (('\0' != *str) && (NULL == back)) { if (quote == *str) { *str = '\0'; back = str; back++; back = dk4str8_start(back, NULL); } else { if ('\\' == *str) { if ('\0' != str[1]) { dk4str8_cpy_to_left(str, &(str[1])); str++; } else { *str = '\0'; } } else { str++; } } } #line 5410 "printqd.ctr" return back; } /** Find start of next text word in LPRng accounting line. @param str Current word (remaining text) in accounting line. @return Pointer to next word if found, NULL on error. */ static char * lprng_next_word(char *str) { char *back = NULL; #line 5425 "printqd.ctr" switch (*str) { case '\'' : { back = lprng_final_quote(&(str[1]), '\''); } break; case '"' : { back = lprng_final_quote(&(str[1]), '"'); } break; default : { back = dk4str8_next(str, NULL); } break; } #line 5436 "printqd.ctr" return back; } /** Fill data structure from LPRng accounting line. @param liptr Structure to fill. @param textline The text line to use. @return 1 on success, 0 on error. */ static int lprng_info_from_line(lprng_info_t *liptr, char *textline) { char *next; int back = 1; #line 5453 "printqd.ctr" DK4_MEMRES(liptr, sizeof(lprng_info_t)); liptr->username = NULL; liptr->queuename = NULL; liptr->jobtitle = NULL; liptr->pagecount = NULL; while (NULL != textline) { next = lprng_next_word(textline); if (('\'' == *textline) || ('"' == *textline)) { textline++; } if ('-' == *textline) { textline++; switch (*textline) { case 'n': { liptr->username = ++textline; } break; case 'P': { liptr->queuename = ++textline; } break; case 'J': { liptr->jobtitle = ++textline; } break; case 'p': { liptr->pagecount = ++textline; } break; } } else { #line 5478 "printqd.ctr" #if 0 /* 2016-02-15 Simply ignore non-option text. */ back = 0; /* ERROR: No minus sign */ #endif } textline = next; } #line 5488 "printqd.ctr" return back; } /** Process jobstart request. @param job Data for one request to process. */ static void rq_jobstart(pqd_rq_t *job) { lprng_info_t lpi; pqd_account_t account; char *un = NULL; char *qn = NULL; int summ = 0; #line 5506 "printqd.ctr" if (0 != lprng_info_from_line(&lpi, job->argptr)) { un = lpi.username; qn = lpi.queuename; } if ((NULL != un) && (NULL != qn)) { if (0 != retrieve_account_data(&account, qn, un)) { summ = account_summary(account.limit, account.used, account.account); } send_response(job, &account, summ, 1); } else { /* Close connection on malformed request. */ if ((NULL == job->soa) && (0 == job->szsoa)) { close_stream_conn(job->sock, job->sto, job->connptr, job->pnconn); } } #line 5522 "printqd.ctr" } /** Report change result to log file. @param un User name. @param cl Class. @param olda Old account values. @param newa New account values. @param pages Number of pages to add. @param doadd Flag: Show added pages instead of used pages. */ static 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 ) { char nb[8*sizeof(dk4_um_t)]; const char *msgs[2]; int res = 1; if (0 == dk4str8_cpy_s(kb, sizeof(kb), un, NULL)) { res = 0; } if (0 == dk4str8_cat_s(kb, sizeof(kb), printqd_kw[85], NULL)) { res = 0; } if (0 == dk4str8_cat_s(kb, sizeof(kb), cl->name, NULL)) { res = 0; } if (0 == dk4str8_cat_s(kb, sizeof(kb), printqd_kw[7], NULL)) { res = 0; } if (0 == dk4str8_cat_s(kb, sizeof(kb), printqd_kw[145], NULL)) { res = 0; } if (DK4_UM_MAX == olda->limit) { if (0 == dk4str8_cat_s(kb, sizeof(kb), printqd_kw[151], NULL)) { res = 0; } } else { if(0 != dk4ma_write_c8_decimal_unsigned(nb,sizeof(nb),olda->limit,0,NULL)) { if (0 == dk4str8_cat_s(kb, sizeof(kb), nb, NULL)) { res = 0; } } else { res = 0; } } if (0 == dk4str8_cat_s(kb, sizeof(kb), printqd_kw[146], NULL)) { res = 0; } if(0 != dk4ma_write_c8_decimal_unsigned(nb,sizeof(nb),olda->used,0,NULL)) { if (0 == dk4str8_cat_s(kb, sizeof(kb), nb, NULL)) { res = 0; } } else { res = 0; } if (0 == dk4str8_cat_s(kb, sizeof(kb), printqd_kw[147], NULL)) { res = 0; } if(0 != dk4ma_write_c8_decimal_unsigned(nb,sizeof(nb),olda->account,0,NULL)) { if (0 == dk4str8_cat_s(kb, sizeof(kb), nb, NULL)) { res = 0; } } else { res = 0; } switch (doadd) { case 1: { if (0 == dk4str8_cat_s(kb,sizeof(kb),printqd_kw[153],NULL)) { res = 0; } } break; default: { if (0 == dk4str8_cat_s(kb,sizeof(kb),printqd_kw[148],NULL)) { res = 0; } } break; } if(0 != dk4ma_write_c8_decimal_unsigned(nb,sizeof(nb),pages,0,NULL)) { if (0 == dk4str8_cat_s(kb, sizeof(kb), nb, NULL)) { res = 0; } } else { res = 0; } if (0 == dk4str8_cat_s(kb, sizeof(kb), printqd_kw[149], NULL)) { res = 0; } if (DK4_UM_MAX == newa->limit) { if (0 == dk4str8_cat_s(kb, sizeof(kb), printqd_kw[151], NULL)) { res = 0; } } else { if(0 != dk4ma_write_c8_decimal_unsigned(nb,sizeof(nb),newa->limit,0,NULL)) { if (0 == dk4str8_cat_s(kb, sizeof(kb), nb, NULL)) { res = 0; } } else { res = 0; } } if (0 == dk4str8_cat_s(kb, sizeof(kb), printqd_kw[146], NULL)) { res = 0; } if(0 != dk4ma_write_c8_decimal_unsigned(nb,sizeof(nb),newa->used,0,NULL)) { if (0 == dk4str8_cat_s(kb, sizeof(kb), nb, NULL)) { res = 0; } } else { res = 0; } if (0 == dk4str8_cat_s(kb, sizeof(kb), printqd_kw[147], NULL)) { res = 0; } if(0 != dk4ma_write_c8_decimal_unsigned(nb,sizeof(nb),newa->account,0,NULL)) { if (0 == dk4str8_cat_s(kb, sizeof(kb), nb, NULL)) { res = 0; } } else { res = 0; } if (0 == dk4str8_cat_s(kb, sizeof(kb), printqd_kw[150], NULL)) { res = 0; } if (0 != res) { msgs[0] = kb; msgs[1] = NULL; log_multipart_message(NULL, 0UL, LOG_EMERG, 0, msgs, 1); } } /** Charge user for a print job. @param job Job structure. @param un User name. @param cl Printer class of printer the job was printed on. @param pcval Number of pages in print job. */ static void do_charge( pqd_rq_t *job, const char *un, pqd_class_t *cl, dk4_um_t pcval ) { pqd_account_t oldacc; pqd_account_t newacc; #line 5637 "printqd.ctr" if (0 != retrieve_account_for_user_and_class(&oldacc, un, cl, 1)) { DK4_MEMCPY(&newacc, &oldacc, sizeof(pqd_account_t)); account_add_pages_from_job(&newacc, pcval); log_old_and_new_account(un, cl, &oldacc, &newacc, pcval, 0); if (0 == save_account_for_user_and_class(&oldacc, &newacc, un, cl)) { #line 5643 "printqd.ctr" /* ERROR: Failed to update account data */ log_5(NULL, 0UL, LOG_EMERG, 1, 156, 157, 158, un, cl->name); } } #if TRACE_DEBUG else { #line 5649 "printqd.ctr" } #endif #line 5652 "printqd.ctr" } /** On start of file printing save user name, job name and pagecount value to database for later use. @param job Job structure. @param un User name. @param pn Printer name. @param jn Job name. @param pc Printer page count at start of job. */ static void do_filestart( pqd_rq_t *job, const char *un, const char *pn, const char *jn, const char *pc ) { const char *ep = NULL; pqd_printer_t *pr = NULL; pqd_class_t *cl = NULL; dk4_um_t pcstt = (dk4_um_t)0UL; int res = 0; #line 5680 "printqd.ctr" pr = get_printer_for_name(pn); if (NULL != pr) { cl = pr->cl; } if (NULL != cl) { res = dk4ma_input_c8_dec_dk4_um_t(&pcstt, pc, &ep, 1, NULL); } if ((NULL != pr) && (NULL != cl) && (0 != res)) { #line 5689 "printqd.ctr" if (0 == dk4str8_cpy_s(kb, sizeof(kb), printqd_kw[90], NULL)) { res = 0; } if (0 == dk4str8_cat_s(kb, sizeof(kb), pr->name, NULL)) { res = 0; } if (0 == dk4str8_cpy_s(vb, sizeof(vb), pc, NULL)) { res = 0; } if (0 == dk4str8_cat_s(vb, sizeof(vb), printqd_kw[8], NULL)) { res = 0; } if (0 == dk4str8_cat_s(vb, sizeof(vb), un, NULL)) { res = 0; } if (0 == dk4str8_cat_s(vb, sizeof(vb), printqd_kw[8], NULL)) { res = 0; } if (0 == dk4str8_cat_s(vb, sizeof(vb), jn, NULL)) { res = 0; } if (0 != res) { #line 5697 "printqd.ctr" if (0 == dbi_set(db, kb, vb, NULL)) { #line 5698 "printqd.ctr" /* ERROR: Failed to set database entry */ log_1(NULL, 0UL, LOG_EMERG, 1, 117); } } #if TRACE_DEBUG else { #line 5704 "printqd.ctr" } #endif } else { #line 5707 "printqd.ctr" /* Close connection on malformed request */ if ((NULL == job->soa) && (0 == job->szsoa)) { close_stream_conn(job->sock, job->sto, job->connptr, job->pnconn); } } #line 5714 "printqd.ctr" } /** On end of file calculate page number used by the job and save modified account to database. @param job Job structure. @param un User name. @param pn Printer name. @param jn Job name. @param pc Printer page count at start of job. */ static void do_fileend( pqd_rq_t *job, const char *un, const char *pn, const char *jn, const char *pc ) { const char *ep = NULL; /* End of processed text */ pqd_printer_t *pr = NULL; /* Printer */ pqd_class_t *cl = NULL; /* Printer class */ char *oun = NULL; /* Old user name */ char *opc = NULL; /* Old page counter value */ char *ojn = NULL; /* Old job name */ dk4_um_t pcstt = (dk4_um_t)0UL; /* Page counter at job start */ dk4_um_t pcend = (dk4_um_t)0UL; /* Page counter at job end */ int res = 0; #line 5747 "printqd.ctr" pr = get_printer_for_name(pn); if (NULL != pr) { cl = pr->cl; } if (NULL != cl) { res = dk4ma_input_c8_dec_dk4_um_t(&pcend, pc, &ep, 1, NULL); } if ((NULL != pr) && (NULL != cl) && (0 != res)) { if (0 == dk4str8_cpy_s(kb, sizeof(kb), printqd_kw[90], NULL)) { res = 0; } if (0 == dk4str8_cat_s(kb, sizeof(kb), pr->name, NULL)) { res = 0; } if (0 != res) { #line 5758 "printqd.ctr" if (0 != dbi_get(db, kb, vb, sizeof(vb), NULL)) { #line 5760 "printqd.ctr" if (0 == dbi_del(db, kb, NULL)) { /* ERROR: Failed to delete db entry */ log_1(NULL, 0UL, LOG_EMERG, 1, 118); } #line 5765 "printqd.ctr" opc = dk4str8_start(vb, NULL); if (NULL != opc) { oun = dk4str8_chr(opc, ':'); if (NULL != oun) { *(oun++) = '\0'; oun = dk4str8_start(oun, NULL); } } if (NULL != oun) { ojn = dk4str8_chr(oun, ':'); if (NULL != ojn) { *(ojn++) = '\0'; ojn = dk4str8_start(ojn, NULL); } } if ((NULL != opc) && (NULL != oun) && (NULL != ojn)) { #line 5782 "printqd.ctr" #line 5783 "printqd.ctr" #line 5784 "printqd.ctr" if (0 == strcmp(ojn, jn)) { if (0 == strcmp(oun, un)) { ep = NULL; res = dk4ma_input_c8_dec_dk4_um_t(&pcstt, opc, &ep, 1, NULL); if (0 != res) { if (pcend > pcstt) { #line 5790 "printqd.ctr" do_charge(job, un, cl, (pcend - pcstt)); } #if TRACE_DEBUG else { #line 5794 "printqd.ctr" } #endif } #if TRACE_DEBUG else { #line 5799 "printqd.ctr" } #endif } #if TRACE_DEBUG else { #line 5804 "printqd.ctr" } #endif } #if TRACE_DEBUG else { #line 5809 "printqd.ctr" } #endif } #if TRACE_DEBUG else { #line 5814 "printqd.ctr" } #endif } else { #line 5818 "printqd.ctr" #line 5819 "printqd.ctr" if (0 == dbi_del(db, kb, NULL)) { /* ERROR: Failed to delete db entry */ log_1(NULL, 0UL, LOG_EMERG, 1, 118); } } } #if TRACE_DEBUG else { #line 5827 "printqd.ctr" } #endif } else { #line 5830 "printqd.ctr" /* Close connection on malformed request */ if ((NULL == job->soa) && (0 == job->szsoa)) { close_stream_conn(job->sock, job->sto, job->connptr, job->pnconn); } } #line 5837 "printqd.ctr" } /** Process filestart request. @param job Data for one request to process. */ static void rq_filestart(pqd_rq_t *job) { lprng_info_t lpi; char *un = NULL; char *pn = NULL; char *jn = NULL; char *pc = NULL; #line 5854 "printqd.ctr" if (0 != lprng_info_from_line(&lpi, job->argptr)) { un = lpi.username; pn = lpi.queuename; jn = lpi.jobtitle; pc = lpi.pagecount; } if ((NULL != un) && (NULL != pn) && (NULL != jn) && (NULL != pc)) { do_filestart(job, un, pn, jn, pc); } else { /* Close connection on malformed request */ if ((NULL == job->soa) && (0 == job->szsoa)) { close_stream_conn(job->sock, job->sto, job->connptr, job->pnconn); } } #line 5868 "printqd.ctr" } /** Process fileend request. @param job Data for one request to process. */ static void rq_fileend(pqd_rq_t *job) { lprng_info_t lpi; char *un = NULL; char *pn = NULL; char *jn = NULL; char *pc = NULL; #line 5885 "printqd.ctr" if (0 != lprng_info_from_line(&lpi, job->argptr)) { un = lpi.username; pn = lpi.queuename; jn = lpi.jobtitle; pc = lpi.pagecount; } if ((NULL != un) && (NULL != pn) && (NULL != jn) && (NULL != pc)) { do_fileend(job, un, pn, jn, pc); } else { /* Close connection on malformed request */ if ((NULL == job->soa) && (0 == job->szsoa)) { close_stream_conn(job->sock, job->sto, job->connptr, job->pnconn); } } #line 5899 "printqd.ctr" } /** Process acct-check request. @param job Data for one request to process. */ static void rq_acct_check(pqd_rq_t *job) { #line 5911 "printqd.ctr" rq_retrieve_data(job, 1); #line 5913 "printqd.ctr" } /** Process acct-start request. @param job Data for one request to process. */ static void rq_acct_start(pqd_rq_t *job) { char *un = NULL; char *pn = NULL; char *jn = NULL; char *pc = NULL; #line 5929 "printqd.ctr" pn = job->argptr; if (NULL != pn) { un = dk4str8_next(pn, NULL); } if (NULL != un) { pc = dk4str8_next(un, NULL); } if (NULL != pc) { jn = dk4str8_next(pc, NULL); } if (NULL != jn) { (void)dk4str8_next(jn, NULL); } if ((NULL != un) && (NULL != pn) && (NULL != jn) && (NULL != pc)) { do_filestart(job, un, pn, jn, pc); } else { /* Close connection on malformed request */ if ((NULL == job->soa) && (0 == job->szsoa)) { close_stream_conn(job->sock, job->sto, job->connptr, job->pnconn); } } #line 5952 "printqd.ctr" } /** Process acct-end request. @param job Data for one request to process. */ static void rq_acct_end(pqd_rq_t *job) { char *un = NULL; char *pn = NULL; char *jn = NULL; char *pc = NULL; #line 5968 "printqd.ctr" pn = job->argptr; if (NULL != pn) { un = dk4str8_next(pn, NULL); } if (NULL != un) { pc = dk4str8_next(un, NULL); } if (NULL != pc) { jn = dk4str8_next(pc, NULL); } if (NULL != jn) { (void)dk4str8_next(jn, NULL); } if ((NULL != un) && (NULL != pn) && (NULL != jn) && (NULL != pc)) { do_fileend(job, un, pn, jn, pc); } else { /* Close connection on malformed request */ if ((NULL == job->soa) && (0 == job->szsoa)) { close_stream_conn(job->sock, job->sto, job->connptr, job->pnconn); } } #line 5991 "printqd.ctr" } /** Process acct-charge request. @param job Data for one request to process. */ static void rq_acct_charge(pqd_rq_t *job) { const char *ep = NULL; pqd_printer_t *pr = NULL; pqd_class_t *cl = NULL; char *un = NULL; char *pn = NULL; char *pc = NULL; dk4_um_t pcval = (dk4_um_t)0UL; #line 6010 "printqd.ctr" pn = job->argptr; if (NULL != pn) { un = dk4str8_next(pn, NULL); } if (NULL != un) { pc = dk4str8_next(un, NULL); } if (NULL != pc) { (void)dk4str8_next(pc, NULL); } if (NULL != pn) { pr = get_printer_for_name(pn); } if (NULL != pr) { cl = pr->cl; } if ( (NULL != un) && (NULL != pn) && (NULL != pc) && (NULL != pr) && (NULL != cl) ) { if (0 != dk4ma_input_c8_dec_dk4_um_t(&pcval, pc, &ep, 1, NULL)) { do_charge(job, un, cl, pcval); } else { /* Close connection on malformed request */ if ((NULL == job->soa) && (0 == job->szsoa)) { close_stream_conn(job->sock, job->sto, job->connptr, job->pnconn); } } } else { /* Close connection on malformed request */ if ((NULL == job->soa) && (0 == job->szsoa)) { close_stream_conn(job->sock, job->sto, job->connptr, job->pnconn); } } #line 6047 "printqd.ctr" } /** Object for DB traversal in control requests. */ typedef struct { dk4_sto_t *s; /**< Key name storage. */ dk4_sto_it_t *i; /**< Key name storage iterator. */ char *cn; /**< Class name. */ char *un; /**< User name. */ } pqd_control_t; /** Comparison function for storage. @param l Left object. @param r Right object. @param cr Comparison criteria (ignored). @return Comparison result. */ static int db_entry_compare(const void *l, const void *r, int cr) { int back = 0; if (NULL != l) { if (NULL != r) { back = strcmp((const char *)l, (const char *)r); if (-1 > back) back = -1; if ( 1 < back) back = 1; } else { back = 1; } } else { if (NULL != r) { back = -1; } } return back; } /** Traverse simple database containing text. @param obj Object to modify during traversal. @param k Key text. @param v Value text. @return 1 on success, 0 on error (continue traversal), -1 on error (abort). */ static int rq_c_reset_traverse(void *obj, const char *k, const char *v) { pqd_control_t *ctoptr = NULL; /* Traversal object pointer */ char *p1 = NULL; /* DB entry type */ char *p2 = NULL; /* Class name */ char *p3 = NULL; /* User name */ int clm = 0; /* Flag: Class name matches */ int unm = 0; /* Flag: User name matches */ int back = 1; #line 6110 "printqd.ctr" ctoptr = (pqd_control_t *)obj; if (0 != dk4str8_cpy_s(kb, sizeof(kb), k, NULL)) { p1 = dk4str8_start(kb, NULL); if (NULL != p1) { p2 = strchr(p1, ':'); if (NULL != p2) { *(p2++) = '\0'; p2 = dk4str8_start(p2, NULL); } if (NULL != p2) { if (0 == strcmp(p1, printqd_kw[152])) { p3 = strchr(p2, ':'); if (NULL != p3) { *(p3++) = '\0'; p3 = dk4str8_start(p3, NULL); } if (NULL != p3) { if (NULL != ctoptr->cn) { if (0 == strcmp(ctoptr->cn, p2)) { clm = 1; } } else { clm = 1; } if (0 != clm) { if (NULL != ctoptr->un) { if (0 == strcmp(ctoptr->un, p3)) { unm = 1; } } else { unm = 1; } if (0 != unm) { p1 = dk4str8_dup(k, NULL); if (NULL != p1) { if (0 == dk4sto_add(ctoptr->s, p1, NULL)) { dk4mem_free(p1); #line 6147 "printqd.ctr" } } #if TRACE_DEBUG else { #line 6151 "printqd.ctr" } #endif } #if TRACE_DEBUG else { #line 6156 "printqd.ctr" } #endif } #if TRACE_DEBUG else { #line 6161 "printqd.ctr" } #endif } #if TRACE_DEBUG else { #line 6166 "printqd.ctr" } #endif } #if TRACE_DEBUG else { #line 6171 "printqd.ctr" } #endif } #if TRACE_DEBUG else { #line 6176 "printqd.ctr" } #endif } #if TRACE_DEBUG else { #line 6181 "printqd.ctr" } #endif } if (0 == can_continue(0, 0)) { back = -1; } #line 6186 "printqd.ctr" return back; } /** Traverse simple database containing text. @param obj Object to modify during traversal. @param k Key text. @param v Value text. @return 1 on success, 0 on error (continue traversal), -1 on error (abort). */ static int rc_c_dbcl_traverse(void *obj, const char *k, const char *v) { pqd_control_t *pctobj; pqd_class_t *cl; char *p1; /* First argument */ char *p2; /* Second argument */ int cdel = 0; /* Flag: Can delete item */ int back = 1; if (0 != dk4str8_cpy_s(kb, sizeof(kb), k, NULL)) { if (0 != dk4str8_cpy_s(vb, sizeof(vb), k, NULL)) { p1 = strchr(kb, ':'); if (NULL != p1) { *(p1++) = '\0'; p1 = dk4str8_start(p1, NULL); dk4str8_normalize(kb, NULL); if (NULL != p1) { pctobj = (pqd_control_t *)obj; switch ( dk4str8_array_index(db_type_names, kb, 0) ) { case 0 : /* p:class:user */ case 1 : /* a:class:user */ { p2 = strchr(p1, ':'); if (NULL != p2) { *(p2++) = '\0'; p2 = dk4str8_start(p2, NULL); if (NULL != p2) { dk4str8_normalize(p1, NULL); dk4str8_normalize(p2, NULL); cl = dk4sto_it_find_like(conf.i_c, p1, 1); if (NULL != cl) { if (NULL == dk4sto_it_find_like(cl->i_u, p2, 1)) { if (NULL == getpwnam(p2)) { cdel = 1; } } } else { cdel = 1; } if (0 != cdel) { p1 = dk4str8_dup(vb, NULL); if (NULL != p1) { if (0 == dk4sto_add(pctobj->s, p1, NULL)) { dk4mem_free(p1); back = 0; } } else { back = 0; } } } } } break; case 2 : { /* j:printer */ dk4str8_normalize(p1, NULL); if (NULL == get_printer_for_name(p1)) { p1 = dk4str8_dup(vb, NULL); if (NULL != p1) { if (0 == dk4sto_add(pctobj->s, p1, NULL)) { dk4mem_free(p1); back = 0; } } else { back = 0; } } } break; } } } } } if (0 == can_continue(0, 0)) { back = -1; } return back; } /** Process control reset request. @param job Arguments for request. */ static void rq_c_reset(pqd_rq_t *job) { pqd_control_t ctobj; char *pc; char *pn; char *pv; #line 6290 "printqd.ctr" /* Initialize variable */ ctobj.s = NULL; ctobj.i = NULL; ctobj.cn = NULL; ctobj.un = NULL; /* Process command arguments */ pc = job->argptr; while (NULL != pc) { pn = dk4str8_next(pc, NULL); #line 6302 "printqd.ctr" pv = dk4str8_chr(pc, '='); if (NULL != pv) { *(pv++) = '\0'; pv = dk4str8_start(pv, NULL); } #line 6308 "printqd.ctr" if (NULL != pv) { switch ( dk4str8_abbr_index(control_arg_names, '$', pc, 0) ) { case 0 : { ctobj.cn = pv; } break; case 1 : { ctobj.un = pv; } break; default : { #line 6318 "printqd.ctr" } break; } } pc = pn; } #line 6324 "printqd.ctr" if (NULL != ctobj.cn) { if (0 == dk4str8_cmp(printqd_kw[2], ctobj.cn)) { ctobj.cn = NULL; } } if (NULL != ctobj.un) { if (0 == dk4str8_cmp(printqd_kw[2], ctobj.un)) { ctobj.un = NULL; } } ctobj.s = dk4sto_open(NULL); if (NULL != ctobj.s) { #line 6332 "printqd.ctr" dk4sto_set_comp(ctobj.s, db_entry_compare, 0); ctobj.i = dk4sto_it_open(ctobj.s, NULL); if (NULL != ctobj.i) { #line 6335 "printqd.ctr" (void)dk4dbi_c8_traverse(db, (void *)(&ctobj), rq_c_reset_traverse); #line 6337 "printqd.ctr" dk4sto_it_reset(ctobj.i); do { pc = (char *)dk4sto_it_next(ctobj.i); if (NULL != pc) { #line 6341 "printqd.ctr" if (0 != can_continue(0, 0)) { (void)dbi_del(db, pc, NULL); } dk4mem_free(pc); } } while (NULL != pc); dk4sto_it_close(ctobj.i); } #if TRACE_DEBUG else { #line 6351 "printqd.ctr" } #endif dk4sto_close(ctobj.s); } #if TRACE_DEBUG else { #line 6357 "printqd.ctr" } #endif #line 6360 "printqd.ctr" } /** Process control add request. @param job Arguments for request. */ static void rq_c_add(pqd_rq_t *job) { pqd_account_t oldacc; pqd_account_t newacc; pqd_class_t *cl = NULL; const char *ep = NULL; char *clname = NULL; char *uname = NULL; char *ptext = NULL; char *pc; char *pn; char *pv; dk4_um_t pages = (dk4_um_t)0UL; /* Process command arguments */ pc = job->argptr; while (NULL != pc) { pn = dk4str8_next(pc, NULL); pv = dk4str8_chr(pc, '='); if (NULL != pv) { *(pv++) = '\0'; pv = dk4str8_start(pv, NULL); } if (NULL != pv) { switch ( dk4str8_abbr_index(control_arg_names, '$', pc, 0) ) { case 0 : { clname = pv; } break; case 1 : { uname = pv; } break; case 2 : { ptext = pv; } break; } } pc = pn; } if ((NULL != clname) && (NULL != uname) && (NULL != ptext)) { if (0 != dk4ma_input_c8_dec_dk4_um_t(&pages, ptext, &ep, 1, NULL)) { cl = dk4sto_it_find_like(conf.i_c, clname, 1); if (NULL != cl) { if (0 != retrieve_account_for_user_and_class(&oldacc, uname, cl, 1)) { DK4_MEMCPY(&newacc, &oldacc, sizeof(pqd_account_t)); if ((DK4_UM_MAX - pages) >= newacc.account) { newacc.account += pages; } else { newacc.account = DK4_UM_MAX; } log_old_and_new_account(uname, cl, &oldacc, &newacc, pages, 1); if (0 == save_account_for_user_and_class(&oldacc,&newacc,uname,cl)) { /* ERROR: Failed to save new account */ log_5(NULL, 0UL, LOG_EMERG, 1, 156, 157, 158, uname, cl->name); } } else { /* ERROR: Failed to retrieve account data */ log_5(NULL, 0UL, LOG_EMERG, 1, 161, 162, 163, uname, cl->name); } } else { /* ERROR: No such class */ log_3(NULL, 0UL, LOG_EMERG, 1, 164, 165, clname); } } else { /* ERROR: ptext not numeric */ log_3(NULL, 0UL, LOG_EMERG, 1, 166, 167, ptext); } } } /** Process control database-cleanup request. @param job Arguments for request. */ static void rq_c_dbcl(pqd_rq_t *job) { pqd_control_t ctobj; char *ptr; DK4_MEMRES(&ctobj, sizeof(pqd_control_t)); ctobj.s = NULL; ctobj.i = NULL; ctobj.cn = NULL; ctobj.un = NULL; ctobj.s = dk4sto_open(NULL); if (NULL != ctobj.s) { dk4sto_set_comp(ctobj.s, db_entry_compare, 0); ctobj.i = dk4sto_it_open(ctobj.s, NULL); if (NULL != ctobj.i) { (void)dk4dbi_c8_traverse(db, (void *)(&ctobj), rc_c_dbcl_traverse); dk4sto_it_reset(ctobj.i); do { ptr = (char *)dk4sto_it_next(ctobj.i); if (NULL != ptr) { if (0 != can_continue(0, 0)) { dbi_del(db, ptr, NULL); } dk4mem_free(ptr); } } while(NULL != ptr); dk4sto_it_close(ctobj.i); } dk4sto_close(ctobj.s); } } /** Process control request. @param job Data for one request to process. */ static void rq_control(pqd_rq_t *job) { char *subcmd; int sc; #line 6491 "printqd.ctr" subcmd = job->argptr; job->argptr = dk4str8_next(subcmd, NULL); #line 6494 "printqd.ctr" switch ( (sc = dk4str8_abbr_index(control_sub_cmds, '$', subcmd, 0)) ) { case 0 : { #line 6496 "printqd.ctr" rq_c_reset(job); } break; case 1 : { #line 6499 "printqd.ctr" rq_c_add(job); } break; case 2 : { #line 6502 "printqd.ctr" rq_c_dbcl(job); } break; default : { /* ERROR: Illegal sub-command */ log_3(NULL, 0UL, LOG_EMERG, 1, 168, 169, subcmd); } break; } #line 6510 "printqd.ctr" } /** Process contents of the inbuf buffer, send response if necessary. @param job Data for one request to process. */ static void process_data(pqd_rq_t *job) { const char * msgs[3]; #line 6523 "printqd.ctr" job->cmdptr = dk4str8_start(inbuf, NULL); if (NULL != job->cmdptr) { dk4str8_delnl(job->cmdptr); /* LOG request */ if (0 == conf.linf) { if ('i' == (job->cmdptr)[0]) { if ('n' == (job->cmdptr)[1]) { if ('f' == (job->cmdptr)[2]) { if ('o' == (job->cmdptr)[3]) { job->logthis = 0; } } } } } if (0 != job->logthis) { msgs[0] = printqd_kw[87]; msgs[1] = job->cmdptr; msgs[2] = NULL; log_multipart_message(NULL, 0UL, LOG_EMERG, 0, msgs, 2); } /* Process request */ job->argptr = dk4str8_next(job->cmdptr, NULL); job->action = dk4str8_array_index(pqd_command_names, job->cmdptr, 0); if (0 != protocol_level_check(job->action, job->protlev)) { switch (job->action) { case PQD_CMD_INFO : { rq_info(job); } break; case PQD_CMD_JOBSTART : { rq_jobstart(job); } break; case PQD_CMD_FILESTART : { rq_filestart(job); } break; case PQD_CMD_FILEEND : { rq_fileend(job); } break; case PQD_CMD_ACCT_CHECK : { rq_acct_check(job); } break; case PQD_CMD_ACCT_START : { rq_acct_start(job); } break; case PQD_CMD_ACCT_END : { rq_acct_end(job); } break; case PQD_CMD_ACCT_CHARGE : { rq_acct_charge(job); } break; case PQD_CMD_CONTROL : { rq_control(job); } break; } } else { /* Close connection if request is denied. */ if ((NULL == job->soa) && (0 == job->szsoa)) { close_stream_conn(job->sock, job->sto, job->connptr, job->pnconn); } } } #line 6586 "printqd.ctr" } /** Run one pass within inner loop. */ static void one_pass(void) { fd_set rfds; /* Read file desc set */ dk4_sockaddr_storage_t soa_sto; /* Remote address */ pqd_rq_t job; /* Job structure */ struct sockaddr *soa; /* Remote address */ #if VERSION_BEFORE_20160329 struct sockaddr_in *soa4; /* Remote IPv4 address */ #if DK4_HAVE_STRUCT_SOCKADDR_IN6 struct sockaddr_in6 *soa6; /* Remote IPv6 address */ #endif #endif pqd_l_conn_t *pconnloc; /* UNIX connection record */ pqd_n_conn_t *pconntcp; /* TCP connection record */ size_t sz_soa_sto; /* Address size */ size_t rdbytes; /* Number of bytes read */ size_t i; /* Traverse socket set */ dk4_socket_t sock; /* Current new socket */ int maxfd = 0; /* Maximum fd number */ int l_conn = 0; /* Flag: Local connection */ int l_proc = 0; /* Flag: Local processing */ int res = 0; /* Operation result */ int addrok; /* Flag: Address size ok */ int protlev; /* Procotol level for conn */ #line 6620 "printqd.ctr" /* Create file descriptor set for select. */ FD_ZERO(&rfds); /* Check for incoming UNIX conn rq only if maximum not yet reached. */ if ((0 == conf.m_loc) || (con_loc < conf.m_loc)) { FD_SET(so_unix,&rfds); if (maxfd < so_unix) { maxfd = so_unix; } } /* Check for incoming TCP conn rq only if maximum not yet reached. */ if ((NULL != ss_tcp) && ((0 == conf.m_tcp) || (con_tcp < conf.m_tcp))) { for (i = 0; i < ss_tcp->szUsed; i++) { FD_SET((ss_tcp->pSockets)[i],&rfds); if (maxfd < (ss_tcp->pSockets)[i]) { maxfd = (ss_tcp->pSockets)[i]; } } } /* Check for data on existing UNIX connections. */ dk4sto_it_reset(i_c_unix); do { pconnloc = (pqd_l_conn_t *)dk4sto_it_next(i_c_unix); if (NULL != pconnloc) { FD_SET(pconnloc->sock,&rfds); if (maxfd < pconnloc->sock) { maxfd = pconnloc->sock; } } } while (NULL != pconnloc); /* Check for data on existing TCP connections. */ dk4sto_it_reset(i_c_tcp); do { pconntcp = (pqd_n_conn_t *)dk4sto_it_next(i_c_tcp); if (NULL != pconntcp) { FD_SET(pconntcp->sock,&rfds); if (maxfd < pconntcp->sock) { maxfd = pconntcp->sock; } } } while (NULL != pconntcp); /* Check for data on UDP sockets. */ if (NULL != ss_udp) { for (i = 0; i < ss_udp->szUsed; i++) { FD_SET((ss_udp->pSockets)[i],&rfds); if (maxfd < (ss_udp->pSockets)[i]) { maxfd = (ss_udp->pSockets)[i]; } } } /* Check for signal meanwhile. */ if (0 == can_continue(1, 0)) { #line 6673 "printqd.ctr" goto finished; } /* Run select(). */ errno = 0; res = select((1+maxfd), &rfds, NULL, NULL, NULL); if (-1 == res) { switch (errno) { case EINTR: { #line 6683 "printqd.ctr" goto finished; } break; default: { #line 6686 "printqd.ctr" /* ERROR: Serious error from select() function */ log_1(NULL, 0UL, LOG_EMERG, 1, 119); ccouter = -1; ccinner = -1; goto finished; } break; } } if (0 == res) { #line 6695 "printqd.ctr" goto finished; } /* Check for new connection attempts on local socket. */ if ((0 == conf.m_loc) || (con_loc < conf.m_loc)) { if (0 != (FD_ISSET(so_unix,&rfds))) { #line 6702 "printqd.ctr" sock = dk4socket_accept(so_unix, NULL, NULL, NULL); if (INVALID_SOCKET != sock) { pconnloc = dk4mem_new(pqd_l_conn_t,1,NULL); if (NULL != pconnloc) { pconnloc->sock = sock; if (dk4sto_add(s_c_unix, pconnloc, NULL)) { con_loc++; l_conn = 1; } else { dk4mem_free(pconnloc); (void)dk4socket_close(sock, NULL); } } else { (void)dk4socket_close(sock, NULL); /* ERROR: Memory */ log_1(NULL, 0UL, LOG_EMERG, 1, 120); ccouter = -1; ccinner = -1; } } } } /* Process data from local socket connections. */ dk4sto_it_reset(i_c_unix); do { if (0 != can_continue(1, 0)) { pconnloc = (pqd_l_conn_t *)dk4sto_it_next(i_c_unix); if (NULL != pconnloc) { if (0 != (FD_ISSET(pconnloc->sock,&rfds))) { l_proc = 1; #line 6734 "printqd.ctr" rdbytes = sizeof(inbuf); res = dk4socket_recv( pconnloc->sock, inbuf, &rdbytes, 0, 0L, 0L, NULL ); if (0 != can_continue(0, 0)) { if (DK4_SOCKET_RESULT_SUCCESS == res) { if (0 < rdbytes) { if (sizeof(inbuf) > rdbytes) { inbuf[rdbytes] = '\0'; job_init(&job); job.sock = pconnloc->sock; job.protlev = PQD_PROTO_ADMIN; job.connptr = pconnloc; job.sto = s_c_unix; job.pnconn = &con_loc; process_data(&job); } } else { close_stream_conn(pconnloc->sock, s_c_unix, pconnloc, &con_loc); } } else { close_stream_conn(pconnloc->sock, s_c_unix, pconnloc, &con_loc); } } else { pconnloc = NULL; } } } } else { pconnloc = NULL; } } while (NULL != pconnloc); /* Skip TCP and UDP data if activity on higher priorized local sockets. */ if ((0 != l_conn) || (0 != l_proc) || (0 == can_continue(1, 0))) { #line 6771 "printqd.ctr" goto finished; } /* Check for new connection attempts on TCP. */ if ((NULL != ss_tcp) && ((0 == conf.m_tcp) || (con_tcp < conf.m_tcp))) { for (i = 0; ((i < ss_tcp->szUsed) && (0 != can_continue(1, 0))); i++) { if (0 != (FD_ISSET((ss_tcp->pSockets)[i],&rfds))) { #line 6780 "printqd.ctr" DK4_MEMRES(&soa_sto, sizeof(soa_sto)); sz_soa_sto = sizeof(soa_sto); sock = dk4socket_accept( (ss_tcp->pSockets)[i], (struct sockaddr *)(&soa_sto), &sz_soa_sto, NULL ); if (INVALID_SOCKET != sock) { #if VERSION_BEFORE_20160329 #if DK4_HAVE_STRUCT_SOCKADDR_IN6 soa6 = (struct sockaddr_in6 *)(&soa_sto); #endif soa4 = (struct sockaddr_in *)(&soa_sto); #endif soa = (struct sockaddr *)(&soa_sto); addrok = 0; if (AF_INET == soa->sa_family) { if (sizeof(struct sockaddr_in) == sz_soa_sto) { addrok = 1; } } #if DK4_HAVE_STRUCT_SOCKADDR_IN6 if (AF_INET6 == soa->sa_family) { if (sizeof(struct sockaddr_in6) == sz_soa_sto) { addrok = 1; } } #endif if (0 != addrok) { protlev = protocol_level_for_address(soa); if (PQD_PROTO_NONE < protlev) { #line 6810 "printqd.ctr" pconntcp = dk4mem_new(pqd_n_conn_t,1,NULL); if (NULL != pconntcp) { pconntcp->sock = sock; if (0 != dk4sto_add(s_c_tcp, pconntcp, NULL)) { #if VERSION_BEFORE_20160811 DK4_MEMCPY(&(pconntcp->raddr),&soa_sto,sizeof(&soa_sto)); #else DK4_MEMCPY(&(pconntcp->raddr),&soa_sto,sizeof(soa_sto)); #endif pconntcp->pqdpl = protlev; } else { dk4mem_free(pconntcp); (void)dk4socket_close(sock, NULL); /* ERROR: Memory */ log_1(NULL, 0UL, LOG_EMERG, 1, 120); ccouter = -1; ccinner = -1; } } else { (void)dk4socket_close(sock, NULL); /* ERROR: Memory */ log_1(NULL, 0UL, LOG_EMERG, 1, 120); ccouter = -1; ccinner = -1; } } else { #line 6836 "printqd.ctr" (void)dk4socket_close(sock, NULL); } } else { #line 6839 "printqd.ctr" (void)dk4socket_close(sock, NULL); } } } } } if (0 == can_continue(1, 0)) { #line 6847 "printqd.ctr" goto finished; } /* Process data from TCP connections. */ dk4sto_it_reset(i_c_tcp); do { if (0 != can_continue(1, 0)) { pconntcp = (pqd_n_conn_t *)dk4sto_it_next(i_c_tcp); if (NULL != pconntcp) { if (0 != (FD_ISSET(pconntcp->sock,&rfds))) { #line 6859 "printqd.ctr" rdbytes = sizeof(inbuf); res = dk4socket_recv( pconntcp->sock, inbuf, &rdbytes, 0, 0L, 0L, NULL ); if (0 != can_continue(0, 0)) { if (DK4_SOCKET_RESULT_SUCCESS == res) { if (0 < rdbytes) { if (sizeof(inbuf) > rdbytes) { inbuf[rdbytes] = '\0'; job_init(&job); job.sock = pconntcp->sock; job.protlev = pconntcp->pqdpl; job.connptr = pconntcp; job.sto = s_c_tcp; job.pnconn = &con_tcp; process_data(&job); } } else { close_stream_conn(pconntcp->sock, s_c_tcp, pconntcp, &con_tcp); } } else { close_stream_conn(pconntcp->sock, s_c_tcp, pconntcp, &con_tcp); } } else { } } } } else { pconntcp = NULL; } } while (NULL != pconntcp); if (0 == can_continue(1, 0)) { #line 6892 "printqd.ctr" goto finished; } /* Process UDP data. */ if (NULL != ss_udp) { for (i = 0; ((i < ss_udp->szUsed) && (0 != can_continue(1, 0))); i++) { if (0 != (FD_ISSET((ss_udp->pSockets)[i],&rfds))) { #line 6901 "printqd.ctr" rdbytes = sizeof(inbuf); sz_soa_sto = sizeof(soa_sto); res = dk4socket_recvfrom( (ss_udp->pSockets)[i], inbuf, &rdbytes, 0, (struct sockaddr *)(&soa_sto), &sz_soa_sto, 0L, 0L, NULL ); if ((DK4_SOCKET_RESULT_SUCCESS == res) && (0 < rdbytes)) { if ((0 != can_continue(1, 0)) && (sizeof(inbuf) > rdbytes)) { inbuf[rdbytes] = '\0'; #if VERSION_BEFORE_20160329 #if DK4_HAVE_STRUCT_SOCKADDR_IN6 soa6 = (struct sockaddr_in6 *)(&soa_sto); #endif soa4 = (struct sockaddr_in *)(&soa_sto); #endif soa = (struct sockaddr *)(&soa_sto); addrok = 0; if (AF_INET == soa->sa_family) { if (sizeof(struct sockaddr_in) == sz_soa_sto) { addrok = 1; } } #if DK4_HAVE_STRUCT_SOCKADDR_IN6 if (AF_INET6 == soa->sa_family) { if (sizeof(struct sockaddr_in6) == sz_soa_sto) { addrok = 1; } } #endif if (0 != addrok) { protlev = protocol_level_for_address(soa); if (PQD_PROTO_NONE < protlev) { job_init(&job); job.sock = (ss_udp->pSockets)[i]; job.protlev = PQD_PROTO_INFO; job.soa = (struct sockaddr *)(&soa_sto); job.szsoa = sz_soa_sto; process_data(&job); } } } } } } } finished: #line 6949 "printqd.ctr" if (0 == dbi_sync(db, NULL)) { /* ERROR: Failed to synchronize database */ log_1(NULL, 0UL, LOG_EMERG, 1, 121); } if (0 == can_continue(1, 0)) { ccinner = 0; if (0 == can_continue(0, 0)) { ccouter = 0; } } #line 6960 "printqd.ctr" } /** Run two nested loops: The outer loop is only finished by SIGTERM or SIGINT to exit the program, the inner loop is also finished by SIGHUP to re-read the configuration. */ static void service_loops(void) { #line 6974 "printqd.ctr" #line 6975 "printqd.ctr" /* LOG: Daemon running */ log_1(NULL, 0UL, LOG_INFO, 0, 73); if (outer_allocate_resources()) { /* Outer loop is left on SIGTERM or SIGINT. */ while(1 == ccouter) { if (1 == can_continue(0, 0)) { config_init(); if (0 != config_read()) { if (inner_allocate_resources()) { if (0 != change_group_and_user()) { /* Inner loop is left on SIGHUP, SIGTERM or SIGINT. */ ccinner = 1; *sig_pass_pointer(&sig_had_hup) = 0; prev_filelog_failed = 0; /* LOG: Entering service mode */ log_1(NULL, 0UL, LOG_INFO, 0, 75); while(1 == ccinner) { if (1 == can_continue(1, 0)) { #line 6995 "printqd.ctr" one_pass(); } else { #line 6997 "printqd.ctr" ccinner = 0; if (0 == can_continue(0, 0)) { ccouter = 0; /* LOG: Exiting service mode */ log_1(NULL, 0UL, LOG_INFO, 0, 76); } else { /* LOG: Exiting service mode for reconfiguration */ log_1(NULL, 0UL, LOG_INFO, 0, 77); } } } /* LOG: Exited service mode */ log_1(NULL, 0UL, LOG_INFO, 0, 78); } else { #line 7011 "printqd.ctr" ccouter = -1; } } else { #line 7014 "printqd.ctr" ccouter = -1; } if (0 == inner_release_resources()) { #line 7017 "printqd.ctr" ccouter = -1; } } else { #line 7020 "printqd.ctr" ccouter = -1; } config_release(); } else { #line 7024 "printqd.ctr" ccouter = 0; } } } #if TRACE_DEBUG else { #line 7030 "printqd.ctr" } #endif outer_release_resources(); /* LOG: Daemon exiting */ log_1( NULL, 0UL, ((0 == ccouter) ? (LOG_INFO) : (LOG_ERR)), ((0 == ccouter) ? (0) : (1)), ((0 == ccouter) ? (74) : (187)) ); #line 7041 "printqd.ctr" #line 7042 "printqd.ctr" } /** Run service in debug mode or normal mode. */ static void set_signal_handlers_and_run_service(void) { int loop_was_running = 0; #ifdef DK4_HAVE_SIGACTION #ifdef SIGHUP struct sigaction ohup; struct sigaction nhup; #endif #ifdef SIGPIPE struct sigaction opipe; struct sigaction npipe; #endif struct sigaction oint; struct sigaction nint; struct sigaction oterm; struct sigaction nterm; #else #ifdef SIGPIPE dk4_sig_handler_t *opipe = NULL; #endif #ifdef SIGHUP dk4_sig_handler_t *ohup = NULL; #endif dk4_sig_handler_t *oterm = NULL; dk4_sig_handler_t *oint = NULL; #endif #ifdef DK4_HAVE_SIGACTION #ifdef SIGHUP int shup = 0; #endif #ifdef SIGPIPE int spipe = 0; #endif int sint = 0; int sterm = 0; int s_f_i = 0; int s_f_r = 0; #endif /* Set signal handlers */ #if DK4_HAVE_SIGACTION #ifdef SIGPIPE DK4_MEMRES(&npipe, sizeof(npipe)); npipe.sa_handler = sig_handler_pipe; npipe.sa_flags = 0; if (0 != sigemptyset(&npipe.sa_mask)) { s_f_i = 1; goto finished; } if (0 != sigaddset(&npipe.sa_mask, SIGPIPE)) { s_f_i = 1; goto finished; } if (0 != sigaction(SIGPIPE, &npipe, &opipe)) { s_f_i = 1; goto finished; } spipe = 1; #endif #ifdef SIGHUP DK4_MEMRES(&nhup, sizeof(nhup)); nhup.sa_handler = sig_handler_hup; nhup.sa_flags = 0; if (0 != sigemptyset(&nhup.sa_mask)) { s_f_i = 1; goto finished; } if (0 != sigaddset(&nhup.sa_mask, SIGHUP)) { s_f_i = 1; goto finished; } if (0 != sigaction(SIGHUP, &nhup, &ohup)) { s_f_i = 1; goto finished; } shup = 1; #endif DK4_MEMRES(&nterm, sizeof(nterm)); nterm.sa_handler = sig_handler_term; nterm.sa_flags = 0; if (0 != sigemptyset(&nterm.sa_mask)) { s_f_i = 1; goto finished; } if (0 != sigaddset(&nterm.sa_mask, SIGTERM)) { s_f_i = 1; goto finished; } if (0 != sigaction(SIGTERM, &nterm, &oterm)) { s_f_i = 1; goto finished; } sterm = 1; DK4_MEMRES(&nint, sizeof(nint)); nint.sa_handler = sig_handler_int; nint.sa_flags = 0; if (0 != sigemptyset(&nint.sa_mask)) { s_f_i = 1; goto finished; } if (0 != sigaddset(&nint.sa_mask, SIGINT)) { s_f_i = 1; goto finished; } if (0 != sigaction(SIGINT, &nint, &oint)) { s_f_i = 1; goto finished; } sint = 1; #else #ifdef SIGPIPE opipe = sigset(SIGPIPE, sig_handler_pipe); #endif #ifdef SIGHUP ohup = sigset(SIGHUP, sig_handler_hup); #endif oint = sigset(SIGINT, sig_handler_int); oterm = sigset(SIGTERM, sig_handler_term); #endif service_loops(); loop_was_running = 1; finished: /* */ if (0 == loop_was_running) { log_1(NULL, 0UL, LOG_ERR, 1, 72); } /* Restore signal handlers */ #if DK4_HAVE_SIGACTION if (0 != s_f_i) { /* ERROR: Failed to install signal handlers */ log_1(NULL, 0UL, LOG_EMERG, 1, 68); exval = EXIT_FAILURE; } if (0 != sint) { if (0 != sigaction(SIGINT, &oint, NULL)) { s_f_r = 1; } } if (0 != sterm) { if (0 != sigaction(SIGTERM, &oterm, NULL)) { s_f_r = 1; } } #ifdef SIGHUP if (0 != shup) { if (0 != sigaction(SIGHUP, &ohup, NULL)) { s_f_r = 1; } } #endif #ifdef SIGPIPE if (0 != spipe) { if (0 != sigaction(SIGPIPE, &opipe, NULL)) { s_f_r = 1; } } #endif if (0 != s_f_r) { /* ERROR: Failed to restore signal handlers */ log_1(NULL, 0UL, LOG_EMERG, 1, 69); exval = EXIT_FAILURE; } #else if (NULL != oterm) { sigset(SIGTERM, oterm); } if (NULL != oint ) { sigset(SIGINT, oint ); } #ifdef SIGHUP if (NULL != ohup) { sigset(SIGHUP, ohup); } #endif #ifdef SIGPIPE if (NULL != opipe) { sigset(SIGPIPE, opipe); } #endif #endif } /** Program entry point. @param argc @param argv @return 0 on success, any other value indicates an error. */ int main(int argc, char *argv[]) { pid_t cpid; /* Child process PID */ int res; /* Operation result */ /* Process command line arguments. */ res = dk4opt_process_argv( options, szoptions, argc, argv, NULL, NULL, 1, 1, NULL ); if (0 == res) { exval = 2; /* Invalid or excess arguments */ goto finished; } /* Must be started as root. */ if (0 != geteuid()) { fputs("printqd: ERROR: Must be run as root!\n", stderr); fflush(stderr); goto finished; } /* Check used command line arguments. */ if (0 != options[0].found) { debug = 1; } /* Run in debug mode. */ if (0 != debug) { set_signal_handlers_and_run_service(); goto finished; } /* PREPARE TO RUN AS DAEMON */ if (0 == dk4dmt_parent_before_fork(printqd_kw[0],pid_file_name,1,syslogf)) { goto finished; } /* Create first background process */ cpid = fork(); if ((pid_t)0 < cpid) { /* In the parent process */ goto finished; } else { if ((pid_t)0 == cpid) { /* In the child process, continue below */ } else { /* Failed to create process */ /* ERROR: fork() failed */ fputs(printqd_kw[0], stderr); fputs(printqd_kw[70], stderr); fflush(stderr); goto finished; } } /* Intermediate process and daemon process should indicate success. */ exval = EXIT_SUCCESS; /* Decouple from terminals. */ if (0 == dk4dmt_intermediate_before_fork(printqd_kw[0], syslogf)) { goto finished; } /* Create daemon background process from within first background process */ cpid = fork(); if ((pid_t)0 < cpid) { /* In the intermediate process */ goto finished; } else { if ((pid_t)0 == cpid) { /* In the daemon process, continue below */ } else { /* Failed to create process */ /* ERROR: fork() failed */ log_1(NULL, 0UL, LOG_ERR, 1, 71); goto finished; } } /* In the daemon process */ if (0 != dk4dmt_daemon_after_fork(printqd_kw[0], pid_file_name, syslogf)) { set_signal_handlers_and_run_service(); } dk4dmt_daemon_end(printqd_kw[0], pid_file_name, syslogf); /* Exit the program. */ finished: exit(exval); return exval; } #else /** Program entry point. @param argc @param argv @return 0 on success, any other value indicates an error. */ int main(int argc, char *argv[]) { fputs("printqd: ERROR: Build requirements violation!\n", stderr); #if DK4_CHAR_SIZE > 1 fputs("Default character size is larger than 1!\n", stderr); #endif #if !((DK4_HAVE_SIGACTION) || (DK4_HAVE_SIGSET)) fputs("Neither sigaction() nor sigset() are available!\n", stderr); #endif #if !(DK4_HAVE_PWD_H) fputs("Include file \"pwd.h\" not found!\n", stderr); #endif #if !(DK4_HAVE_UID_T) fputs("Data type uid_t not available!\n", stderr); #endif #if !(DK4_HAVE_GRP_H) fputs("Include file \"grp.h\" not found!\n", stderr); #endif #if !(DK4_HAVE_GID_T) fputs("Data type gid_t not available!\n", stderr); #endif #if !(DK4_HAVE_MODE_T) fputs("Data type mode_t not available!\n", stderr); #endif #if !(DK4_HAVE_GETPWNAM) fputs("Function getpwnam() is not available!\n", stderr); #endif #if !(DK4_HAVE_GETGRNAM) fputs("Function getgrnam() is not available!\n", stderr); #endif #if !((DK4_HAVE_SETSID) || (DK4_HAVE_SETPGRP)) fputs("Neither setsid() nor setpgrp() are available!\n", stderr); #endif #if DK4_ON_WINDOWS fputs("On Windows platform!\n", stderr); #endif fflush(stderr); exit(EXIT_FAILURE); return EXIT_FAILURE; } #endif