Subversion Repositories general

Rev

Rev 1140 | Rev 1143 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1140 dev 1
/******************************************************************
2
 *
3
 * Daemon which waiting on specified TCP port for special string
4
 * and reboot the computer.
5
 *
6
 * Command line: rebootdaemon [--port PORT] [--config CONFIG_FILE]
7
 * Defaults are port 19 and config /etc/rebootdaemon.conf.
8
 *
9
 * Config file looks like:
10
 * --------------------------
11
 * port=19
12
 * password="some password"
13
 * --------------------------
14
 *
15
 * Usage example (from any other host):
16
 * echo -n "some password" | nc host_to_rebot 19
17
 *
18
 * Copyleft 2005 Anatoli Klassen
19
 *
20
 ******************************************************************/
21
 
22
#include <stdlib.h>
23
#include <stdio.h>
24
#include <string.h>
25
#include <stdarg.h>
26
#include <errno.h>
27
#include <signal.h>
28
#include <unistd.h>
29
#include <netdb.h>
30
#include <syslog.h>
31
#include <sys/types.h>
32
#include <sys/socket.h>
33
#include <sys/wait.h>
34
#include <sys/reboot.h>
35
#include <netinet/in.h>
36
#include <arpa/inet.h>
37
 
38
#define PORT             19
39
#define CFG_FILE         "/etc/rebootdaemon.conf"
40
#define CMDSIZE          4096
41
#define BUFSIZE          4096
42
#define MAX_CONFIG_LINE  4096
43
#define PORT_MIN         1
44
#define PORT_MAX         65535
45
 
46
#define PARAM_PORT_1     "-p"
47
#define PARAM_PORT_2     "--port"
48
#define PARAM_CONFIG_1   "-c"
49
#define PARAM_CONFIG_2   "--config"
50
#define CONFIG_PORT      "port"
51
#define CONFIG_PASSWORD  "password"
52
 
53
struct config {
54
	int  port;
55
	char password[MAX_CONFIG_LINE];
56
};
57
 
58
static struct config cfg;
59
 
60
static int parse_cmd_line(int argc, char* argv[], long *port, char *config_name);
61
static int parse_config_file(char *config_name, long *port, char *password);
62
 
63
static int min(int a, int b)
64
{
65
	return (a < b) ? a : b;
66
}
67
 
68
static int establish(unsigned short portnum)
69
{
70
	int s;
71
	struct sockaddr_in sa;
72
 
73
	memset(&sa, 0, sizeof(struct sockaddr_in));
74
 
75
	sa.sin_family      = AF_INET;
76
	sa.sin_port        = htons(portnum);
77
	sa.sin_addr.s_addr = INADDR_ANY;
78
 
79
	if((s = socket(AF_INET, SOCK_STREAM, 0)) < 0)
80
		return -1;
81
 
82
	if(bind(s, (struct sockaddr *)&sa, sizeof(struct sockaddr_in)) < 0) {
83
		close(s);
84
		return -1;
85
	}
86
 
87
	listen(s, 1);
88
 
89
	return s;
90
}
91
 
1142 dev 92
static void listen_socket(int socket)
93
{
94
	int                t;
95
	char               cmd[CMDSIZE];
96
	char               buf[BUFSIZE];
97
	char*              msg;
98
	int                br;
99
	struct sockaddr_in sa;
100
	socklen_t          sa_len;
101
 
102
	for(;;) {
103
		sa_len = sizeof(sa);
104
		if((t = accept(socket, (struct sockaddr *)&sa, &sa_len)) < 0) {
105
			if(errno == EINTR) /* EINTR might happen on accept(), */
106
				continue;        /* try again */
107
 
108
			msg = strerror(errno);
109
			syslog(LOG_ERR, "cannot get connection, %s", msg);
110
			continue;
111
		}
112
 
113
		msg = inet_ntoa(sa.sin_addr);
114
		syslog(LOG_INFO, "connect from %s", msg);
115
 
116
		cmd[0] = '\0';
117
		while((br = recv(t, buf, BUFSIZE, 0)) > 0) {
118
			strncat(cmd, buf, min(br, sizeof(cmd) - strlen(cmd) - 1));
119
		}
120
		sleep(1);
121
		close(t);
122
 
123
		syslog(LOG_INFO, "got command [%s]", cmd);
124
 
125
		if(0 == strncmp(cmd, cfg.password, sizeof(cmd))) {
126
			syslog(LOG_EMERG, "REBOOT");
127
			sleep(5);
128
			if(reboot(RB_AUTOBOOT) < 0) {
129
				msg = strerror(errno);
130
				syslog(LOG_ERR, "cannot reboot, %s", msg);
131
			}
132
		}
133
	}
134
}
135
 
1140 dev 136
static int print_cmd_error(char *msg, char *value)
137
{
138
	fprintf(stderr, "%s", msg);
139
	if(value) fprintf(stderr, " - %s\n", value);
140
	fprintf(stderr, "\n");
141
 
142
	return 0;
143
}
144
 
145
static int print_config_error(char *config_name, int line, char *msg, char *value)
146
{
147
	fprintf(stderr, "Error in %s, line %d: %s", config_name, line, msg);
148
	if(value) fprintf(stderr, " - %s", value);
149
	fprintf(stderr, "\n");
150
 
151
	return 0;
152
}
153
 
154
static int read_config(int argc, char* argv[])
155
{
156
	long cmd_port;
157
	long file_port;
158
	char cmd_config[MAX_CONFIG_LINE];
159
 
160
	if(!parse_cmd_line(argc, argv, &cmd_port, cmd_config)) return 0;
161
 
162
	if(!parse_config_file(cmd_config[0] != '\0' ? cmd_config : CFG_FILE, &file_port, cfg.password)) return 0;
163
 
164
	if(cfg.password[0] == '\0') {
165
		fprintf(stderr, "Password is not set\n");
166
		return 0;
167
	}
168
 
169
	if(cmd_port > 0)
170
		cfg.port = (int)cmd_port;
171
	else if(file_port > 0)
172
		cfg.port = (int)file_port;
173
	else
174
		cfg.port = PORT;
175
 
176
	return 1;
177
}
178
 
179
static int parse_cmd_line(int argc, char* argv[], long *port, char *config_name)
180
{
181
	char *end;
182
	int  i;
183
 
184
	*port          = 0;
185
	config_name[0] = '\0';
186
 
187
	for(i = 1; i < argc; i++) {
188
		if(0 == strcmp(argv[i], PARAM_PORT_1) || 0 == strcmp(argv[i], PARAM_PORT_2)) {
189
			if(*port > 0)
190
				return print_cmd_error("Port is already set", NULL);
191
 
192
			if(++i < argc) {
193
				*port = strtol(argv[i], &end, 10);
194
				if(*end != '\0' || *port < PORT_MIN || *port > PORT_MAX)
195
					return print_cmd_error("Port number must be integer between 1 and 65535", NULL);
196
			}
197
			else {
198
				return print_cmd_error("Port number expected", NULL);
199
			}
200
		}
201
		else if(0 == strcmp(argv[i], PARAM_CONFIG_1) || 0 == strcmp(argv[i], PARAM_CONFIG_2)) {
202
			if(config_name[0] != '\0')
203
				return print_cmd_error("Config file is already set", NULL);
204
 
205
			if(++i < argc) {
206
				strncpy(config_name, argv[i], MAX_CONFIG_LINE);
207
				if(config_name[MAX_CONFIG_LINE - 1] != '\0')
208
					return print_cmd_error("Config file name is too long", NULL);
209
			}
210
			else {
211
				return print_cmd_error("Config file expected", NULL);
212
			}
213
		}
214
		else {
215
			return print_cmd_error("Unknown parameter", argv[i]);
216
		}
217
	}
218
 
219
	return 1;
220
}
221
 
222
 
223
static int parse_config_file(char *config_name, long *port, char *password)
224
{
225
	FILE *config_file;
226
	char buf[MAX_CONFIG_LINE];
227
	char *line;
228
	char *subline;
229
	char *cur;
230
	int  count;
231
 
232
	config_file = fopen(config_name, "r");
233
	if(!config_file) {
234
		fprintf(stderr, "Can not open config file %s: %s\n", config_name, strerror(errno));
235
		return 0;
236
	}
237
 
238
	count = 0;
239
	while(fgets(buf, sizeof(buf), config_file)) {
240
		count++;
241
		line = buf;
242
 
243
		/* skip end spaces */
244
		int len = strlen(line);
245
		while(len && isspace(line[len-1])) --len;
246
		if(!len) continue;
247
		line[len] = '\0';
248
 
249
		/* skip begin spaces */
250
		while(line[0] != '\0' && isspace(line[0])) line++;
251
 
252
		if('#' == line[0]) { /* skip comment lines */
253
			continue;
254
		}
255
		else if(strncmp(line, CONFIG_PORT, min(sizeof(CONFIG_PORT) - 1, len)) == 0) {
256
			subline = line + sizeof(CONFIG_PORT) - 1;
257
			while(subline[0] != '\0' && isspace(subline[0])) subline++;
258
			if('=' != subline[0])
259
				return print_config_error(config_name, count, "Equal sign expected", NULL);
260
			subline++;
261
			*port = strtol(subline, &subline, 10);
262
			if(*port < PORT_MIN || *port > PORT_MAX)
263
				return print_config_error(config_name, count, 
264
					"Port number must be integer between 1 and 65535", NULL);
265
			while(subline[0] != '\0' && isspace(subline[0])) subline++;
266
			if('\0' != subline[0] && '#' != subline[0])
267
				return print_config_error(config_name, count, "End of line expected", NULL);
268
		}
269
		else if(strncmp(line, CONFIG_PASSWORD, min(sizeof(CONFIG_PASSWORD) - 1, len)) == 0) {
270
			subline = line + sizeof(CONFIG_PASSWORD) - 1;
271
			while(subline[0] != '\0' && isspace(subline[0])) subline++;
272
			if('=' != subline[0])
273
				return print_config_error(config_name, count, "Equal sign expected", NULL);
274
			subline++;
275
			while(subline[0] != '\0' && isspace(subline[0])) subline++;
276
			if('"' != subline[0])
277
				return print_config_error(config_name, count, "Open quot expected", NULL);
278
			subline++;
279
 
280
			cur = password;
281
			while(subline[0] != '\0' && subline[0] != '"') {
282
				cur[0] = subline[0];
283
				cur++;
284
				subline++;
285
			}
286
 
287
			cur[0] = '\0';
288
			if('"' != subline[0])
289
				return print_config_error(config_name, count, "Close quot expected", NULL);
290
			subline++;
291
			while(subline[0] != '\0' && isspace(subline[0])) subline++;
292
			if('\0' != subline[0] && '#' != subline[0])
293
				return print_config_error(config_name, count, "End of line expected", NULL);
294
		}
295
		else {
296
			return print_config_error(config_name, count, "Unknown config parameter", line);
297
		}
298
	}
299
 
300
	if(fclose(config_file) != 0) {
301
		fprintf(stderr, "Can not close config file %s: %s\n", config_name, strerror(errno));
302
		return 0;
303
	}
304
 
305
	return 1;
306
}
307
 
308
int main(int argc, char* argv[])
309
{
1142 dev 310
	int s;
1140 dev 311
 
312
	if(!read_config(argc, argv)) return 1;
313
 
314
	if((s = establish(cfg.port)) < 0) {
315
		fprintf(stderr, "Cannot listen to port %i\n", cfg.port);
316
		return 1;
317
	}
318
 
1142 dev 319
	listen_socket(s);
1140 dev 320
 
321
	return 0;
322
}
323