]> git.pond.sub.org Git - empserver/blob - src/client/servcmd.c
Update copyright notice
[empserver] / src / client / servcmd.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2020, 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 doredir(char *p);
58 static void dopipe(char *p);
59 static int doexecute(char *p);
60
61 int
62 servercmd(int code, char *arg, int len)
63 {
64     static int nmin, nbtu, fd;
65     static char the_prompt[1024];
66     static char teles[64];
67
68     switch (code) {
69     case C_PROMPT:
70         if (sscanf(arg, "%d %d", &nmin, &nbtu) != 2) {
71             fprintf(stderr, "Warning: server sent malformed prompt %s",
72                     arg);
73         }
74         snprintf(the_prompt, sizeof(the_prompt), "[%d:%d] Command : ",
75                  nmin, nbtu);
76         if (redir_fp) {
77             if (redir_is_pipe)
78                 (void)pclose(redir_fp);
79             else
80                 (void)fclose(redir_fp);
81             redir_fp = NULL;
82         }
83         outch('\n');
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                 outch('\n');
111                 putchar('\07');
112                 prompt(code, the_prompt, teles);
113             }
114         } else
115             teles[0] = 0;
116         break;
117     case C_PIPE:
118         dopipe(arg);
119         break;
120     case C_REDIR:
121         doredir(arg);
122         break;
123     default:
124         assert(0);
125         break;
126     }
127
128     return 0;
129 }
130
131 static char *
132 fname(char *s)
133 {
134     char *beg, *end;
135
136     for (beg = s; isspace(*(unsigned char *)beg); beg++) ;
137     for (end = beg; !isspace(*(unsigned char *)end); end++) ;
138     *end = 0;
139     return beg;
140 }
141
142 static int
143 common_authorized(char *arg, char *attempt)
144 {
145     if (restricted) {
146         fprintf(stderr, "Can't %s in restricted mode\n", attempt);
147         return 0;
148     }
149
150     if (executing) {
151         fprintf(stderr, "Can't %s in a batch file\n", attempt);
152         return 0;
153     }
154     return 1;
155 }
156
157 static int
158 redir_authorized(char *arg, char *attempt)
159 {
160     if (redir_fp) {
161         fprintf(stderr, "Warning: dropped conflicting %s %s",
162                 attempt, arg);
163         return 0;
164     }
165
166     if (!seen_input(arg)) {
167         fprintf(stderr, "Warning: server attempted to %s %s",
168                 attempt, arg);
169         return 0;
170     }
171
172     return common_authorized(arg, attempt);
173 }
174
175 static int
176 exec_authorized(char *arg)
177 {
178     if (!seen_exec_input(arg)) {
179         fprintf(stderr,
180                 "Warning: server attempted to execute batch file %s", arg);
181         return 0;
182     }
183
184     return common_authorized(arg, "execute batch file");
185 }
186
187 static void
188 doredir(char *p)
189 {
190     int mode;
191     int fd;
192
193     if (!redir_authorized(p, "redirect to file"))
194         return;
195     if (*p++ != '>') {
196         fprintf(stderr, "Warning: dropped weird redirection %s", p);
197         return;
198     }
199
200     mode = O_WRONLY | O_CREAT;
201     if (*p == '>') {
202         mode |= O_APPEND;
203         p++;
204     } else if (*p == '!') {
205         mode |= O_TRUNC;
206         p++;
207     } else
208         mode |= O_EXCL;
209
210     p = fname(p);
211     if (*p == 0) {
212         fprintf(stderr, "Redirection lacks a file name\n");
213         return;
214     }
215
216     redir_is_pipe = 0;
217     fd = open(p, mode, 0666);
218     redir_fp = fd < 0 ? NULL : fdopen(fd, "w");
219     if (!redir_fp) {
220         fprintf(stderr, "Can't redirect to %s: %s\n",
221                 p, strerror(errno));
222     }
223 }
224
225 static void
226 dopipe(char *p)
227 {
228     if (!redir_authorized(p, "pipe to shell command"))
229         return;
230     if (*p++ != '|') {
231         fprintf(stderr, "Warning: dropped weird pipe %s", p);
232         return;
233     }
234
235     for (; *p && isspace(*p); p++) ;
236     if (*p == 0) {
237         fprintf(stderr, "Redirection lacks a command\n");
238         return;
239     }
240
241     /* strip newline */
242     p[strlen(p) - 1] = 0;
243
244     redir_is_pipe = 1;
245     errno = 0;
246     if ((redir_fp = popen(p, "w")) == NULL) {
247         fprintf(stderr, "Can't redirect to pipe %s%s%s\n",
248                 p, errno ? ": " : "", errno ? strerror(errno) : "");
249     }
250 }
251
252 static int
253 doexecute(char *p)
254 {
255     int fd;
256
257     if (!exec_authorized(p))
258         return -1;
259
260     p = fname(p);
261     if (*p == 0) {
262         fprintf(stderr, "Need a file to execute\n");
263         return -1;
264     }
265
266     if ((fd = open(p, O_RDONLY)) < 0) {
267         fprintf(stderr, "Can't open batch file %s: %s\n",
268                 p, strerror(errno));
269         return -1;
270     }
271
272     return fd;
273 }
274
275 void
276 outch(char c)
277 {
278     if (auxfp)
279         putc(c, auxfp);
280     if (redir_fp)
281         putc(c, redir_fp);
282     else if (eight_bit_clean) {
283         if (c == 14)
284             putso();
285         else if (c == 15)
286             putse();
287         else
288             putchar(c);
289     } else if (c & 0x80) {
290         putso();
291         putchar(c & 0x7f);
292         putse();
293     } else
294         putchar(c);
295 }