2
* Copyright (c) 1998 peter memishian (meem), meem@gnu.org
4
* This program is free software; you can redistribute it and/or modify
5
* it under the terms of the GNU General Public License as published by
6
* the Free Software Foundation; either version 2, or (at your option)
9
* This program is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
* General Public License for more details.
14
* $Id: rlprd.c,v 1.7 1999/05/04 01:45:24 meem Exp $
17
#include <sys/types.h>
18
#include <sys/socket.h>
20
#include <sys/time.h> /* select() */
21
#include <sys/stat.h> /* umask() */
28
#include <netinet/in.h>
29
#include <arpa/inet.h>
32
#include R_MAXHOSTNAMELEN_HDR
34
#ifdef HAVE_SYS_SELECT_H
35
#include <sys/select.h>
44
static struct component *components[] =
52
const char *program_name;
53
const char *bsd_program_name = 0;
55
static struct rlpr_rlprd *rlpr_rlprd;
57
static int converse(int, int);
58
static int process_client(int, struct sockaddr_in *);
59
static int register_sigchld(void);
60
static int daemonize(void);
61
static RETSIGTYPE catch_sigchld(int);
62
static RETSIGTYPE graceful_shutdown(int);
65
main(int argc, char *argv[])
67
struct component *comp;
68
int listen_fd, client_fd;
69
struct sockaddr_in sin_rlprd, sin_client;
72
program_name = argv[0];
75
setlocale(LC_ALL, "");
76
bindtextdomain(PACKAGE, LOCALEDIR);
79
if ((comp = component_init(components, argc, argv)) != 0)
80
msg(R_FATAL, 0, "component `%s': init() failed!", comp->name);
83
msg(R_FATAL, 0, "must be run as root or setuid root");
85
if (register_sigchld() == -1)
86
msg(R_FATAL, errno, "register_sigchld");
88
signal(SIGHUP, SIG_IGN);
89
signal(SIGQUIT, SIG_IGN);
90
signal(SIGTERM, graceful_shutdown);
92
if (rlpr_rlprd->no_daemon == 0 && daemonize() == 0)
93
msg(R_FATAL, 0, "daemonizing failed");
96
* open ourselves for business
99
listen_fd = socket(AF_INET, SOCK_STREAM, 0);
101
msg(R_FATAL, errno, "socket() for listening socket");
103
setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, (caddr_t)&on, sizeof on);
105
init_sockaddr_in(&sin_rlprd, 0, rlpr_rlprd->listen_port);
107
if (bind(listen_fd, (struct sockaddr *)&sin_rlprd, sizeof sin_rlprd) == -1)
108
msg(R_FATAL, errno, "bind() on listening socket");
110
if (listen(listen_fd, 5) == -1)
111
msg(R_FATAL, errno, "listen() on listening socket");
113
msg(R_DEBUG, 0, "listening for incoming connections on port %hu",
114
rlpr_rlprd->listen_port);
117
* main loop - accept incoming requests, calling process_client() on each
122
client_fd = accept(listen_fd, (struct sockaddr *)&sin_client, &unused);
123
if (client_fd == -1) {
125
msg(R_ERROR, errno, "accept");
132
if (process_client(client_fd, &sin_client) == 0)
139
msg(R_ERROR, errno, "fork");
153
process_client(int client_fd, struct sockaddr_in *sin_client)
155
char printhost[MAXHOSTNAMELEN + 1];
158
struct sockaddr_in sin_local;
159
struct sockaddr_in sin_lpd;
161
msg(R_DEBUG, 0, "process_client: connection from %s:%i",
162
inet_ntoa(sin_client->sin_addr), ntohs(sin_client->sin_port));
165
* read in the hostname
168
for (i = 0; i < MAXHOSTNAMELEN; i++) {
169
full_read_timed(client_fd, &printhost[i], 1, rlpr_rlprd->timeout, 0, 0);
170
if (printhost[i] == '\n')
174
msg(R_DEBUG, 0, "process_client: request for host `%s'", printhost);
177
* process the request
180
init_sockaddr_in(&sin_local, 0, 0);
181
if (init_sockaddr_in(&sin_lpd, printhost, R_LPD_DST_PORT) == 0)
184
toggle_root(); /* get root */
186
lpd_fd = socket(AF_INET, SOCK_STREAM, 0);
188
msg(R_ERROR, errno, "process_client: socket");
193
if (bind_try_range(&sin_local, lpd_fd, R_LPD_SRC_PORT_LOW,
194
R_LPD_SRC_PORT_HIGH) == 0) {
195
msg(R_ERROR, errno, "process_client: bind");
202
if (connect_timed(lpd_fd, &sin_lpd, rlpr_rlprd->timeout) == -1) {
203
msg(R_ERROR, errno, "process_client: connect to lpd");
207
msg(R_DEBUG, 0, "process_client: connected from %s:%i to %s:%i",
208
inet_ntoa(sin_client->sin_addr), ntohs(sin_client->sin_port),
209
inet_ntoa(sin_lpd.sin_addr), ntohs(sin_lpd.sin_port));
211
if (converse(client_fd, lpd_fd) == 0) {
212
msg(R_ERROR, 0, "process_client: errors in conversing with lpd");
216
msg(R_DEBUG, 0, "process client: transaction completed");
221
converse(int client_fd, int server_fd)
223
int maxfdp1 = MAX(client_fd, server_fd) + 1;
224
char buffer[R_BUFMAX];
226
int read_fd, write_fd;
232
FD_SET(client_fd, &fds);
233
FD_SET(server_fd, &fds);
235
if (select(maxfdp1, &fds, 0, 0, 0) <= 0) {
236
msg(R_ERROR, errno, "converse: select");
240
read_fd = FD_ISSET(client_fd, &fds) ? client_fd : server_fd;
241
write_fd = FD_ISSET(client_fd, &fds) ? server_fd : client_fd;
243
n_read = read(read_fd, buffer, sizeof buffer);
247
full_write_timed(write_fd, buffer, n_read, rlpr_rlprd->timeout, 0, 0);
253
catch_sigchld(int unused)
255
while (waitpid(-1, 0, WNOHANG) > 0)
261
graceful_shutdown(int unused)
263
struct component *comp;
265
if ((comp = component_fini(components)) != 0)
266
msg(R_FATAL, 0, "component `%s': fini() failed!", comp->name);
272
register_sigchld(void)
274
struct sigaction sa = { 0 };
276
sa.sa_handler = catch_sigchld;
278
sa.sa_flags = SA_RESTART;
280
sigemptyset(&sa.sa_mask);
282
return sigaction(SIGCHLD, &sa, 0);
294
msg(R_ERROR, errno, "fork while daemonizing");
300
* start our new session, fork() again to lose process group leader
316
/* FALLTHRU into default */
328
struct rlpr_rlprd rlpr_rlprd_tmpl = { 0, R_RLPRD_LISTEN_PORT };
330
rlpr_rlprd = xmalloc(sizeof (struct rlpr_rlprd));
331
*rlpr_rlprd = rlpr_rlprd_tmpl;
333
rlpr_rlprd->timeout = R_TIMEOUT_DEFAULT;
338
rlprd_parse_args(int opt)
343
rlpr_rlprd->no_daemon++;
347
rlpr_rlprd->listen_port = strtoul(optarg, 0, 0);
351
msg(R_STDOUT, 0, "usage: %s [-nqV] [-pport] [--debug]"
352
" \nplease see the manpage for detailed help", program_name);
357
rlpr_rlprd->timeout = strtol(optarg, 0, 0);
361
msg(R_STDOUT, 0, "version "VERSION" from "__DATE__" "__TIME__
373
static struct option rlprd_opts[] = {
374
{ "help", 0, 0, -700 },
375
{ "no-daemon", 0, 0, 'n' },
376
{ "port", 1, 0, 'p' },
377
{ "timeout", 1, 0, -701 },
378
{ "version", 0, 0, 'V' },
382
static const char rlprd_opt_list[] = "npV";
384
struct component comp_rlprd = {
385
"rlprd", rlprd_init, 0,
386
{ { rlprd_opts, rlprd_opt_list, rlprd_parse_args } }