Projet

Général

Profil

Télécharger (21,3 ko) Statistiques
| Branche: | Révision:

univnautes-tools / pfPorts / check_reload_status / files / check_reload_status.c @ 455d784c

1
/*
2
        Copyright (C) 2010 Ermal Lu?i
3
        All rights reserved.
4

    
5
        Redistribution and use in source and binary forms, with or without
6
        modification, are permitted provided that the following conditions are met:
7

    
8
        1. Redistributions of source code must retain the above copyright notice,
9
           this list of conditions and the following disclaimer.
10

    
11
        2. Redistributions in binary form must reproduce the above copyright
12
           notice, this list of conditions and the following disclaimer in the
13
           documentation and/or other materials provided with the distribution.
14

    
15
        THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
16
        INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
17
        AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
18
        AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
19
        OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20
        SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21
        INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22
        CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23
        ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24
        POSSIBILITY OF SUCH DAMAGE.
25

    
26
*/
27

    
28
#include <sys/types.h>
29
#include <sys/event.h>
30
#include <sys/sbuf.h>
31
#include <sys/stat.h>
32
#include <sys/socket.h>
33
#include <sys/un.h>
34
#include <sys/queue.h>
35

    
36
#include <ctype.h>
37

    
38
#include <stdio.h>
39
#include <errno.h>
40
#include <err.h>
41
#include <fcntl.h>
42
#include <stdlib.h>
43
#include <signal.h>
44
#include <syslog.h>
45
#include <unistd.h>
46
#include <strings.h>
47
#include <string.h>
48

    
49
#include <event.h>
50

    
51
#include "server.h"
52
#include "common.h"
53

    
54
#include <sys/utsname.h>
55

    
56
#include "fastcgi.h"
57

    
58
/*
59
 * Internal representation of a packet.
60
 */
61
struct runq {
62
	TAILQ_ENTRY(runq) rq_link;
63
	struct event ev;
64
	char   command[2048];
65
	char   params[256];
66
	int requestId;
67
	int aggregate;
68
	int dontexec;
69
	int socket;
70
	struct event socket_ev;
71
};
72
TAILQ_HEAD(runqueue, runq) cmds = TAILQ_HEAD_INITIALIZER(cmds);;
73

    
74
/* function definitions */
75
static void			handle_signal(int);
76
static void			handle_signal_act(int, siginfo_t *, void *);
77
static void			run_command(struct command *, char *);
78
static void			set_blockmode(int socket, int cmd);
79
struct command *	match_command(struct command *target, char *wordpassed);
80
struct command *	parse_command(int fd, int argc, char **argv);
81
static void			socket_read_command(int socket, short event, void *arg);
82
static void			show_command_list(int fd, const struct command *list);
83
static void			socket_accept_command(int socket, short event, void *arg);
84
static void			socket_close_command(int fd, struct event *ev);
85
static void			socket_read_fcgi(int, short, void *);
86
static void			fcgi_send_command(int, short, void *);
87
static int			fcgi_open_socket(struct runq *);
88

    
89
static pid_t ppid = -1;
90
static struct utsname uts;
91
static int keepalive = 1;
92
static char *fcgipath = (char *)FCGI_SOCK_PATH;
93

    
94
static int
95
prepare_packet(FCGI_Header *header, int type, int lcontent, int requestId)
96
{
97
        header->version = (unsigned char)FCGI_VERSION_1;
98
        header->type = (unsigned char)type;
99
        header->requestIdB1 = (unsigned char)((requestId >> 8) & 0xFF);
100
        header->requestIdB0 = (unsigned char)(requestId & 0xFF);
101
        header->contentLengthB1 = (unsigned char)((lcontent >> 8) & 0xFF);
102
        header->contentLengthB0 = (unsigned char)(lcontent & 0xFF);
103

    
104
        return (0);
105
}
106

    
107
static int
108
build_nvpair(struct sbuf *sb, int lkey, int lvalue, const char *key, char *svalue)
109
{
110
        if (lkey < 128)
111
                sbuf_putc(sb, lkey);
112
        else
113
                sbuf_printf(sb, "%c%c%c%c", (u_char)((lkey >> 24) | 0x80), (u_char)((lkey >> 16) & 0xFF), (u_char)((lkey >> 8) & 0xFF), (u_char)(lkey & 0xFF));
114

    
115
        if (lvalue < 128 || lvalue > 65535)
116
                sbuf_putc(sb, lvalue);
117
        else
118
                sbuf_printf(sb, "%c%c%c%c", (u_char)((lvalue >> 24) | 0x80), (u_char)((lvalue >> 16) & 0xFF), (u_char)((lvalue >> 8) & 0xFF), (u_char)(lvalue & 0xFF));
119

    
120
        if (lkey > 0)
121
                sbuf_printf(sb, "%s", key);
122
        if (lvalue > 0)
123
                sbuf_printf(sb, "%s", svalue);
124

    
125
        return (0);
126
}
127

    
128
static int
129
fcgi_open_socket(struct runq *cmd)
130
{
131
        struct sockaddr_un sun;
132
	int fcgifd;
133

    
134
	fcgifd = socket(PF_UNIX, SOCK_STREAM, 0);
135
	if (fcgifd < 0) {
136
		syslog(LOG_ERR, "Could not socket\n");
137
		return (-1);
138
	}
139

    
140
	bzero(&sun, sizeof(sun));
141
	sun.sun_family = PF_UNIX;
142
        strlcpy(sun.sun_path, fcgipath, sizeof(sun.sun_path));
143
        if (connect(fcgifd, (struct sockaddr *)&sun, sizeof(sun)) < 0) {
144
                syslog(LOG_ERR, "Could not connect to %s\n", fcgipath);
145
                close(fcgifd);
146
                return (-1);
147
        }
148

    
149
        set_blockmode(fcgifd, O_NONBLOCK | FD_CLOEXEC);
150

    
151
	event_set(&cmd->socket_ev, fcgifd, EV_READ | EV_PERSIST, socket_read_fcgi, cmd);
152
	event_add(&cmd->socket_ev, NULL);
153

    
154
	return (fcgifd);
155
}
156

    
157
static void
158
show_command_list(int fd, const struct command *list)
159
{
160
        int     i;
161
	char	value[2048];
162

    
163
	if (list == NULL)
164
		return;
165

    
166
        for (i = 0; list[i].action != NULLOPT; i++) {
167
                switch (list[i].type) {
168
                case NON:
169
			bzero(value, sizeof(value));
170
			snprintf(value, sizeof(value), "\t%s <cr>\n", list[i].keyword);
171
                        write(fd, value, strlen(value));
172
                        break;
173
                case COMPOUND:
174
			bzero(value, sizeof(value));
175
			snprintf(value, sizeof(value), "\t%s\n", list[i].keyword);
176
                        write(fd, value, strlen(value));
177
                        break;
178
                case ADDRESS:
179
			bzero(value, sizeof(value));
180
			snprintf(value, sizeof(value), "\t%s <address>\n", list[i].keyword);
181
                        write(fd, value, strlen(value));
182
                        break;
183
                case PREFIX:
184
			bzero(value, sizeof(value));
185
			snprintf(value, sizeof(value), "\t%s <address>[/len]\n", list[i].keyword);
186
                        write(fd, value, strlen(value));
187
                        break;
188
		case INTEGER:
189
			bzero(value, sizeof(value));
190
			snprintf(value, sizeof(value), "\t%s <number>\n", list[i].keyword);
191
                        write(fd, value, strlen(value));
192
			break;
193
                case IFNAME:
194
			bzero(value, sizeof(value));
195
			snprintf(value, sizeof(value), "\t%s <interface>\n", list[i].keyword);
196
                        write(fd, value, strlen(value));
197
                        break;
198
                case STRING:
199
			bzero(value, sizeof(value));
200
			snprintf(value, sizeof(value), "\t%s <string>\n", list[i].keyword);
201
                        write(fd, value, strlen(value));
202
                        break;
203
                }
204
        }
205
}
206

    
207
struct command *
208
parse_command(int fd, int argc, char **argv)
209
{
210
	struct command	*start = first_level;
211
	struct command	*match = NULL;
212
	char *errstring = (char *)"ERROR:\tvalid commands are:\n";
213

    
214
	while (argc >= 0) {
215
		match = match_command(start, *argv);
216
		if (match == NULL) {
217
			errstring = (char *)"ERROR:\tNo match found.\n";
218
			goto error3;
219
		}
220

    
221
		argc--;
222
		argv++;
223

    
224
		if (argc > 0 && match->next == NULL) {
225
			errstring = (char *)"ERROR:\textra arguments passed.\n";
226
			goto error3;
227
		}
228
		if (argc < 0 && match->type != NON) {
229
			if (match->next != NULL)
230
				start = match->next;
231
			errstring = (char *)"ERROR:\tincomplete command.\n";
232
			goto error3;
233
		}
234
		if (argc == 0 && *argv == NULL && match->type != NON) {
235
			if (match->next != NULL)
236
				start = match->next;
237
			errstring = (char *)"ERROR:\tincomplete command.\n";
238
			goto error3;
239
		}
240

    
241
		if ( match->next == NULL)
242
			break;
243

    
244
		start = match->next;	
245
	}
246

    
247
	return (match);
248
error3:
249
	write(fd, errstring, strlen(errstring));
250
	show_command_list(fd, start);
251
	return (NULL);
252
}
253

    
254
struct command *
255
match_command(struct command *target, char *wordpassed)
256
{
257
	int i;
258

    
259
	if (wordpassed == NULL)
260
		return NULL;
261

    
262
	for (i = 0; target[i].action != NULLOPT; i++) {
263
		if (strcmp(target[i].keyword, wordpassed) == 0)
264
			return &target[i];
265
	}
266

    
267
	return (NULL);
268
}
269

    
270
static void
271
handle_signal_act(int sig, siginfo_t *unused1 __unused, void *unused2 __unused)
272
{
273
	handle_signal(sig);
274
}
275

    
276
static void
277
handle_signal(int sig)
278
{
279
        switch(sig) {
280
        case SIGHUP:
281
        case SIGTERM:
282
#if 0
283
		if (child)
284
			exit(0);
285
#endif
286
                break;
287
        }
288
}
289

    
290
static void
291
fcgi_send_command(int fd __unused , short event __unused, void *arg)
292
{
293
	FCGI_BeginRequestRecord *bHeader;
294
        FCGI_Header *tmpl;
295
        struct sbuf sb;
296
	struct runq *cmd;
297
	struct timeval tv = { 8, 0 };
298
	static int requestId = 0;
299
	int len, result;
300
	char *p, sbuf[4096], buf[4096], *bufptr;
301

    
302
	cmd = arg;
303
	if (cmd == NULL)
304
		return;
305

    
306
	if (cmd->dontexec) {
307
		TAILQ_REMOVE(&cmds, cmd, rq_link);
308
		timeout_del(&cmd->ev);
309
		event_del(&cmd->socket_ev);
310
		free(cmd);
311
		return;
312
	}
313

    
314
	requestId++;
315
	cmd->requestId = requestId;
316

    
317
	memset(sbuf, 0, sizeof(sbuf));
318
	sbuf_new(&sb, sbuf, 4096, 0);
319
	/* TODO: Use hardcoded length instead of strlen allover later on */
320
	/* TODO: Remove some env variables since might not be needed at all!!! */
321
	build_nvpair(&sb, strlen("GATEWAY_INTERFACE"), strlen("FastCGI/1.0"), "GATEWAY_INTERFACE", (char *)"FastCGI/1.0");
322
	build_nvpair(&sb, strlen("REQUEST_METHOD"), strlen("GET"), "REQUEST_METHOD", (char *)"GET");
323
	build_nvpair(&sb, strlen("SCRIPT_FILENAME"), strlen(cmd->command), "SCRIPT_FILENAME", cmd->command);
324
	build_nvpair(&sb, strlen("NO_HEADERS"), strlen("1"), "NO_HEADERS", (char *)"1");
325
	p = strrchr(cmd->command, '/');
326
	build_nvpair(&sb, strlen("SCRIPT_NAME"), strlen(p), "SCRIPT_NAME", p);
327
	p++;
328
	build_nvpair(&sb, strlen("DOCUMENT_URI"), strlen(p), "DOCUMENT_URI", p);
329
	build_nvpair(&sb, strlen("QUERY_STRING"), strlen(cmd->params), "QUERY_STRING", cmd->params);
330
	if (!cmd->params[0]) {
331
		build_nvpair(&sb, strlen("REQUEST_URI"), 0, "REQUEST_URI", p);
332
	} else {
333
		/* XXX: Hack in sight to avoid using another sbuf */
334
		build_nvpair(&sb, strlen("REQUEST_URI"), 1 + strlen(p) + strlen(cmd->params) + 1, "REQUEST_URI", (char *)"/");
335
		sbuf_printf(&sb, "%s?%s", p, cmd->params);
336
	}
337
	sbuf_finish(&sb);
338

    
339
	len = (3 * sizeof(FCGI_Header)) + sizeof(FCGI_BeginRequestRecord) + sbuf_len(&sb);
340
#if 0
341
	if (len > 4096) {
342
		buf = calloc(1, len);
343
		if (buf == NULL) {
344
			tv.tv_sec = 1;
345
			timeout_add(&cmd->ev, &tv);
346
			sbuf_delete(sbtmp2);
347
			return;
348
		}
349
	} else
350
#endif
351
		memset(buf, 0, sizeof(buf));
352

    
353
	bufptr = buf;
354
	bHeader = (FCGI_BeginRequestRecord *)buf;
355
	prepare_packet(&bHeader->header, FCGI_BEGIN_REQUEST, sizeof(bHeader->body), requestId);
356
	bHeader->body.roleB0 = (unsigned char)FCGI_RESPONDER;
357
	bHeader->body.flags = (unsigned char)(keepalive ? FCGI_KEEP_CONN : 0);
358

    
359
	bufptr += sizeof(FCGI_Header);
360
	tmpl = (FCGI_Header *)bufptr;
361
	prepare_packet(tmpl, FCGI_PARAMS, sbuf_len(&sb), requestId);
362

    
363
	bufptr += sizeof(FCGI_Header);
364
	tmpl = (FCGI_Header *)bufptr;
365
	memcpy((char *)tmpl, sbuf_data(&sb), sbuf_len(&sb));
366

    
367
	bufptr += sbuf_len(&sb);
368
	tmpl = (FCGI_Header *)bufptr;
369
        prepare_packet(tmpl, FCGI_PARAMS, 0, requestId);
370

    
371
	bufptr += sizeof(FCGI_Header);
372
	tmpl = (FCGI_Header *)bufptr;
373
        prepare_packet(tmpl, FCGI_STDIN, 0, requestId);
374
	if (cmd->socket < 0) {
375
		if ((cmd->socket = fcgi_open_socket(cmd)) < 0) {
376
			/* Reschedule */
377
			tv.tv_sec = 1;
378
			cmd->socket = -1;
379
			timeout_add(&cmd->ev, &tv);
380
			return;
381
		}
382
	}
383

    
384
	result = write(cmd->socket, buf, len);
385
	if (result < 0) {
386
		if (cmd->socket) {
387
			event_del(&cmd->socket_ev);
388
			close(cmd->socket);
389
		}
390
		cmd->socket = -1;
391
		syslog(LOG_ERR, "Something wrong happened while sending request: %m\n");
392
		timeout_add(&cmd->ev, &tv);
393
	} else if (cmd->aggregate > 0) {
394
		cmd->dontexec = 1;
395
		timeout_add(&cmd->ev, &tv);
396
	}
397
#if 0
398
	} else {
399
		TAILQ_REMOVE(&cmds, cmd, rq_link);
400
		timeout_del(&cmd->ev);
401
		free(cmd);
402
	}
403
#endif
404
}
405

    
406
static void
407
run_command_detailed(int fd __unused, short event __unused, void *arg) {
408
	struct runq *cmd;
409
	struct timeval tv = { 8, 0 };
410

    
411
	cmd = (struct runq *)arg;
412

    
413
	if (cmd == NULL)
414
		return;
415

    
416
	if (cmd->dontexec) {
417
		TAILQ_REMOVE(&cmds, cmd, rq_link);
418
		timeout_del(&cmd->ev);
419
		free(cmd);
420
		return;
421
	}
422

    
423

    
424
	switch (vfork()) {
425
	case -1:
426
		syslog(LOG_ERR, "Could not vfork() error %d - %s!!!", errno, strerror(errno));
427
		break;
428
	case 0:
429
		/* Possibly optimize by creating argument list and calling execve. */
430
		if (cmd->params[0])
431
			execl("/bin/sh", "/bin/sh", "-c", cmd->command, cmd->params, (char *)NULL);
432
		else
433
			execl("/bin/sh", "/bin/sh", "-c", cmd->command, (char *)NULL);
434
		syslog(LOG_ERR, "could not run: %s", cmd->command);
435
		_exit(127); /* Protect in case execl errors out */
436
		break;
437
	default:
438
		if (cmd->aggregate > 0) {
439
			cmd->dontexec = 1;
440
			timeout_add(&cmd->ev, &tv);
441
		} else {
442
			TAILQ_REMOVE(&cmds, cmd, rq_link);
443
			timeout_del(&cmd->ev);
444
			free(cmd);
445
		}
446
		break;
447
	}
448
}
449

    
450
static void
451
run_command(struct command *cmd, char *argv) {
452
	struct runq *command, *tmpcmd;
453
	struct timeval tv = { 1, 0 };
454
	int aggregate = 0;
455

    
456
	TAILQ_FOREACH(tmpcmd, &cmds, rq_link) {
457
		if (cmd->cmd.flags & AGGREGATE && !strcmp(tmpcmd->command, cmd->cmd.command)) {
458
			aggregate += tmpcmd->aggregate;
459
			if (aggregate > 1) {
460
				/* Rexec the command so the event is not lost. */
461
				if (tmpcmd->dontexec && aggregate < 3) {
462
					//syslog(LOG_ERR, "Rescheduling command %s", tmpcmd->command);
463
					syslog(LOG_NOTICE, cmd->cmd.syslog, argv);
464
					tmpcmd->dontexec = 0;
465
					tv.tv_sec = 5;
466
					timeout_del(&tmpcmd->ev);
467
					timeout_add(&tmpcmd->ev, &tv);
468
				}
469
				return;
470
			}
471
		}
472
	}
473

    
474
	command = calloc(1, sizeof(*command));
475
	if (command == NULL) {
476
		syslog(LOG_ERR, "Calloc failure for command %s", argv);
477
		return;
478
	}
479

    
480
	command->aggregate = aggregate + 1;
481
	memcpy(command->command, cmd->cmd.command, sizeof(command->command));
482
	if (cmd->cmd.params)
483
		snprintf(command->params, sizeof(command->params), cmd->cmd.params, argv);
484

    
485
	if (!(cmd->cmd.flags & AGGREGATE))
486
		command->aggregate = 0;
487

    
488
	TAILQ_INSERT_HEAD(&cmds, command, rq_link);
489

    
490
	switch (cmd->type) {
491
	case NON:
492
		syslog(LOG_NOTICE, "%s", cmd->cmd.syslog);
493
		break;
494
	case COMPOUND: /* XXX: Should never happen. */
495
		syslog(LOG_ERR, "trying to execute COMPOUND entry!!! Please report it.");
496
		return;
497
		/* NOTREACHED */
498
		break;
499
	case ADDRESS:
500
	case PREFIX:
501
	case INTEGER:
502
	case IFNAME:
503
	case STRING:
504
		syslog(LOG_NOTICE, cmd->cmd.syslog, argv);
505
		break;
506
	}
507

    
508
	if (cmd->cmd.flags & FCGICMD) {
509
		command->socket = fcgi_open_socket(command);
510
		timeout_set(&command->ev, fcgi_send_command, command);
511
	} else {
512
		timeout_set(&command->ev, run_command_detailed, command);
513
	}
514
	timeout_add(&command->ev, &tv);
515

    
516
	return;
517
}
518

    
519
static void
520
socket_close_command(int fd, struct event *ev)
521
{
522
	event_del(ev);
523
	free(ev);
524
        close(fd);
525
}
526

    
527
static void
528
socket_read_fcgi(int fd, short event, void *arg)
529
{
530
	struct runq *tmpcmd = arg;
531
	FCGI_Header header;
532
	char buf[4096];
533
        int len, terr, success = 0;
534

    
535
	if (event == EV_TIMEOUT) {
536
		close(fd);
537
		fcgi_open_socket(tmpcmd);
538
		return;
539
	}
540

    
541
	len = 0;
542
	memset(&header, 0, sizeof(header));
543
	if (recv(fd, &header, sizeof(header), 0) > 0) {
544
		len = (header.requestIdB1 << 8) | header.requestIdB0;
545
		len = (header.contentLengthB1 << 8) | header.contentLengthB0;
546
		len += header.paddingLength;
547
		
548
		//syslog(LOG_ERR, "LEN: %d, %d, %d\n", len, header.type, (header.requestIdB1 << 8) | header.requestIdB0);
549
		if (len > 0) {
550
			memset(buf, 0, sizeof(buf));
551

    
552
			/* XXX: Should check if len > sizeof(buf)? */
553
			terr = recv(fd, buf, len, 0);
554
			if (terr < 0) {
555
				syslog(LOG_ERR, "Something happened during recv of data: %m");
556
				return;
557
			}
558
		}
559
	} else 
560
		return;
561

    
562
	switch (header.type) {
563
	case FCGI_DATA:
564
	case FCGI_STDOUT:
565
	case FCGI_STDERR:
566
		break;
567
	case FCGI_ABORT_REQUEST:
568
		syslog(LOG_ERR, "Request aborted\n");
569
		break;
570
	case FCGI_END_REQUEST:
571
		if (len >= (int)sizeof(FCGI_EndRequestBody)) {
572
			switch (((FCGI_EndRequestBody *)buf)->protocolStatus) {
573
			case FCGI_CANT_MPX_CONN:
574
				syslog(LOG_ERR, "The FCGI server cannot multiplex\n");
575
				success = 0;
576
				break;
577
			case FCGI_OVERLOADED:
578
				syslog(LOG_ERR, "The FCGI server is overloaded\n");
579
				success = 0;
580
				break;
581
			case FCGI_UNKNOWN_ROLE:
582
				syslog(LOG_ERR, "FCGI role is unknown\n");
583
				success = 0;
584
				break;
585
			case FCGI_REQUEST_COMPLETE:
586
				//syslog(LOG_ERR, "FCGI request completed");
587
				success = 1;
588
				break;
589
			}
590
			if (tmpcmd != NULL)  {
591
				if (success) {
592
					TAILQ_REMOVE(&cmds, tmpcmd, rq_link);
593
					timeout_del(&tmpcmd->ev);
594
					event_del(&tmpcmd->socket_ev);
595
					free(tmpcmd);
596
				} else {
597
				       /* Rexec the command so the event is not lost. */
598
					syslog(LOG_ERR, "Repeating event %s/%s because it was not triggered.", tmpcmd->command, tmpcmd->params);
599
					if (tmpcmd->dontexec)
600
						tmpcmd->dontexec = 0;
601
				}
602
			}
603
		}
604
		break;
605
	}
606
}
607

    
608
static void
609
socket_read_command(int fd, short event, void *arg)
610
{
611
	struct command *cmd;
612
	struct event *ev = arg;
613
	enum { bufsize = 2048 };
614
	char buf[bufsize];
615
	register int n;
616
	char **ap, *argv[bufsize], *p;
617
	int i, loop = 0;
618

    
619
	if (event == EV_TIMEOUT) {
620
		socket_close_command(fd, ev);
621
		return;
622
	}
623
		
624
tryagain:
625
	bzero(buf, sizeof(buf));
626
	if ((n = read (fd, buf, bufsize)) == -1) {
627
		if (errno != EWOULDBLOCK && errno != EINTR) {
628
			return;
629
		} else {
630
			if (loop > 3) {
631
				return;
632
			}
633
			loop++;
634
			goto tryagain;
635
		}
636
	} else if (n == 0) {
637
		return;
638
	}
639
	
640
	if (buf[n - 1] == '\n')
641
		buf[n - 1] = '\0'; /* remove stray \n */
642
	if (n > 1 && buf[n - 2] == '\r') {
643
		n--;
644
		buf[n - 1] = '\0';
645
	}
646
	for (i = 0; i < n - 1; i++) {
647
		if (!isalpha(buf[i]) && !isspace(buf[i]) && !isdigit(buf[i]) && !ispunct(buf[i])) {
648
			write(fd, "ERROR:\tonly alphanumeric chars allowd", 37);
649
			socket_close_command(fd, ev);
650
			return;
651
		}
652
	}
653
	p = buf; /* blah, compiler workaround */
654

    
655
	i = 0;
656
	for (ap = argv; (*ap = strsep(&p, " \t")) != NULL;) {
657
		if (**ap != '\0') {
658
			if (++ap >= &argv[bufsize])
659
				break;
660
		}
661
		i++;
662
	}
663
	if (i > 0) {
664
		p = argv[i - 1];
665
		i = i - 1;
666
	} else {
667
		p = argv[i];
668
	}
669
	cmd = parse_command(fd, i, argv);
670
	if (cmd != NULL) {
671
		write(fd, "OK\n", 3);
672
		run_command(cmd, p);
673
	}
674

    
675
	return;
676
}
677

    
678
static void
679
socket_accept_command(int fd, __unused short event, __unused void *arg)
680
{
681
	struct sockaddr_un sun;
682
	struct timeval tv = { 10, 0 };
683
	struct event *ev;
684
	socklen_t len;
685
	int newfd;
686

    
687
	if ((newfd = accept(fd, (struct sockaddr *)&sun, &len)) < 0) {
688
		if (errno != EWOULDBLOCK && errno != EINTR)
689
			syslog(LOG_ERR, "problems on accept");
690
		return;
691
	}
692
	set_blockmode(newfd, O_NONBLOCK | FD_CLOEXEC);
693

    
694
	if ((ev = malloc(sizeof(*ev))) == NULL) {
695
		syslog(LOG_ERR, "Cannot allocate new struct event.");
696
		close(newfd);
697
		return;
698
	}
699

    
700
	event_set(ev, newfd, EV_READ | EV_PERSIST, socket_read_command, ev);
701
	event_add(ev, &tv);
702
}
703

    
704
static void
705
set_blockmode(int fd, int cmd)
706
{
707
        int     flags;
708

    
709
        if ((flags = fcntl(fd, F_GETFL, 0)) == -1)
710
                errx(errno, "fcntl F_GETFL");
711

    
712
	flags |= cmd;
713

    
714
        if ((flags = fcntl(fd, F_SETFL, flags)) == -1)
715
                errx(errno, "fcntl F_SETFL");
716
}
717

    
718
int
719
main(void)
720
{
721
	struct event ev;
722
	struct sockaddr_un sun;
723
	struct sigaction sa;
724
	mode_t *mset, mode;
725
	sigset_t set;
726
	int fd, errcode = 0;
727
	char *p;
728

    
729
	tzset();
730

    
731
	/* daemonize */
732
	if (daemon(0, 0) < 0) {
733
		syslog(LOG_ERR, "check_reload_status could not start.");
734
		errcode = 1;
735
		goto error;
736
	}
737

    
738
	syslog(LOG_NOTICE, "check_reload_status is starting.");
739

    
740
	uname(&uts);
741

    
742
	if ((p = getenv("fcgipath")) != NULL) {
743
		fcgipath = p;
744
		syslog(LOG_ERR, "fcgipath %s", fcgipath);
745
	}
746

    
747
	sigemptyset(&set);
748
	sigfillset(&set);
749
	sigdelset(&set, SIGHUP);
750
	sigdelset(&set, SIGTERM);
751
	sigdelset(&set, SIGCHLD);
752
	sigprocmask(SIG_BLOCK, &set, NULL);
753
	signal(SIGCHLD, SIG_IGN);
754

    
755
	sa.sa_handler = handle_signal;
756
	sa.sa_sigaction = handle_signal_act;
757
        sa.sa_flags = SA_SIGINFO|SA_RESTART;
758
        sigemptyset(&sa.sa_mask);
759
        sigaction(SIGHUP, &sa, NULL);
760
	sigaction(SIGTERM, &sa, NULL);
761

    
762
	ppid = getpid();
763
	if (fork() == 0) {
764
		setproctitle("Monitoring daemon of check_reload_status");
765
		/* Prepare code to monitor the parent :) */
766
		struct kevent kev;
767
		int kq;
768

    
769
		while (1) {
770
			kq = kqueue();
771
			EV_SET(&kev, ppid, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, NULL);
772
			kevent(kq, &kev, 1, NULL, 0, NULL);
773
			switch (kevent(kq, NULL, 0, &kev, 1, NULL)) {
774
			case 1:
775
				syslog(LOG_ERR, "Reloading check_reload_status because it exited from an error!");
776
				execl("/usr/local/sbin/check_reload_status", "/usr/local/sbin/check_reload_status", (char *)NULL);
777
				_exit(127);
778
				syslog(LOG_ERR, "could not run check_reload_status again");
779
				/* NOTREACHED */
780
				break;
781
			default:
782
				/* XXX: Should report any event?! */
783
				break;
784
			}
785
			close(kq);
786
		}
787
		exit(2);
788
	}
789

    
790
	fd = socket(PF_UNIX, SOCK_STREAM, 0);
791
	if (fd < 0) {
792
		errcode = -1;
793
		printf("Could not socket\n");
794
		goto error;
795
	}
796

    
797
#if 0
798
	if (unlink(PATH) == -1) {
799
		errcode = -2;
800
		printf("Could not unlink\n");
801
		close(fd);
802
		goto error;
803
	}
804
#else
805
	unlink(PATH);
806
#endif
807

    
808
	bzero(&sun, sizeof(sun));
809
        sun.sun_family = PF_UNIX;
810
        strlcpy(sun.sun_path, PATH, sizeof(sun.sun_path));
811
	if (bind(fd, (struct sockaddr *)&sun, sizeof(sun)) < 0) {
812
		errcode = -2;
813
		printf("Could not bind\n");
814
		close(fd);
815
		goto error;
816
	}
817

    
818
	set_blockmode(fd, O_NONBLOCK | FD_CLOEXEC);
819

    
820
        if (listen(fd, 30) == -1) {
821
                printf("control_listen: listen");
822
		close(fd);
823
                return (-1);
824
        }
825

    
826
	/* 0666 */
827
	if ((mset = setmode("0666")) != NULL) {
828
		mode = getmode(mset, S_IRUSR|S_IWUSR | S_IRGRP|S_IWGRP | S_IROTH|S_IWOTH);
829
		chmod(PATH, mode);
830
		free(mset);
831
	}
832

    
833
	TAILQ_INIT(&cmds);
834

    
835
	event_init();
836
	event_set(&ev, fd, EV_READ | EV_PERSIST, socket_accept_command, &ev);
837
	event_add(&ev, NULL);
838
	event_dispatch();
839

    
840
	return (0);
841
error:
842
	syslog(LOG_NOTICE, "check_reload_status is stopping.");
843

    
844
	return (errcode);
845
}
(1-1/6)