]> git.pond.sub.org Git - empserver/blob - src/client/servcmd.c
c02390dc06a1f3d121d0b30c34951950ec1b54fa
[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-2017
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 int
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             executing = 1;
95         return fd;
96     case C_EXIT:
97         printf("Exit: %s", arg);
98         if (auxfp)
99             fprintf(auxfp, "Exit: %s", arg);
100         break;
101     case C_FLASH:
102         printf("\n%s", arg);
103         if (auxfp)
104             fprintf(auxfp, "\n%s", arg);
105         break;
106     case C_INFORM:
107         if (arg[0] != '\n') {
108             snprintf(teles, sizeof(teles), "(%.*s) ", len - 1, arg);
109             if (!redir_fp) {
110                 putchar('\07');
111                 prompt(code, the_prompt, teles);
112             }
113         } else
114             teles[0] = 0;
115         break;
116     case C_PIPE:
117         dopipe(arg);
118         break;
119     case C_REDIR:
120         doredir(arg);
121         break;
122     default:
123         assert(0);
124         break;
125     }
126
127     return 0;
128 }
129
130 static void
131 prompt(int code, char *prompt, char *teles)
132 {
133     char *nl;
134
135     nl = code == C_PROMPT || code == C_INFORM ? "\n" : "";
136     printf("%s%s%s", nl, teles, prompt);
137     fflush(stdout);
138     if (auxfp) {
139         fprintf(auxfp, "%s%s%s", nl, teles, prompt);
140         fflush(auxfp);
141     }
142 }
143
144 static char *
145 fname(char *s)
146 {
147     char *beg, *end;
148
149     for (beg = s; isspace(*(unsigned char *)beg); beg++) ;
150     for (end = beg; !isspace(*(unsigned char *)end); end++) ;
151     *end = 0;
152     return beg;
153 }
154
155 static int
156 common_authorized(char *arg, char *attempt)
157 {
158     if (restricted) {
159         fprintf(stderr, "Can't %s in restricted mode\n", attempt);
160         return 0;
161     }
162
163     if (executing) {
164         fprintf(stderr, "Can't %s in a batch file\n", attempt);
165         return 0;
166     }
167     return 1;
168 }
169
170 static int
171 redir_authorized(char *arg, char *attempt)
172 {
173     if (redir_fp) {
174         fprintf(stderr, "Warning: dropped conflicting %s %s",
175                 attempt, arg);
176         return 0;
177     }
178
179     if (!seen_input(arg)) {
180         fprintf(stderr, "Warning: server attempted to %s %s",
181                 attempt, arg);
182         return 0;
183     }
184
185     return common_authorized(arg, attempt);
186 }
187
188 static int
189 exec_authorized(char *arg)
190 {
191     if (!seen_exec_input(arg)) {
192         fprintf(stderr,
193                 "Warning: server attempted to execute batch file %s", arg);
194         return 0;
195     }
196
197     return common_authorized(arg, "execute batch file");
198 }
199
200 static void
201 doredir(char *p)
202 {
203     int mode;
204     int fd;
205
206     if (!redir_authorized(p, "redirect to file"))
207         return;
208     if (*p++ != '>') {
209         fprintf(stderr, "Warning: dropped weird redirection %s", p);
210         return;
211     }
212
213     mode = O_WRONLY | O_CREAT;
214     if (*p == '>') {
215         mode |= O_APPEND;
216         p++;
217     } else if (*p == '!') {
218         mode |= O_TRUNC;
219         p++;
220     } else
221         mode |= O_EXCL;
222
223     p = fname(p);
224     if (*p == 0) {
225         fprintf(stderr, "Redirection lacks a file name\n");
226         return;
227     }
228
229     redir_is_pipe = 0;
230     fd = open(p, mode, 0666);
231     redir_fp = fd < 0 ? NULL : fdopen(fd, "w");
232     if (!redir_fp) {
233         fprintf(stderr, "Can't redirect to %s: %s\n",
234                 p, strerror(errno));
235     }
236 }
237
238 static void
239 dopipe(char *p)
240 {
241     if (!redir_authorized(p, "pipe to shell command"))
242         return;
243     if (*p++ != '|') {
244         fprintf(stderr, "Warning: dropped weird pipe %s", p);
245         return;
246     }
247
248     for (; *p && isspace(*p); p++) ;
249     if (*p == 0) {
250         fprintf(stderr, "Redirection lacks a command\n");
251         return;
252     }
253
254     /* strip newline */
255     p[strlen(p) - 1] = 0;
256
257     redir_is_pipe = 1;
258     errno = 0;
259     if ((redir_fp = popen(p, "w")) == NULL) {
260         fprintf(stderr, "Can't redirect to pipe %s%s%s\n",
261                 p, errno ? ": " : "", errno ? strerror(errno) : "");
262     }
263 }
264
265 static int
266 doexecute(char *p)
267 {
268     int fd;
269
270     if (!exec_authorized(p))
271         return -1;
272
273     p = fname(p);
274     if (*p == 0) {
275         fprintf(stderr, "Need a file to execute\n");
276         return -1;
277     }
278
279     if ((fd = open(p, O_RDONLY)) < 0) {
280         fprintf(stderr, "Can't open batch file %s: %s\n",
281                 p, strerror(errno));
282         return -1;
283     }
284
285     return fd;
286 }
287
288 void
289 outch(char c)
290 {
291     if (auxfp)
292         putc(c, auxfp);
293     if (redir_fp)
294         putc(c, redir_fp);
295     else if (eight_bit_clean) {
296         if (c == 14)
297             putso();
298         else if (c == 15)
299             putse();
300         else
301             putchar(c);
302     } else if (c & 0x80) {
303         putso();
304         putchar(c & 0x7f);
305         putse();
306     } else
307         putchar(c);
308 }