pidentd  3.0.19
About: implementation of the RFC1413 identification server (more or less complete rewrite compared to version 2)
  Fossies Dox: pidentd-3.0.19.tar.gz  ("inofficial" and yet experimental doxygen-generated source code documentation)  

main.c
Go to the documentation of this file.
1 /*
2 ** main.c - Main entrypoint for Pidentd 3.0
3 **
4 ** Copyright (c) 1997 Peter Eriksson <pen@lysator.liu.se>
5 **
6 ** This program is free software; you can redistribute it and/or
7 ** modify it as you wish - as long as you don't claim that you wrote
8 ** it.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 */
14 
15 #include "config.h"
16 
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <syslog.h>
21 #ifdef HAVE_UNISTD_H
22 #include <unistd.h>
23 #endif
24 #include <signal.h>
25 
26 #include "pidentd.h"
27 
28 #if defined(HAVE_LIBTHREAD) && defined(HAVE_THR_SETCONCURRENCY)
29 # include <thread.h>
30 #endif
31 
32 extern char *optarg;
33 extern int optind;
34 
35 char *argv0 = "identd";
36 
37 int debug = 0;
41 
42 #ifdef HAVE_LIBDES
43 int encrypt_flag = 0;
44 char *encrypt_keyfile = PATH_KEYFILE;
45 #endif
46 
48 
49 
50 static void
51 usage(FILE *fp)
52 {
53  fprintf(fp, "Usage: %s [options]\n", argv0);
54  fputs("\n", fp);
55  fputs("Options:\n", fp);
56  fputs(" -d Enable debug mode\n", fp);
57  fputs(" -h Print this information\n", fp);
58  fputs(" -V Print version and OS information\n", fp);
59  fputs("\n", fp);
60  fputs(" -w Start in Inetd 'wait' mode\n", fp);
61  fputs(" -i Start in Inetd 'nowait' mode\n", fp);
62  fputs(" -I Start in Init mode\n", fp);
63  fputs(" -b Start in Standalone mode\n", fp);
64  fputs("\n", fp);
65  fputs(" -e Enable protocol extensions\n", fp);
66  fputs(" -m Enable multiquery mode\n", fp);
67 #ifdef HAVE_LIBDES
68  fputs(" -E Enable DES encrypted replies\n", fp);
69 #endif
70  fputs(" -n Send uid numbers instead of usernames\n", fp);
71  fputs(" -o Return OTHER instead of UNIX\n", fp);
72  fputs(" -N Check for .noident files\n", fp);
73  fputs("\n", fp);
74  fputs(" -l Log a message to syslog at startup\n", fp);
75  fputs(" -t<time> Request timeout limit in seconds\n", fp);
76  fputs(" -p<port> Port to listen for connections on\n", fp);
77  fputs(" -g<group> Group name/number to run as\n", fp);
78  fputs(" -u<user> User name/number to run as\n", fp);
79  fputs(" -C<file> Config file to include\n", fp);
80  fputs(" -P<file> Where to write the process id number\n", fp);
81  fputs(" -K<threads> Number of kernel lookup threads\n", fp);
82 }
83 
84 
85 static void
86 program_header(FILE *fp)
87 {
88  fprintf(fp, "[Pidentd, version %s (compiled for %s) - %s %s]\n",
90  __DATE__, __TIME__);
91 }
92 
93 void
95 {
96  if (geteuid() != ROOT_UID)
97  return;
98 
99  if (server_uid == NO_UID)
100  {
101  if (str2uid("nobody", &server_uid, &server_gid) < 0)
103  }
104 
105  if (setgroups(1, &server_gid) < 0)
106  goto Error;
107 
108  if (server_gid != ROOT_GID)
109  if (setgid(server_gid) < 0)
110  goto Error;
111 
112  if (server_uid != ROOT_UID)
113  if (setuid(server_uid) < 0)
114  goto Error;
115 
116  return;
117  Error:
118  syslog(LOG_ERR, "Error while changing user/group privileges");
120 }
121 
122 int
123 main(int argc, char *argv[])
124 {
125  int c;
126 #ifdef LOG_DAEMON
127  int code = LOG_DAEMON;
128 #else
129  int code = 0;
130 #endif
131  int socket_type = -1;
132  int init_mode = 0;
133  int log_header = 0;
134 
135 
136  if (argv[0] != NULL)
137  {
138  char *cp;
139 
140  cp = strrchr(argv[0], '/');
141  if (cp != NULL)
142  argv0 = s_strdup(cp+1);
143  else
144  argv0 = s_strdup(argv[0]);
145  }
146 
147 #ifdef SIGTTOU
148  signal(SIGTTOU, SIG_IGN);
149 #endif
150  signal(SIGPIPE, SIG_IGN);
151 
152  s_openlog(argv0, LOG_PID|LOG_ODELAY, code);
153 
154 
155  /*
156  ** Try to autodetect how we was started.
157  */
158  socket_type = socktype(STDIN_FILENO);
159 
160  if (debug)
161  fprintf(stderr, "socktype = %d\n", socket_type);
162 
163  if (socket_type == SOCKTYPE_LISTEN || socket_type == SOCKTYPE_CONNECTED)
165 
167 
168 
169  while ((c = getopt(argc, argv, "lNVEdhbwiIemnop:u:g:t:C:P:K:L:")) != -1)
170  switch (c)
171  {
172 #ifdef HAVE_LIBDES
173  case 'E':
174  encrypt_flag = 1;
175  break;
176 #endif
177 
178  case 'n':
179  uidonly_flag = 1;
180  break;
181 
182  case 'd':
183  debug++;
184  break;
185 
186  case 'h':
187  usage(stdout);
188  return EXIT_SUCCESS;
189 
190  case 'e':
191  extensions_enabled = 1;
192  break;
193 
194  case 'm':
195  multiquery_enabled = 1;
196  break;
197 
198  case 'w':
200  socket_type = SOCKTYPE_LISTEN;
201  break;
202 
203  case 'i':
205  socket_type = SOCKTYPE_CONNECTED;
206  break;
207 
208  case 'I':
209  listen_sock = -1;
210  socket_type = SOCKTYPE_NOTSOCKET;
211  init_mode = 1;
212  break;
213 
214  case 'b':
215  listen_sock = -1;
216  socket_type = SOCKTYPE_NOTSOCKET;
217  break;
218 
219  case 'l':
220  log_header = 1;
221  break;
222 
223  case 'p':
224  if (str2port(optarg, &listen_port) < 0)
225  {
226  syslog(LOG_ERR, "invalid argument to '-p': %s", optarg);
227  if (socket_type == -1 || socket_type == SOCKTYPE_NOTSOCKET)
228  fprintf(stderr, "%s: invalid argument to '-p': %s",
229  argv0, optarg);
230  return EXIT_FAILURE;
231  }
232  break;
233 
234  case 't':
235  if (str2int(optarg, &request_timeout) < 0)
236  {
237  syslog(LOG_ERR, "invalid argument to '-t': %s", optarg);
238  if (socket_type == -1 || socket_type == SOCKTYPE_NOTSOCKET)
239  fprintf(stderr, "%s: invalid argument to '-t': %s",
240  argv0, optarg);
241  return EXIT_FAILURE;
242  }
243  break;
244 
245  case 'g':
246  if (str2gid(optarg, &server_gid) < 0)
247  {
248  syslog(LOG_ERR, "invalid argument to '-g': %s", optarg);
249  if (socket_type == -1 || socket_type == SOCKTYPE_NOTSOCKET)
250  fprintf(stderr, "%s: invalid argument to '-g': %s",
251  argv0, optarg);
252  return EXIT_FAILURE;
253  }
254  break;
255 
256  case 'u':
257  if (str2uid(optarg, &server_uid, &server_gid) < 0)
258  {
259  syslog(LOG_ERR, "invalid argument to '-u': %s", optarg);
260  if (socket_type == -1 || socket_type == SOCKTYPE_NOTSOCKET)
261  fprintf(stderr, "%s: invalid argument to '-u': %s",
262  argv0, optarg);
263  return EXIT_FAILURE;
264  }
265  break;
266 
267  case 'L':
268  code = syslog_str2fac(optarg);
269  if (code < 0)
270  {
271  syslog(LOG_ERR, "invalid argument to '-L': %s", optarg);
272  if (socket_type == -1 || socket_type == SOCKTYPE_NOTSOCKET)
273  fprintf(stderr, "%s: invalid argument to '-L': %s",
274  argv0, optarg);
275  return EXIT_FAILURE;
276  }
277  closelog();
278  s_openlog(argv0, LOG_PID|LOG_ODELAY, code);
279  break;
280 
281  case 'C':
282  if (conf_parse(optarg, 0) < 0)
283  {
284  if (socket_type == -1 || socket_type == SOCKTYPE_NOTSOCKET)
285  fprintf(stderr, "%s: error parsing config file: %s\n",
286  argv[0], optarg);
287  return EXIT_FAILURE;
288  }
289  break;
290 
291  case 'P':
293  break;
294 
295  case 'K':
296  if (str2int(optarg, &kernel_threads) < 0)
297  {
298  syslog(LOG_ERR, "invalid argument to '-K': %s", optarg);
299  if (socket_type == -1 || socket_type == SOCKTYPE_NOTSOCKET)
300  fprintf(stderr, "%s: invalid argument to '-K': %s",
301  argv0, optarg);
302  return EXIT_FAILURE;
303  }
304  break;
305 
306  case 'o':
307  opsys = "OTHER";
308  break;
309 
310  case 'N':
311  noident_flag = 1;
312  break;
313 
314  case 'V':
315  program_header(stdout);
317 
318  default:
319  if (socket_type == -1 || socket_type == SOCKTYPE_NOTSOCKET)
320  usage(stderr);
321  else
322  syslog(LOG_ERR, "invalid command line option: %s",
323  argv[optind]);
324 
325  return EXIT_FAILURE;
326  }
327 
328  if (debug)
329  program_header(stderr);
330 
331  if (socket_type == -1)
332  {
333  syslog(LOG_ERR, "unable to autodetect socket type");
334  fprintf(stderr, "%s: unable to autodetect socket type\n",
335  argv0);
336  return EXIT_FAILURE;
337  }
338 
339  if (ka_init())
340  {
341  syslog(LOG_ERR, "OS version mismatch - compiled for %s", osinfo_build);
342  if (socket_type == SOCKTYPE_NOTSOCKET)
343  fprintf(stderr,
344  "%s: OS version mismatch - compiled for: %s\n",
345  argv[0], osinfo_build);
346  return EXIT_FAILURE;
347  }
348 
349 
350  if (!debug &&
351  getppid() != INIT_PID && !init_mode &&
352  socket_type != SOCKTYPE_CONNECTED &&
353  listen_sock < 0)
354  {
355  become_daemon();
356  }
357 
358 #ifdef HAVE_THR_SETCONCURRENCY
359 #if 1
360  thr_setconcurrency(kernel_threads+8);
361 #else
362  thr_setconcurrency(sysconf(_SC_NPROCESSORS_ONLN));
363 #endif
364 #endif
365 
366  if (log_header)
367  syslog(LOG_INFO, "started");
368  else
369  syslog(LOG_DEBUG, "started");
370 
371 
374 
375 
376  if (socket_type != SOCKTYPE_CONNECTED)
377  {
378  if (!debug && pidfile_path != NULL)
380 
381  if (server_init() < 0)
382  {
383  if (debug)
384  fprintf(stderr, "%s: failed binding to the TCP/IP socket\n",
385  argv[0]);
386  goto Exit;
387  }
388  }
389 
390 #ifdef HAVE_LIBDES
391  if (encrypt_flag)
392  {
393  if (pdes_init(encrypt_keyfile) < 0)
394  {
395  syslog(LOG_ERR, "encryption could not be initalized: %m");
396  if (debug)
397  {
398  fprintf(stderr, "%s: encryption could not be initialized: ",
399  argv[0]);
400  perror("");
401  }
402  goto Exit;
403  }
404  }
405 #endif
406 
407 /* Sigh - stupid Linux handles threads like... Anyway, we'll have to
408  add this kludge to work around the fact that threads in Linux can
409  have different uid's... Luckily Linux doesn't need root to get at
410  the needed information anyway. */
411 #ifdef __linux__
412  drop_root_privs();
413 #endif
414 
415  if (kernel_init() < 0)
416  {
417  if (debug)
418  fprintf(stderr, "%s: failed opening kernel devices\n",
419  argv[0]);
420  goto Exit;
421  }
422 
423 #ifndef __linux__
424  drop_root_privs();
425 #endif
426 
427  timeout_init();
428  request_init();
429 
430  if (socket_type != SOCKTYPE_CONNECTED)
431  {
432  if (debug)
433  fprintf(stderr, "entering server main loop\n");
434 
435  server_run();
436  }
437  else
438  return request_run(listen_sock, 1);
439 
440  Exit:
441  syslog(LOG_DEBUG, "terminating");
442  return EXIT_FAILURE;
443 }
PATH_CFGFILE
#define PATH_CFGFILE
Definition: pidentd.h:49
PATH_PIDFILE
#define PATH_PIDFILE
Definition: pidentd.h:45
s_strdup
char * s_strdup(const char *s)
Definition: safeio.c:161
opsys
char * opsys
Definition: send.c:36
extensions_enabled
int extensions_enabled
Definition: request.c:29
debug
int debug
Definition: main.c:37
PTHREAD_CREATE_DETACHED
#define PTHREAD_CREATE_DETACHED
Definition: cma_thr.h:53
request_timeout
int request_timeout
Definition: request.c:31
pidfile_create
void pidfile_create(const char *path)
Definition: daemon.c:85
SOCKTYPE_CONNECTED
#define SOCKTYPE_CONNECTED
Definition: support.h:24
server_uid
uid_t server_uid
Definition: main.c:38
uidonly_flag
int uidonly_flag
Definition: send.c:31
syslog_str2fac
int syslog_str2fac(const char *name)
Definition: support.c:411
timeout_init
int timeout_init(void)
Definition: timeout.c:248
pidentd.h
socktype
int socktype(int fd)
Definition: support.c:64
argv0
char * argv0
Definition: main.c:35
request_run
int request_run(int fd, int nofork)
Definition: request.c:261
request_init
int request_init(void)
Definition: request.c:310
program_header
static void program_header(FILE *fp)
Definition: main.c:86
server_version
char server_version[]
Definition: version.c:1
kernel_threads
int kernel_threads
Definition: kernel.c:34
optind
int optind
NO_UID
#define NO_UID
Definition: pidentd.h:55
pdes_init
int pdes_init(char *keyfile)
ROOT_UID
#define ROOT_UID
Definition: pidentd.h:56
server_run
int server_run(void)
Definition: server.c:116
pidfile_path
char * pidfile_path
Definition: main.c:40
optarg
char * optarg
conf_parse
int conf_parse(const char *path, int silent)
Definition: conf.c:26
LOG_ODELAY
#define LOG_ODELAY
Definition: system.h:32
usage
static void usage(FILE *fp)
Definition: main.c:51
str2gid
int str2gid(const char *str, gid_t *out)
Definition: str2.c:159
drop_root_privs
void drop_root_privs(void)
Definition: main.c:94
server_gid
gid_t server_gid
Definition: main.c:39
listen_sock
int listen_sock
Definition: server.c:28
str2port
int str2port(const char *str, int *out)
Definition: str2.c:136
noident_flag
int noident_flag
Definition: send.c:32
multiquery_enabled
int multiquery_enabled
Definition: request.c:30
str2int
int str2int(const char *buf, int *out)
Definition: str2.c:50
cma_t_handle
Definition: hp_pthread.h:26
SOCKTYPE_LISTEN
#define SOCKTYPE_LISTEN
Definition: support.h:23
exit
#define exit
Definition: k_sunos510.c:38
main
int main(int argc, char *argv[])
Definition: main.c:123
ka_init
#define ka_init
Definition: k_sunos510.c:36
pthread_attr_setdetachstate
#define pthread_attr_setdetachstate(ap, state)
Definition: cma_thr.h:58
become_daemon
void become_daemon(void)
Definition: daemon.c:38
server_init
int server_init(void)
Definition: server.c:62
kernel::argv
char * argv
Definition: kernel.h:40
cattr_detached
int cattr_detached
Definition: main.c:47
STDIN_FILENO
#define STDIN_FILENO
Definition: system.h:36
SOCKTYPE_NOTSOCKET
#define SOCKTYPE_NOTSOCKET
Definition: support.h:22
ROOT_GID
#define ROOT_GID
Definition: pidentd.h:57
kernel_init
int kernel_init(void)
Definition: kernel.c:131
s_openlog
void s_openlog(const char *ident, int logopt, int facility)
Definition: support.c:348
listen_port
int listen_port
Definition: server.c:29
str2uid
int str2uid(const char *str, uid_t *uid, gid_t *gid)
Definition: str2.c:180
EXIT_SUCCESS
#define EXIT_SUCCESS
Definition: system.h:40
pthread_attr_init
#define pthread_attr_init(ap)
Definition: cma_thr.h:51
osinfo_build
char osinfo_build[]
EXIT_FAILURE
#define EXIT_FAILURE
Definition: system.h:44
INIT_PID
#define INIT_PID
Definition: pidentd.h:53