]> git.pond.sub.org Git - empserver/blob - src/client/servcmd.c
client: Signal interrupt instead of EOF on batch file error
[empserver] / src / client / servcmd.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2015, Dave Pare, Jeff Bailey, Thomas Ruschak,
4  *                Ken Stevens, Steve McClure, Markus Armbruster
5  *
6  *  Empire is free software: you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation, either version 3 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  *
19  *  ---
20  *
21  *  See files README, COPYING and CREDITS in the root of the source
22  *  tree for related information and legal notices.  It is expected
23  *  that future projects/authors will amend these files as needed.
24  *
25  *  ---
26  *
27  *  servercmd.c: Change the state depending on the command from the server.
28  *
29  *  Known contributors to this file:
30  *     Dave Pare, 1989
31  *     Steve McClure, 1998
32  *     Ron Koenderink, 2005
33  *     Markus Armbruster, 2005-2015
34  */
35
36 #include <config.h>
37
38 #include <assert.h>
39 #include <ctype.h>
40 #include <errno.h>
41 #include <fcntl.h>
42 #include <stdio.h>
43 #include <string.h>
44 #include <unistd.h>
45 #include "misc.h"
46 #include "proto.h"
47 #include "secure.h"
48
49 int eight_bit_clean;
50 FILE *auxfp;
51 int restricted;
52
53 static FILE *redir_fp;
54 static int redir_is_pipe;
55 static int executing;
56
57 static void prompt(int, char *, char *);
58 static void doredir(char *p);
59 static void dopipe(char *p);
60 static int doexecute(char *p);
61
62 void
63 servercmd(int code, char *arg, int len)
64 {
65     static int nmin, nbtu, fd;
66     static char the_prompt[1024];
67     static char teles[64];
68
69     switch (code) {
70     case C_PROMPT:
71         if (sscanf(arg, "%d %d", &nmin, &nbtu) != 2) {
72             fprintf(stderr, "Warning: server sent malformed prompt %s",
73                     arg);
74         }
75         snprintf(the_prompt, sizeof(the_prompt), "[%d:%d] Command : ",
76                  nmin, nbtu);
77         if (redir_fp) {
78             if (redir_is_pipe)
79                 (void)pclose(redir_fp);
80             else
81                 (void)fclose(redir_fp);
82             redir_fp = NULL;
83         }
84         prompt(code, the_prompt, teles);
85         executing = 0;
86         break;
87     case C_FLUSH:
88         snprintf(the_prompt, sizeof(the_prompt), "%.*s", len - 1, arg);
89         prompt(code, the_prompt, teles);
90         break;
91     case C_EXECUTE:
92         fd = doexecute(arg);
93         if (fd < 0) {
94             if (input_fd)
95                 close(input_fd);
96         } else {
97             assert(!input_fd);
98             executing = 1;
99         }
100         input_fd = fd;
101         break;
102     case C_EXIT:
103         printf("Exit: %s", arg);
104         if (auxfp)
105             fprintf(auxfp, "Exit: %s", arg);
106         break;
107     case C_FLASH:
108         printf("\n%s", arg);
109         if (auxfp)
110             fprintf(auxfp, "\n%s", arg);
111         break;
112     case C_INFORM:
113         if (arg[0] != '\n') {
114             snprintf(teles, sizeof(teles), "(%.*s) ", len - 1, arg);
115             if (!redir_fp) {
116                 putchar('\07');
117                 prompt(code, the_prompt, teles);
118             }
119         } else
120             teles[0] = 0;
121         break;
122     case C_PIPE:
123         dopipe(arg);
124         break;
125     case C_REDIR:
126         doredir(arg);
127         break;
128     default:
129         assert(0);
130         break;
131     }
132 }
133
134 static void
135 prompt(int code, char *prompt, char *teles)
136 {
137     char *nl;
138
139     nl = code == C_PROMPT || code == C_INFORM ? "\n" : "";
140     printf("%s%s%s", nl, teles, prompt);
141     fflush(stdout);
142     if (auxfp) {
143         fprintf(auxfp, "%s%s%s", nl, teles, prompt);
144         fflush(auxfp);
145     }
146 }
147
148 static char *
149 fname(char *s)
150 {
151     char *beg, *end;
152
153     for (beg = s; isspace(*(unsigned char *)beg); beg++) ;
154     for (end = beg; !isspace(*(unsigned char *)end); end++) ;
155     *end = 0;
156     return beg;
157 }
158
159 static int
160 common_authorized(char *arg, char *attempt)
161 {
162     if (restricted) {
163         fprintf(stderr, "Can't %s in restricted mode\n", attempt);
164         return 0;
165     }
166
167     if (executing) {
168         fprintf(stderr, "Can't %s in a batch file\n", attempt);
169         return 0;
170     }
171     return 1;
172 }
173
174 static int
175 redir_authorized(char *arg, char *attempt)
176 {
177     if (redir_fp) {
178         fprintf(stderr, "Warning: dropped conflicting %s %s",
179                 attempt, arg);
180         return 0;
181     }
182
183     if (!seen_input(arg)) {
184         fprintf(stderr, "Warning: server attempted to %s %s",
185                 attempt, arg);
186         return 0;
187     }
188
189     return common_authorized(arg, attempt);
190 }
191
192 static int
193 exec_authorized(char *arg)
194 {
195     if (!seen_exec_input(arg)) {
196         fprintf(stderr,
197                 "Warning: server attempted to execute batch file %s", arg);
198         return 0;
199     }
200
201     return common_authorized(arg, "execute batch file");
202 }
203
204 static void
205 doredir(char *p)
206 {
207     int mode;
208     int fd;
209
210     if (!redir_authorized(p, "redirect to file"))
211         return;
212     if (*p++ != '>') {
213         fprintf(stderr, "Warning: dropped weird redirection %s", p);
214         return;
215     }
216
217     mode = O_WRONLY | O_CREAT;
218     if (*p == '>') {
219         mode |= O_APPEND;
220         p++;
221     } else if (*p == '!') {
222         mode |= O_TRUNC;
223         p++;
224     } else
225         mode |= O_EXCL;
226
227     p = fname(p);
228     if (*p == 0) {
229         fprintf(stderr, "Redirection lacks a file name\n");
230         return;
231     }
232
233     redir_is_pipe = 0;
234     fd = open(p, mode, 0666);
235     redir_fp = fd < 0 ? NULL : fdopen(fd, "w");
236     if (!redir_fp) {
237         fprintf(stderr, "Can't redirect to %s: %s\n",
238                 p, strerror(errno));
239     }
240 }
241
242 static void
243 dopipe(char *p)
244 {
245     if (!redir_authorized(p, "pipe to shell command"))
246         return;
247     if (*p++ != '|') {
248         fprintf(stderr, "Warning: dropped weird pipe %s", p);
249         return;
250     }
251
252     for (; *p && isspace(*p); p++) ;
253     if (*p == 0) {
254         fprintf(stderr, "Redirection lacks a command\n");
255         return;
256     }
257
258     /* strip newline */
259     p[strlen(p) - 1] = 0;
260
261     redir_is_pipe = 1;
262     errno = 0;
263     if ((redir_fp = popen(p, "w")) == NULL) {
264         fprintf(stderr, "Can't redirect to pipe %s%s%s\n",
265                 p, errno ? ": " : "", errno ? strerror(errno) : "");
266     }
267 }
268
269 static int
270 doexecute(char *p)
271 {
272     int fd;
273
274     if (!exec_authorized(p))
275         return -1;
276
277     p = fname(p);
278     if (*p == 0) {
279         fprintf(stderr, "Need a file to execute\n");
280         return -1;
281     }
282
283     if ((fd = open(p, O_RDONLY)) < 0) {
284         fprintf(stderr, "Can't open batch file %s: %s\n",
285                 p, strerror(errno));
286         return -1;
287     }
288
289     return fd;
290 }
291
292 void
293 outch(char c)
294 {
295     if (auxfp)
296         putc(c, auxfp);
297     if (redir_fp)
298         putc(c, redir_fp);
299     else if (eight_bit_clean) {
300         if (c == 14)
301             putso();
302         else if (c == 15)
303             putse();
304         else
305             putchar(c);
306     } else if (c & 0x80) {
307         putso();
308         putchar(c & 0x7f);
309         putse();
310     } else
311         putchar(c);
312 }