]> git.pond.sub.org Git - empserver/blob - src/client/servcmd.c
Flaws in the Empire protocol make redirections within execute next to
[empserver] / src / client / servcmd.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2007, Dave Pare, Jeff Bailey, Thomas Ruschak,
4  *                           Ken Stevens, Steve McClure
5  *
6  *  This program 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 2 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, write to the Free Software
18  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  *  ---
21  *
22  *  See files README, COPYING and CREDITS in the root of the source
23  *  tree for related information and legal notices.  It is expected
24  *  that future projects/authors will amend these files as needed.
25  *
26  *  ---
27  *
28  *  servercmd.c: Change the state depending on the command from the server.
29  * 
30  *  Known contributors to this file:
31  *     Dave Pare, 1989
32  *     Steve McClure, 1998
33  *     Ron Koenderink, 2005
34  *     Markus Armbruster, 2005-2007
35  */
36
37 #include <config.h>
38
39 #include <assert.h>
40 #include <ctype.h>
41 #include <errno.h>
42 #include <fcntl.h>
43 #include <stdio.h>
44 #include <string.h>
45 #include "misc.h"
46 #include "proto.h"
47 #include "secure.h"
48
49 int eight_bit_clean;
50 FILE *auxfp;
51
52 static FILE *redir_fp;
53 static FILE *pipe_fp;
54 static int executing;
55 static size_t input_to_forget;
56
57 static void prompt(int, char *, char *);
58 static void doredir(char *p);
59 static void dopipe(char *p);
60 static void doexecute(char *p);
61
62 void
63 servercmd(int code, char *arg, int len)
64 {
65     static int nmin, nbtu;
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, "prompt: bad server prompt %s\n", arg);
73         }
74         snprintf(the_prompt, sizeof(the_prompt), "[%d:%d] Command : ",
75                  nmin, nbtu);
76         prompt(code, the_prompt, teles);
77         break;
78     case C_FLUSH:
79         snprintf(the_prompt, sizeof(the_prompt), "%.*s", len - 1, arg);
80         prompt(code, the_prompt, teles);
81         break;
82     case C_EXECUTE:
83         doexecute(arg);
84         break;
85     case C_EXIT:
86         printf("Exit: %s", arg);
87         if (auxfp)
88             fprintf(auxfp, "Exit: %s", arg);
89         break;
90     case C_FLASH:
91         printf("\n%s", arg);
92         if (auxfp)
93             fprintf(auxfp, "\n%s", arg);
94         break;
95     case C_INFORM:
96         if (*arg) {
97             snprintf(teles, sizeof(teles), "(%.*s )", len -1, arg);
98             if (!redir_fp && !pipe_fp) {
99                 putchar('\07');
100                 prompt(code, the_prompt, teles);
101             }
102         } else
103             teles[0] = 0;
104         break;
105     case C_PIPE:
106         dopipe(arg);
107         break;
108     case C_REDIR:
109         doredir(arg);
110         break;
111     default:
112         assert(0);
113         break;
114     }
115 }
116
117 static void
118 prompt(int code, char *prompt, char *teles)
119 {
120     char *nl;
121
122     if (code == C_PROMPT) {
123         if (redir_fp) {
124             (void)fclose(redir_fp);
125             redir_fp = NULL;
126         } else if (pipe_fp) {
127             (void)pclose(pipe_fp);
128             pipe_fp = NULL;
129         }
130         executing = 0;
131         if (input_to_forget) {
132             forget_input(input_to_forget);
133             input_to_forget = 0;
134         }
135     }
136
137     nl = code == C_PROMPT || code == C_INFORM ? "\n" : "";
138     printf("%s%s%s", nl, teles, prompt);
139     fflush(stdout);
140     if (auxfp) {
141         fprintf(auxfp, "%s%s%s", nl, teles, prompt);
142         fflush(auxfp);
143     }
144 }
145
146 static char *
147 fname(char *s)
148 {
149     char *beg, *end;
150
151     for (beg = s; isspace(*(unsigned char *)beg); beg++) ;
152     for (end = beg; !isspace(*(unsigned char *)end); end++) ;
153     *end = 0;
154     return beg;
155 }
156
157 static int
158 redir_authorized(char *arg, char *attempt)
159 {
160     size_t seen = seen_input(arg);
161
162     if (executing) {
163         fprintf(stderr, "Can't %s in a script\n", attempt);
164         return 0;
165     }
166
167     if (!seen || (input_to_forget && input_to_forget != seen)) {
168         fprintf(stderr, "WARNING!  Server attempted to %s %s\n",
169                 attempt, arg);
170         return 0;
171     }
172     input_to_forget = seen;
173     return 1;
174 }
175
176 /*
177  * opens redir_fp if successful
178  */
179 static void
180 doredir(char *p)
181 {
182     int mode;
183     int fd;
184
185     if (redir_fp) {
186         (void)fclose(redir_fp);
187         redir_fp = NULL;
188     }
189
190     if (!redir_authorized(p, "redirect to file"))
191         return;
192     if (*p++ != '>') {
193         fprintf(stderr, "WARNING!  Weird redirection %s", p);
194         return;
195     }
196
197     mode = O_WRONLY | O_CREAT;
198     if (*p == '>') {
199         mode |= O_APPEND;
200         p++;
201     } else if (*p == '!') {
202         mode |= O_TRUNC;
203         p++;
204     } else
205         mode |= O_EXCL;
206
207     p = fname(p);
208     if (*p == 0) {
209         fprintf(stderr, "Redirection lacks a file name\n");
210         return;
211     }
212
213     fd = open(p, mode, 0666);
214     redir_fp = fd < 0 ? NULL : fdopen(fd, "w");
215     if (!redir_fp) {
216         fprintf(stderr, "Can't redirect to %s: %s\n",
217                 p, strerror(errno));
218     }
219 }
220
221 /*
222  * opens "pipe_fp" if successful
223  */
224 static void
225 dopipe(char *p)
226 {
227     if (!redir_authorized(p, "pipe to shell command"))
228         return;
229     if (*p++ != '|') {
230         fprintf(stderr, "WARNING!  Weird pipe %s", p);
231         return;
232     }
233
234     for (; *p && isspace(*p); p++) ;
235     if (*p == 0) {
236         fprintf(stderr, "Redirection lacks a command\n");
237         return;
238     }
239
240     if ((pipe_fp = popen(p, "w")) == NULL) {
241         fprintf(stderr, "Can't redirect to pipe %s: %s\n",
242                 p, strerror(errno));
243     }
244 }
245
246 static void
247 doexecute(char *p)
248 {
249     int fd;
250
251     if (!redir_authorized(p, "execute script file")) {
252         send_eof++;
253         return;
254     }
255
256     p = fname(p);
257     if (*p == 0) {
258         fprintf(stderr, "Need a file to execute\n");
259         send_eof++;
260         return;
261     }
262
263     if ((fd = open(p, O_RDONLY)) < 0) {
264         fprintf(stderr, "Can't open execute file %s: %s\n",
265                 p, strerror(errno));
266         send_eof++;
267         return;
268     }
269
270     input_fd = fd;
271     executing = 1;
272 }
273
274 void
275 outch(char c)
276 {
277     if (auxfp)
278         putc(c, auxfp);
279     if (redir_fp)
280         putc(c, redir_fp);
281     else if (pipe_fp)
282         putc(c, pipe_fp);
283     else if (eight_bit_clean) {
284         if (c == 14)
285             putso();
286         else if (c == 15)
287             putse();
288         else
289             putchar(c);
290     } else if (c & 0x80) {
291         putso();
292         putchar(c & 0x7f);
293         putse();
294     } else
295         putchar(c);
296 }