/* Copyright (C) 2016-2020, Dirk Krause SPDX-License-Identifier: BSD-3-Clause */ /* WARNING: This file was generated by the dkct program (see http://dktools.sourceforge.net/ for details). 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 */ #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 #if DK4_HAVE_SYSEXITS_H #ifndef SYSEXITS_H_INCLUDED #include #define SYSEXITS_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" #include "dk4unused.h" #line 327 "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_RUNSTATE "/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_SYSTEMD_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 1021 "printqd.ctr" }; /** Choices for deny action. */ static const char * const deny_action_names[] = { /* 0 */ "remove", /* 1 */ "hold", NULL #line 1032 "printqd.ctr" }; /** Section names in configuration files. */ static const char * const config_section_names[] = { /* 0 */ "options", /* 1 */ "class", /* 2 */ "printer", NULL #line 1044 "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 1109 "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 1130 "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 1142 "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 1154 "printqd.ctr" }; /** Log feature names. */ static const char * const log_feature_names[] = { /* 0 */ "db", /* 1 */ "info", /* 2 */ "all", /* 3 */ "*", /* 4 */ "none", /* 5 */ "-", NULL #line 1169 "printqd.ctr" }; static const char * const db_type_names[] = { /* 0 */ "p", /* 1 */ "a", /* 2 */ "j", NULL #line 1179 "printqd.ctr" }; /** Daemon configuration. */ static pqd_conf_t conf; /** Daemon tool function structure. */ static dk4dmt_t dmt; /** 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 DK4_ARG_UNUSED(signo) ) { DK4_UNUSED_ARG(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 DK4_ARG_UNUSED(signo) ) { DK4_UNUSED_ARG(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 DK4_ARG_UNUSED(signo) ) { DK4_UNUSED_ARG(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 DK4_ARG_UNUSED(signo) ) { DK4_UNUSED_ARG(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 1467 "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 1482 "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 1515 "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 1539 "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 1570 "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 1723 "printqd.ctr" } static void log_1( const char *sourcefile, unsigned long sourceline, int sll, int error, size_t i1 ) { const char *msgs[2]; #line 1739 "printqd.ctr" msgs[0] = printqd_kw[i1]; msgs[1] = NULL; log_multipart_message(sourcefile, sourceline, sll, error, msgs, 1); #line 1743 "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 1761 "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 1767 "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 1787 "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 1795 "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 DK4_ARG_UNUSED(cr) ) { const pqd_l_conn_t *pl; const pqd_l_conn_t *pr; int back = 0; #line 2072 "printqd.ctr" DK4_UNUSED_ARG(cr) 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 2091 "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 DK4_ARG_UNUSED(cr) ) { const pqd_n_conn_t *pl; const pqd_n_conn_t *pr; int back = 0; #line 2110 "printqd.ctr" DK4_UNUSED_ARG(cr) 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 2129 "printqd.ctr" return back; } /** Delete a limit structure (release memory). @param ptr Limit to delete. */ static void limit_delete(pqd_limit_t *ptr) { #line 2142 "printqd.ctr" if (NULL != ptr) { #line 2143 "printqd.ctr" dk4mem_release(ptr->name); ptr->limit = (dk4_um_t)0UL; dk4mem_free(ptr); } #line 2148 "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 2163 "printqd.ctr" if (NULL != name) { #line 2164 "printqd.ctr" back = dk4mem_new(pqd_limit_t,1,NULL); if (NULL != back) { #line 2166 "printqd.ctr" back->limit = max; back->name = dk4str8_dup(name, NULL); if (NULL == back->name) { #line 2169 "printqd.ctr" limit_delete(back); back = NULL; } } #if TRACE_DEBUG else { #line 2175 "printqd.ctr" } #endif } #line 2178 "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 2196 "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 2225 "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 2240 "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 2249 "printqd.ctr" } /** Delete a class structure (release memory). @param ptr Class to delete. */ static void class_delete(pqd_class_t *ptr) { #line 2261 "printqd.ctr" if (NULL != ptr) { #line 2262 "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 2281 "printqd.ctr" } #endif #line 2284 "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 2297 "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 2306 "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 2321 "printqd.ctr" if (NULL != n) { #line 2322 "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 2344 "printqd.ctr" } #if TRACE_DEBUG else { #line 2347 "printqd.ctr" } #endif } #if TRACE_DEBUG else { #line 2352 "printqd.ctr" } #endif } #if TRACE_DEBUG else { #line 2357 "printqd.ctr" } #endif } #if TRACE_DEBUG else { #line 2362 "printqd.ctr" } #endif } #if TRACE_DEBUG else { #line 2367 "printqd.ctr" } #endif if (0 == ok) { #line 2370 "printqd.ctr" class_delete(back); back = NULL; } } #if TRACE_DEBUG else { #line 2376 "printqd.ctr" } #endif } #if TRACE_DEBUG else { #line 2381 "printqd.ctr" } #endif #line 2384 "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 2403 "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 2431 "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 2444 "printqd.ctr" if (NULL != ptr) { #line 2445 "printqd.ctr" dk4mem_release(ptr->name); ptr->cl = NULL; dk4mem_free(ptr); } #line 2450 "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 2464 "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 2470 "printqd.ctr" printer_delete(back); back = NULL; } } #if TRACE_DEBUG else { #line 2476 "printqd.ctr" } #endif } #if TRACE_DEBUG else { #line 2481 "printqd.ctr" } #endif #line 2484 "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 2503 "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 2531 "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 2545 "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 2554 "printqd.ctr" } /** Delete printer alias structure (release memory). @param ptr Structure to delete. */ static void printer_alias_delete(pqd_printer_alias_t *ptr) { #line 2566 "printqd.ctr" if (NULL != ptr) { #line 2567 "printqd.ctr" dk4mem_release(ptr->name); ptr->pr = NULL; dk4mem_free(ptr); } #line 2572 "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 2587 "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 2598 "printqd.ctr" } #endif } #if TRACE_DEBUG else { #line 2603 "printqd.ctr" } #endif } #if TRACE_DEBUG else { #line 2608 "printqd.ctr" } #endif #line 2611 "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 2630 "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 2658 "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 2672 "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 2681 "printqd.ctr" } /** Initialize configuration before reading configuration file. */ static void config_init(void) { #line 2692 "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 2724 "printqd.ctr" } /** Allocate internal structures for configuration. @return 1 on success, 0 on error. */ static int config_allocate(void) { int back = 0; #line 2737 "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 2763 "printqd.ctr" } #endif } #if TRACE_DEBUG else { #line 2768 "printqd.ctr" } #endif } #if TRACE_DEBUG else { #line 2773 "printqd.ctr" } #endif } #if TRACE_DEBUG else { #line 2778 "printqd.ctr" } #endif #line 2781 "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 2802 "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 2808 "printqd.ctr" /* ERROR: Must be positive */ log_1(fn, lineno, LOG_EMERG, 1, 15); } } else { #line 2812 "printqd.ctr" /* ERROR: Not an integer number */ log_5(fn, lineno, LOG_EMERG, 1, 12, 13, 14, pv, ep); } #line 2815 "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 2841 "printqd.ctr" res = dk4ma_input_c8_dec_size_t(&sz, pv, &ep, 1, NULL); if (0 != res) { *pmaxconn = sz; back = 1; } else { #line 2846 "printqd.ctr" /* ERROR: Not a size specification */ log_5(fn, lineno, LOG_EMERG, 1, 16, 17, 18, pv, ep); } #line 2850 "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 2874 "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 2880 "printqd.ctr" /* ERROR: Port number must not be 0 */ log_1(fn, lineno, LOG_EMERG, 1, 22); } } else { #line 2884 "printqd.ctr" /* ERROR: Not a 16 bit unsigned number */ log_5(fn, lineno, LOG_EMERG, 1, 19, 20, 21, pv, ep); } #line 2888 "printqd.ctr" return back; } /** Add address to list of allowed hosts. @param s Containter of allowed peers. @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, 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 2915 "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 2930 "printqd.ctr" dk4mem_free(pap); /* ERROR: Memory */ log_1(filename, lineno, LOG_EMERG, 1, 27); } } else { #line 2935 "printqd.ctr" /* ERROR: Memory */ log_1(filename, lineno, LOG_EMERG, 1, 27); } } else { #line 2939 "printqd.ctr" /* ERROR: Syntax, not a peer definition */ log_3(filename, lineno, LOG_EMERG, 1, 25, 26, str); } } } else { #line 2944 "printqd.ctr" /* ERROR: Unexpected text */ log_3(filename, lineno, LOG_EMERG, 1, 23, 24, px); } #line 2948 "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 2967 "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 2980 "printqd.ctr" /* ERROR: Syntax, not an unsigned number */ log_5(fn, lineno, LOG_EMERG, 1, 28, 29, 30, src, ep); } } } #line 2986 "printqd.ctr" return back; } /** Add a user or group limit to a class. @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( 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 3015 "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 3027 "printqd.ctr" /* ERROR: Memory */ log_1(fn, lineno, LOG_EMERG, 1, 27); limit_delete(plim); } } else { #line 3032 "printqd.ctr" /* ERROR: Memory */ log_1(fn, lineno, LOG_EMERG, 1, 27); } } else { #line 3036 "printqd.ctr" /* ERROR: Limit redefinition */ log_3(fn, lineno, LOG_EMERG, 1, 32, 33, str); } } } else { #line 3041 "printqd.ctr" /* ERROR: Syntax, no further text expected */ log_3(fn, lineno, LOG_EMERG, 1, 23, 24, px); } } else { #line 3045 "printqd.ctr" /* ERROR: Missing limit. */ log_1(fn, lineno, LOG_EMERG, 1, 31); } #line 3049 "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 3072 "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 3080 "printqd.ctr" /* ERROR: Syntax, default limit redefined */ log_1(fn, lineno, LOG_EMERG, 1, 34); } } } else { #line 3085 "printqd.ctr" /* ERROR: No further text expected */ log_3(fn, lineno, LOG_EMERG, 1, 23, 24, px); } #line 3089 "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 3112 "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 3121 "printqd.ctr" /* ERROR: Redefinition of deny action */ log_1(fn, lineno, LOG_EMERG, 1, 35); } } break; default: { } break; } } else { #line 3129 "printqd.ctr" /* ERROR: Syntax, no further text expected */ log_3(fn, lineno, LOG_EMERG, 1, 23, 24, px); } #line 3133 "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 3152 "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 3163 "printqd.ctr" /* ERROR: Memory */ log_1(fn, lineno, LOG_EMERG, 1, 27); printer_alias_delete(ppa); } } else { #line 3168 "printqd.ctr" /* ERROR: Memory */ log_1(fn, lineno, LOG_EMERG, 1, 27); } } else { #line 3172 "printqd.ctr" /* ERROR: Printer exists */ log_3(fn, lineno, LOG_EMERG, 1, 36, 37, pv); } } else { #line 3176 "printqd.ctr" /* ERROR: Alias already exists */ log_3(fn, lineno, LOG_EMERG, 1, 38, 39, pv); } } else { #line 3180 "printqd.ctr" /* ERROR: Syntax, unexpected text */ log_3(fn, lineno, LOG_EMERG, 1, 23, 24, px); } #line 3184 "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 3202 "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 3210 "printqd.ctr" /* ERROR: Syntax, class not found */ log_3(fn, lineno, LOG_EMERG, 1, 40, 41, pv); } } else { #line 3214 "printqd.ctr" /* ERROR: Syntax, redefinition of printer class */ log_1(fn, lineno, LOG_EMERG, 1, 42); } } else { #line 3218 "printqd.ctr" /* ERROR: Syntax, unexpected text */ log_3(fn, lineno, LOG_EMERG, 1, 23, 24, px); } #line 3222 "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 3239 "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 3247 "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 3261 "printqd.ctr" /* WARNING: Default limit missing for class */ log_3(filename, lineno, LOG_EMERG, 0, 93, 94, cl->name); } } } while (NULL != cl); #line 3268 "printqd.ctr" return back; } /** Set additional features to log. @param pv Text containing the feature names. @return 1 on success, 0 on errors. */ static int set_log_features(char *pv) { 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 3348 "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 3358 "printqd.ctr" pk = dk4str8_start(inbuf, NULL); if (NULL != pk) { if ('#' != *pk) { if ('[' == *pk) { #line 3362 "printqd.ctr" /* Opening a new section. */ pk = dk4str8_start(++pk, NULL); if (NULL != pk) { #line 3367 "printqd.ctr" sectt = -1; pcl = NULL; ppr = NULL; pv = dk4str8_chr(pk, ']'); if (NULL != pv) { *pv = '\0'; } #line 3372 "printqd.ctr" pv = dk4str8_next(pk, NULL); switch ( dk4str8_array_index(config_section_names, pk, 0) ) { /* Opening options section. */ case 0 : { #line 3377 "printqd.ctr" sectt = 0; } break; /* Opening class section. */ case 1 : { #line 3382 "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 3396 "printqd.ctr" back = 0; } } else { #line 3399 "printqd.ctr" /* ERROR: MEMORY */ log_1(fn, lineno, LOG_EMERG, 1, 27); back = 0; } } else { #line 3404 "printqd.ctr" /* ERROR: Syntax, class already exists */ log_3(fn, lineno, LOG_EMERG, 1, 43, 44, pv); back = 0; } } else { #line 3409 "printqd.ctr" /* ERROR: Syntax, only one component allowed */ log_3(fn, lineno, LOG_EMERG, 1, 23, 24, px); back = 0; } } else { #line 3414 "printqd.ctr" /* ERROR: Syntax, missing class name */ log_1(fn, lineno, LOG_EMERG, 1, 45); back = 0; } } break; /* Opening printer section. */ case 2 : { #line 3422 "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 3440 "printqd.ctr" } } else { #line 3442 "printqd.ctr" /* ERROR: Memory */ log_1(fn, lineno, LOG_EMERG, 1, 27); back = 0; } } else { #line 3447 "printqd.ctr" /* ERROR: Syntax, pr/al already exists */ log_3(fn, lineno, LOG_EMERG, 1, 46, 47, pv); back = 0; } } else { #line 3452 "printqd.ctr" /* ERROR: Syntax, just one component allowed */ log_3(fn, lineno, LOG_EMERG, 1, 23, 24, px); back = 0; } } else { #line 3457 "printqd.ctr" /* ERROR: Syntax, name required */ log_1(fn, lineno, LOG_EMERG, 1, 48); back = 0; } } break; default : { #line 3463 "printqd.ctr" /* ERROR: Syntax, illegal section name */ log_3(fn, lineno, LOG_EMERG, 1, 49, 50, pk); back = 0; } break; } } else { #line 3469 "printqd.ctr" /* ERROR: Syntax, empty section */ log_1(fn, lineno, LOG_EMERG, 1, 51); back = 0; } } else { #line 3474 "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 3483 "printqd.ctr" switch ( dk4str8_array_index(config_option_names, pk, 0) ) { case 0 : { #line 3486 "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 3497 "printqd.ctr" } } else { #line 3499 "printqd.ctr" /* ERROR: User not found */ log_3(fn, lineno, LOG_EMERG, 1, 53, 54, pv); back = 0; } } else { #line 3504 "printqd.ctr" /* ERROR: Syntax, just one component allowed */ log_3(fn, lineno, LOG_EMERG, 1, 23, 24, px); back = 0; } } else { #line 3509 "printqd.ctr" /* ERROR: Only allwowed in options section */ log_1(fn, lineno, LOG_EMERG, 1, 55); back = 0; } } break; case 1 : { #line 3515 "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 3526 "printqd.ctr" } } else { #line 3528 "printqd.ctr" /* ERROR: Syntax, group not found */ log_3(fn, lineno, LOG_EMERG, 1, 57, 58, pv); back = 0; } } else { #line 3533 "printqd.ctr" /* ERROR: Syntax, just one component allowed */ log_3(fn, lineno, LOG_EMERG, 1, 23, 24, px); back = 0; } } else { #line 3538 "printqd.ctr" /* ERROR: Syntax, only allowed in options */ log_1(fn, lineno, LOG_EMERG, 1, 55); back = 0; } } break; case 2 : { #line 3544 "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 3551 "printqd.ctr" } } else { /* ERROR: Redefinition */ log_1(fn, lineno, LOG_EMERG, 1, 59); back = 0; #line 3556 "printqd.ctr" } } else { #line 3558 "printqd.ctr" /* ERROR: Syntax, only allowed in options */ log_1(fn, lineno, LOG_EMERG, 1, 55); back = 0; } } break; case 3 : { #line 3564 "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 3571 "printqd.ctr" } } else { #line 3573 "printqd.ctr" /* ERROR: Redefinition */ log_1(fn, lineno, LOG_EMERG, 1, 60); back = 0; } } else { #line 3578 "printqd.ctr" /* ERROR: Syntax, only allowed in options */ log_1(fn, lineno, LOG_EMERG, 1, 55); back = 0; } } break; case 4 : { #line 3584 "printqd.ctr" if (0 == sectt) { if (0 == set_backlog(&(conf.slbl), 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 5 : { #line 3595 "printqd.ctr" if (0 == sectt) { if(0 == set_max_connections(&(conf.m_loc),pv,fn,lineno)) { back = 0; #line 3599 "printqd.ctr" } } else { #line 3601 "printqd.ctr" /* ERROR: Syntax, only allowed in options */ log_1(fn, lineno, LOG_EMERG, 1, 55); back = 0; } } break; case 6 : { #line 3607 "printqd.ctr" if (0 == sectt) { if (0 == set_port_number(&(conf.pudp),pv,fn,lineno)) { back = 0; #line 3610 "printqd.ctr" } } else { #line 3612 "printqd.ctr" /* ERROR: Syntax, only allowed in options */ log_1(fn, lineno, LOG_EMERG, 1, 55); back = 0; } } break; case 7 : { #line 3618 "printqd.ctr" if (0 == sectt) { if (0 == set_port_number(&(conf.ptcp),pv,fn,lineno)) { back = 0; #line 3621 "printqd.ctr" } } else { #line 3623 "printqd.ctr" /* ERROR: Syntax, only allowed in options */ log_1(fn, lineno, LOG_EMERG, 1, 55); back = 0; } } break; case 8 : { #line 3629 "printqd.ctr" if (0 == sectt) { if (0 == set_backlog(&(conf.snbl), 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 9 : { #line 3640 "printqd.ctr" if (0 == sectt) { if(0 == set_max_connections(&(conf.m_tcp),pv,fn,lineno)) { back = 0; #line 3644 "printqd.ctr" } } else { #line 3646 "printqd.ctr" /* ERROR: Syntax, only allowed in options */ log_1(fn, lineno, LOG_EMERG, 1, 55); back = 0; } } break; case 10 : { #line 3652 "printqd.ctr" if (0 == sectt) { myres = allow_hosts( conf.s_ai, &(conf.iglo), pv, fn, lineno ); if (0 == myres) { #line 3658 "printqd.ctr" back = 0; } } else { #line 3661 "printqd.ctr" /* ERROR: Syntax, only allowed in options */ log_1(fn, lineno, LOG_EMERG, 1, 55); back = 0; } } break; case 11 : { #line 3667 "printqd.ctr" if (0 == sectt) { myres = allow_hosts( conf.s_ad, &(conf.dglo), pv, fn, lineno ); if (0 == myres) { #line 3673 "printqd.ctr" back = 0; } } else { #line 3676 "printqd.ctr" /* ERROR: Syntax, only allowed in options */ log_1(fn, lineno, LOG_EMERG, 1, 55); back = 0; } } break; case 12 : { #line 3682 "printqd.ctr" if (0 == sectt) { myres = allow_hosts( conf.s_aa, &(conf.aglo), pv, fn, lineno ); if (0 == myres) { #line 3688 "printqd.ctr" back = 0; } } else { #line 3691 "printqd.ctr" /* ERROR: Syntax, only allowed in options */ log_1(fn, lineno, LOG_EMERG, 1, 55); back = 0; } } break; case 13 : { #line 3697 "printqd.ctr" if ((1 == sectt) && (NULL != pcl)) { myres = add_limit( pcl->s_u, pcl->i_u, pv, fn, lineno ); if (0 == myres) { #line 3702 "printqd.ctr" back = 0; } } else { #line 3705 "printqd.ctr" /* ERROR: Syntax, only allowed in class */ log_1(fn, lineno, LOG_EMERG, 1, 61); back = 0; } } break; case 14 : { #line 3711 "printqd.ctr" if ((1 == sectt) && (NULL != pcl)) { myres = add_limit( pcl->s_g, pcl->i_g, 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 15 : { #line 3725 "printqd.ctr" if ((1 == sectt) && (NULL != pcl)) { myres = set_default_limit(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 16 : { #line 3737 "printqd.ctr" if ((1 == sectt) && (NULL != pcl)) { myres = set_deny_action(pcl, pv, fn, lineno); if (0 == myres) { #line 3740 "printqd.ctr" back = 0; } } else { #line 3743 "printqd.ctr" /* ERROR: Syntax, only allowed in class */ log_1(fn, lineno, LOG_EMERG, 1, 61); back = 0; } } break; case 17 : { #line 3749 "printqd.ctr" if ((2 == sectt) && (NULL != ppr)) { myres = add_alias(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 18 : { #line 3761 "printqd.ctr" if ((2 == sectt) && (NULL != ppr)) { myres = assign_class(ppr, pv, fn, lineno); if (0 == myres) { #line 3764 "printqd.ctr" back = 0; } } else { #line 3767 "printqd.ctr" /* ERROR: Syntax, only allowed in printer */ log_1(fn, lineno, LOG_EMERG, 1, 62); back = 0; } } break; case 19 : { #line 3773 "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 3780 "printqd.ctr" } } else { #line 3782 "printqd.ctr" /* ERROR: Redefinition */ log_1(fn, lineno, LOG_EMERG, 1, 63); back = 0; } } else { #line 3787 "printqd.ctr" /* ERROR: Only in options */ log_1(fn, lineno, LOG_EMERG, 1, 55); back = 0; } } break; case 20 : { #line 3793 "printqd.ctr" back = set_log_features(pv); } break; case 21 : { #line 3796 "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 3807 "printqd.ctr" } } else { #line 3809 "printqd.ctr" /* ERROR: User not found */ log_3(fn, lineno, LOG_EMERG, 1, 53, 54, pv); back = 0; } } else { #line 3814 "printqd.ctr" /* ERROR: Syntax, just one component allowed */ log_3(fn, lineno, LOG_EMERG, 1, 23, 24, px); back = 0; } } else { #line 3819 "printqd.ctr" /* ERROR: Only allwowed in options section */ log_1(fn, lineno, LOG_EMERG, 1, 55); back = 0; } } break; case 22 : { #line 3825 "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 3836 "printqd.ctr" } } else { #line 3838 "printqd.ctr" /* ERROR: Syntax, group not found */ log_3(fn, lineno, LOG_EMERG, 1, 57, 58, pv); back = 0; } } else { #line 3843 "printqd.ctr" /* ERROR: Syntax, just one component allowed */ log_3(fn, lineno, LOG_EMERG, 1, 23, 24, px); back = 0; } } else { #line 3848 "printqd.ctr" /* ERROR: Syntax, only allowed in options */ log_1(fn, lineno, LOG_EMERG, 1, 55); back = 0; } } break; } } else { #line 3855 "printqd.ctr" /* ERROR: Syntax, missing value */ log_1(fn, lineno, LOG_EMERG, 1, 64); back = 0; } } else { #line 3860 "printqd.ctr" /* ERROR: Syntax, missing value */ log_1(fn, lineno, LOG_EMERG, 1, 64); back = 0; } } } #if TRACE_DEBUG else { #line 3868 "printqd.ctr" } #endif } #if TRACE_DEBUG else { #line 3873 "printqd.ctr" } #endif } fclose(fipo); if (1 == back) { back = config_check(fn, lineno); } } else { #line 3881 "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 3889 "printqd.ctr" return back; } static void release_allowed_peers(dk4_sto_it_t *it) { dk4_allowed_peer_t *peer; #line 3900 "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 3909 "printqd.ctr" } /** Release resources used to save configuration data. */ static void config_release(void) { #line 3920 "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 3971 "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 3984 "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 3996 "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 4003 "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 4009 "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 4016 "printqd.ctr" /* ERROR: Memory */ log_1(NULL, 0UL, LOG_EMERG, 1, 27); goto finished; } /* Indicate success. */ back = 1; finished: #line 4027 "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 4041 "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 4081 "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 4139 "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 4150 "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 4166 "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 4190 "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 4200 "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 4215 "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 4254 "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 4263 "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 4304 "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 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; 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 4351 "printqd.ctr" dk4error_init(&er); db = dk4dbi_open(fn, 1, 0, 1024, 1024, &er); if (NULL != db) { #line 4354 "printqd.ctr" db_modified = 0; } else { #line 4356 "printqd.ctr" /* ERROR: Failed to open database */ pqd_dbi_open_error(fn, &er); goto finished; } } else { #line 4361 "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 4392 "printqd.ctr" /* ERROR: Failed to open database */ pqd_dbi_open_error(fn, &er); goto finished; } /* Finally indicate success. */ back = 1; finished: #line 4403 "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 4420 "printqd.ctr" /* Database */ if (NULL != db) { if (0 == dk4dbi_close(db, NULL)) { #line 4425 "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 4436 "printqd.ctr" dk4socket_set_close(ss_udp, NULL); } ss_udp = NULL; /* TCP listener socket set. */ if (NULL != ss_tcp) { #line 4443 "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 4456 "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; #if (!(DK4_HAVE_SETGROUPS)) && DK4_HAVE_INITGROUPS && DK4_HAVE_GETPWUID struct pwent *pw; #endif uid_t myuid; gid_t mygid; int dbt = DK4_DB_BE_UNKNOWN; int back = 1; #line 4477 "printqd.ctr" if (0 != user_switched) { #line 4478 "printqd.ctr" if (conf.uid != prev_uid) { back = 0; #line 4480 "printqd.ctr" /* ERROR: User to run as was changed */ log_1(NULL, 0UL, LOG_EMERG, 1, 66); } else { if (conf.gid != prev_gid) { #line 4484 "printqd.ctr" back = 0; /* ERROR: Group to run as was changed */ log_1(NULL, 0UL, LOG_EMERG, 1, 67); } } } else { #line 4490 "printqd.ctr" user_switched = 1; myuid = geteuid(); mygid = getegid(); if ((myuid != conf.uid) || (mygid != conf.gid)) { #line 4494 "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 4514 "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 4519 "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 4527 "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 4533 "printqd.ctr" if (0 == dk4dbi_close(db, NULL)) { #line 4534 "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 4557 "printqd.ctr" #line 4558 "printqd.ctr" if (0 != fchown(so_unix, conf.uid, conf.gid)) { back = 0; #line 4560 "printqd.ctr" /* ERROR: Failed to change socket ownership */ log_1(NULL, 0UL, LOG_EMERG, 1, 112); } #line 4564 "printqd.ctr" if (0 != fchmod(so_unix, 0660)) { back = 0; #line 4566 "printqd.ctr" /* ERROR: Failed to change socket permissions */ log_1(NULL, 0UL, LOG_EMERG, 1, 113); } } else { #line 4570 "printqd.ctr" } #if DK4_HAVE_SETGROUPS if (0 != setgroups(1, &(conf.gid))) { back = 0; #line 4574 "printqd.ctr" log_1(NULL, 0UL, LOG_EMERG, 1, 114); } #else #if DK4_HAVE_INITGROUPS && DK4_HAVE_GETPWUID pw = getpwuid(myuid); if (NULL != pw) { if (NULL != pw->pw_name) { if (0 != initgroups(pw->pw_name, conf.gid)) { back = 0; #line 4583 "printqd.ctr" log_1(NULL, 0UL, LOG_EMERG, 1, 114); } } } #endif #endif /* Switch group */ if (mygid != conf.gid) { if (0 != setgid(conf.gid)) { back = 0; #line 4595 "printqd.ctr" /* ERROR: Failed to switch group */ log_1(NULL, 0UL, LOG_EMERG, 1, 114); } } /* Switch user */ if (myuid != conf.uid) { if (0 != setuid(conf.uid)) { back = 0; #line 4605 "printqd.ctr" /* ERROR: Failed to switch user */ log_1(NULL, 0UL, LOG_EMERG, 1, 115); } } /* Re-open database if closed. */ if (NULL == db) { #line 4613 "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 4619 "printqd.ctr" back = 0; /* ERROR: Failed to open database */ log_3(NULL, 0UL, LOG_EMERG, 1, 105, 106, fn); } } } else { #line 4625 "printqd.ctr" } } #line 4628 "printqd.ctr" return back; } static int protocol_level_for_address(struct sockaddr *so) { int back = PQD_PROTO_NONE; #line 4639 "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 4663 "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 4679 "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 4691 "printqd.ctr" return back; } static void job_init(pqd_rq_t *ptr) { #line 4701 "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 4714 "printqd.ctr" } static void account_init(pqd_account_t *ptr) { #line 4723 "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 4729 "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 4749 "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 4764 "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 4781 "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 4792 "printqd.ctr" (void)dk4socket_sendto( job->sock, inbuf, &wr, 0, job->soa, job->szsoa, 0L, 0L, NULL ); } else { #line 4796 "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 4801 "printqd.ctr" res = DK4_SOCKET_RESULT_FAILED; } } break; } if (DK4_SOCKET_RESULT_FAILED == res) { #line 4806 "printqd.ctr" close_stream_conn(job->sock, job->sto, job->connptr, job->pnconn); } } } else { #line 4810 "printqd.ctr" /* ERROR: Response text too long (BUG)! */ log_1(NULL, 0UL, LOG_EMERG, 1, 116); } } else { #line 4814 "printqd.ctr" /* ERROR: Response text too long (BUG)! */ log_1(NULL, 0UL, LOG_EMERG, 1, 116); } #line 4818 "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 4841 "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 4909 "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 4924 "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 4932 "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 4956 "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 4964 "printqd.ctr" if (0 != dbi_set(db, kb, vb, NULL)) { #line 4965 "printqd.ctr" back = 1; } else { #line 4968 "printqd.ctr" /* ERROR: Failed to set DB entry */ log_1(NULL, 0UL, LOG_EMERG, 1, 117); } } #if TRACE_DEBUG else { #line 4974 "printqd.ctr" } #endif } else { strok = 1; #line 4979 "printqd.ctr" if (0 != dbi_del(db, kb, NULL)) { #line 4980 "printqd.ctr" back = 1; } else { #line 4982 "printqd.ctr" /* ERROR: Failed to delete DB entry */ log_1(NULL, 0UL, LOG_EMERG, 1, 118); } } } } } } if (0 == strok) { /* ##### ERROR: Strings too long */ } #line 4994 "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 5018 "printqd.ctr" mustsave = 1; if (NULL != oldacc) { if (oldacc->used == newacc->used) { mustsave = 0; } } if (0 != mustsave) { #line 5025 "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 5036 "printqd.ctr" if (0 == save_one_number(89, un, cl->name, newacc->account)) { back = 0; } } #line 5041 "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 5072 "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 5099 "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 5105 "printqd.ctr" } #endif } #if TRACE_DEBUG else { #line 5110 "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 5124 "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 5131 "printqd.ctr" } #endif } #if TRACE_DEBUG else { #line 5136 "printqd.ctr" } #endif } } } } /* Find user limit */ #line 5146 "printqd.ctr" lim = (pqd_limit_t *)dk4sto_it_find_like(cl->i_u, un, 1); if (NULL != lim) { #line 5148 "printqd.ctr" account->limit = lim->limit; back = 1; goto finished; } /* Find group limit */ #line 5156 "printqd.ctr" pw = getpwnam(un); if (NULL != pw) { #line 5158 "printqd.ctr" pg = pw->pw_gid; dk4sto_it_reset(cl->i_g); do { #line 5162 "printqd.ctr" lim = (pqd_limit_t *)dk4sto_it_next(cl->i_g); if (NULL != lim) { #line 5164 "printqd.ctr" if (lim->limit > account->limit) { #line 5165 "printqd.ctr" #line 5166 "printqd.ctr" gr = getgrnam(lim->name); if (NULL != gr) { #line 5168 "printqd.ctr" if (pg == gr->gr_gid) { #line 5169 "printqd.ctr" account->limit = lim->limit; back = 1; } else { #line 5172 "printqd.ctr" if (NULL != gr->gr_mem) { grmem = gr->gr_mem; ingr = 0; while ((0 == ingr) && (NULL != *grmem)) { #line 5177 "printqd.ctr" if (0 == strcmp(un, *grmem)) { ingr = 1; } grmem++; } if (0 != ingr) { #line 5183 "printqd.ctr" account->limit = lim->limit; back = 1; } #if TRACE_DEBUG else { #line 5188 "printqd.ctr" } #endif } #if TRACE_DEBUG else { #line 5193 "printqd.ctr" } #endif } } #if TRACE_DEBUG else { #line 5199 "printqd.ctr" } #endif } } #if TRACE_DEBUG else { #line 5205 "printqd.ctr" } #endif #line 5208 "printqd.ctr" } while(NULL != lim); if (0 != back) { goto finished; } } #if TRACE_DEBUG else { #line 5215 "printqd.ctr" } #endif /* Apply default limit */ #line 5221 "printqd.ctr" account->limit = cl->dl; back = 1; finished: #line 5226 "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 5250 "printqd.ctr" /* Initialize account data */ account_init(account); /* Find printer */ pr = get_printer_for_name(printer_name); if (NULL == pr) { #line 5259 "printqd.ctr" goto finished; } /* Find class for printer */ cl = pr->cl; if (NULL == cl) { #line 5266 "printqd.ctr" goto finished; } if (NULL == cl->name) { #line 5269 "printqd.ctr" goto finished; } /* Search for data */ back = retrieve_account_for_user_and_class(account, user_name, cl, 0); /* Return result */ finished: #line 5280 "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; pages = (dk4_um_t)0UL; } 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 5343 "printqd.ctr" if (DK4_UM_MAX == limit) { #line 5344 "printqd.ctr" back = 1; } else { if (used < limit) { #line 5347 "printqd.ctr" back = 1; } else { if ((dk4_um_t)0UL < account) { #line 5350 "printqd.ctr" back = 1; } } } #line 5355 "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 5373 "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 5399 "printqd.ctr" } /** Process info request. @param job Data for one request to process. */ static void rq_info(pqd_rq_t *job) { #line 5411 "printqd.ctr" rq_retrieve_data(job, 0); #line 5413 "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 5428 "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 5448 "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 5463 "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 5474 "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 5491 "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 5516 "printqd.ctr" #if 0 /* 2016-02-15 Simply ignore non-option text. */ back = 0; /* ERROR: No minus sign */ #endif } textline = next; } #line 5526 "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 5544 "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 5560 "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 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( const char *un, pqd_class_t *cl, dk4_um_t pcval ) { pqd_account_t oldacc; pqd_account_t newacc; #line 5673 "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 5679 "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 5685 "printqd.ctr" } #endif #line 5688 "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 5716 "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 5725 "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 5733 "printqd.ctr" if (0 == dbi_set(db, kb, vb, NULL)) { #line 5734 "printqd.ctr" /* ERROR: Failed to set database entry */ log_1(NULL, 0UL, LOG_EMERG, 1, 117); } } #if TRACE_DEBUG else { #line 5740 "printqd.ctr" } #endif } else { #line 5743 "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 5750 "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 5783 "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 5794 "printqd.ctr" if (0 != dbi_get(db, kb, vb, sizeof(vb), NULL)) { #line 5796 "printqd.ctr" if (0 == dbi_del(db, kb, NULL)) { /* ERROR: Failed to delete db entry */ log_1(NULL, 0UL, LOG_EMERG, 1, 118); } #line 5801 "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 5818 "printqd.ctr" #line 5819 "printqd.ctr" #line 5820 "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 5826 "printqd.ctr" do_charge(un, cl, (pcend - pcstt)); } #if TRACE_DEBUG else { #line 5830 "printqd.ctr" } #endif } #if TRACE_DEBUG else { #line 5835 "printqd.ctr" } #endif } #if TRACE_DEBUG else { #line 5840 "printqd.ctr" } #endif } #if TRACE_DEBUG else { #line 5845 "printqd.ctr" } #endif } #if TRACE_DEBUG else { #line 5850 "printqd.ctr" } #endif } else { #line 5854 "printqd.ctr" #line 5855 "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 5863 "printqd.ctr" } #endif } else { #line 5866 "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 5873 "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 5890 "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 5904 "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 5921 "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 5935 "printqd.ctr" } /** Process acct-check request. @param job Data for one request to process. */ static void rq_acct_check(pqd_rq_t *job) { #line 5947 "printqd.ctr" rq_retrieve_data(job, 1); #line 5949 "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 5965 "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 5988 "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 6004 "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 6027 "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 6046 "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(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 6083 "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 DK4_ARG_UNUSED(cr) ) { int back = 0; DK4_UNUSED_ARG(cr) 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 * DK4_ARG_UNUSED(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 6147 "printqd.ctr" DK4_UNUSED_ARG(v) 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 6185 "printqd.ctr" } } #if TRACE_DEBUG else { #line 6189 "printqd.ctr" } #endif } #if TRACE_DEBUG else { #line 6194 "printqd.ctr" } #endif } #if TRACE_DEBUG else { #line 6199 "printqd.ctr" } #endif } #if TRACE_DEBUG else { #line 6204 "printqd.ctr" } #endif } #if TRACE_DEBUG else { #line 6209 "printqd.ctr" } #endif } #if TRACE_DEBUG else { #line 6214 "printqd.ctr" } #endif } #if TRACE_DEBUG else { #line 6219 "printqd.ctr" } #endif } if (0 == can_continue(0, 0)) { back = -1; } #line 6224 "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 * DK4_ARG_UNUSED(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; DK4_UNUSED_ARG(v) 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 = (pqd_class_t *)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 6329 "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 6341 "printqd.ctr" pv = dk4str8_chr(pc, '='); if (NULL != pv) { *(pv++) = '\0'; pv = dk4str8_start(pv, NULL); } #line 6347 "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 6357 "printqd.ctr" } break; } } pc = pn; } #line 6363 "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 6371 "printqd.ctr" dk4sto_set_comp(ctobj.s, db_entry_compare, 0); ctobj.i = dk4sto_it_open(ctobj.s, NULL); if (NULL != ctobj.i) { #line 6374 "printqd.ctr" (void)dk4dbi_c8_traverse(db, (void *)(&ctobj), rq_c_reset_traverse); #line 6376 "printqd.ctr" dk4sto_it_reset(ctobj.i); do { pc = (char *)dk4sto_it_next(ctobj.i); if (NULL != pc) { #line 6380 "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 6390 "printqd.ctr" } #endif dk4sto_close(ctobj.s); } #if TRACE_DEBUG else { #line 6396 "printqd.ctr" } #endif #line 6399 "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 = (pqd_class_t *)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(void) { 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 6530 "printqd.ctr" subcmd = job->argptr; job->argptr = dk4str8_next(subcmd, NULL); #line 6533 "printqd.ctr" switch ( (sc = dk4str8_abbr_index(control_sub_cmds, '$', subcmd, 0)) ) { case 0 : { #line 6535 "printqd.ctr" rq_c_reset(job); } break; case 1 : { #line 6538 "printqd.ctr" rq_c_add(job); } break; case 2 : { #line 6541 "printqd.ctr" rq_c_dbcl(); } break; default : { /* ERROR: Illegal sub-command */ log_3(NULL, 0UL, LOG_EMERG, 1, 168, 169, subcmd); } break; } #line 6549 "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 6562 "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 6625 "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 6659 "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 6712 "printqd.ctr" goto finished; } /* Run select(). */ errno = 0; res = select((1+maxfd), &rfds, NULL, NULL, NULL); if (-1 == res) { switch (errno) { case EINTR: { #line 6722 "printqd.ctr" goto finished; } break; default: { #line 6725 "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 6734 "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 6741 "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 6773 "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 6810 "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 6819 "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 6849 "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 6875 "printqd.ctr" (void)dk4socket_close(sock, NULL); } } else { #line 6878 "printqd.ctr" (void)dk4socket_close(sock, NULL); } } } } } if (0 == can_continue(1, 0)) { #line 6886 "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 6898 "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 6931 "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 6940 "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 6988 "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 6999 "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 7013 "printqd.ctr" #line 7014 "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 7034 "printqd.ctr" one_pass(); } else { #line 7036 "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 7050 "printqd.ctr" ccouter = -1; } } else { #line 7053 "printqd.ctr" ccouter = -1; } if (0 == inner_release_resources()) { #line 7056 "printqd.ctr" ccouter = -1; } } else { #line 7059 "printqd.ctr" ccouter = -1; } config_release(); } else { #line 7063 "printqd.ctr" ccouter = 0; } } } #if TRACE_DEBUG else { #line 7069 "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 7080 "printqd.ctr" #line 7081 "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); dk4dmt_error_sysfct(&dmt); } 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); dk4dmt_error_sysfct(&dmt); } #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 */ /* Initialize daemon tool structure */ dk4dmt_init(&dmt); dk4dmt_set_program(&dmt, printqd_kw[0]); dk4dmt_set_pidfile(&dmt, pid_file_name); dk4dmt_set_syslog_feature(&dmt, syslogf); /* Process command line arguments. */ res = dk4opt_process_argv( options, szoptions, argc, argv, NULL, NULL, 1, 1, NULL ); if (0 == res) { dk4dmt_error_usage(&dmt); /* Invalid or excess arguments */ fputs("printqd: ERROR: Invalid command line arguments!\n", stderr); fflush(stderr); goto finished; } /* Must be started as root. */ if (0 != geteuid()) { dk4dmt_error_usage(&dmt); 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) { dk4dmt_set_log_stderr(&dmt, 1); dk4dmt_success(&dmt); set_signal_handlers_and_run_service(); goto finished; } /* PREPARE TO RUN AS DAEMON */ dk4dmt_set_program(&dmt, printqd_kw[0]); dk4dmt_set_pidfile(&dmt, pid_file_name); dk4dmt_set_syslog_feature(&dmt, syslogf); if (0 == dk4dmt_parent_before_fork(&dmt)) { goto finished; } /* Create first background process */ cpid = fork(); if ((pid_t)0 < cpid) { /* In the parent process */ dk4dmt_parent_after_fork(&dmt); 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); dk4dmt_parent_fork_failed(&dmt); goto finished; } } /* Intermediate process and daemon process should indicate success. */ dk4dmt_success(&dmt); /* Intermediate process */ /* Decouple from terminals. */ if (0 == dk4dmt_intermediate_before_fork(&dmt)) { goto finished; } /* Create daemon background process from within first background process */ cpid = fork(); if ((pid_t)0 < cpid) { /* In the intermediate process */ dk4dmt_intermediate_after_fork(&dmt); 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); dk4dmt_intermediate_fork_failed(&dmt); goto finished; } } /* In the daemon process */ if (0 != dk4dmt_daemon_start(&dmt)) { set_signal_handlers_and_run_service(); } dk4dmt_daemon_end(&dmt); /* Exit the program. */ finished: exval = dk4dmt_get_exit_status(&dmt); 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