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