]> git.pond.sub.org Git - empserver/blob - src/lib/commands/info.c
(info): Don't leak potentially sensitive information to player in
[empserver] / src / lib / commands / info.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2004, 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 the "LEGAL", "LICENSE", "CREDITS" and "README" files for all the
23  *  related information and legal notices. It is expected that any future
24  *  projects/authors will amend these files as needed.
25  *
26  *  ---
27  *
28  *  info.c: display an info page
29  * 
30  *  Known contributors to this file:
31  *     Dave Pare, 1986
32  *     Mike Wise, 1997 - added apropos and case insensitivity
33  *     Doug Hay, 1998
34  *     Steve McClure, 1998-2000
35  */
36
37 #include "misc.h"
38 #include "player.h"
39 #include <errno.h>
40 #include <string.h>
41 #include <stdio.h>
42 #include <sys/stat.h>
43 #if !defined(_WIN32)
44 #include <dirent.h>
45 #else
46 #include <windows.h>
47 #endif
48 #include "commands.h"
49 #include "optlist.h"
50
51 static s_char *
52 lowerit(s_char *buf, int n, s_char *orig)
53 {                               /* converts a string to lower case */
54     /* lower case output buffer */
55     /* size of output buffer */
56     /* input strig */
57     int i;
58     s_char *tmp;
59     tmp = buf;
60     memset(buf, 0, n);
61     for (i = 0; i < n && *orig; i++) {
62         *tmp++ = tolower(*orig++);
63     }
64     return buf;
65 }
66
67 static int
68 strnccmp(s_char *s1, s_char *s2, int n)
69 {
70     int i;
71     char c1, c2;
72     for (i = 0; i < n && *s1 && s2; i++) {
73         c1 = tolower(*s1++);
74         c2 = tolower(*s2++);
75         if (c1 > c2)
76             return 1;
77         else if (c1 < c2)
78             return -1;
79     }
80     return 0;
81 }
82
83 #if !defined(_WIN32)
84
85 int
86 info(void)
87 {
88     s_char buf[255];
89     FILE *fp;
90     s_char *bp;
91     struct stat statb;
92     struct dirent *dp;
93     s_char filename[1024];
94     DIR *info_dp;
95
96     if (player->argp[1] == 0 || !*player->argp[1])
97         bp = "TOP";
98     /*
99      * don't let sneaky people go outside the info directory
100      */
101     else if (NULL != (bp = strrchr(player->argp[1], '/')))
102         bp++;
103     else
104         bp = player->argp[1];
105     sprintf(filename, "%s/%s", infodir, bp);
106     fp = fopen(filename, "r");
107     if (fp == NULL) {
108         int len = strlen(bp);
109         /* may be a "partial" request.  */
110         info_dp = opendir(infodir);
111         if (info_dp == 0) {
112             pr("Can't open info dir\n");
113             logerror("Can't open info dir \"%s\"\n", infodir);
114             return RET_SYS;
115         }
116         rewinddir(info_dp);
117         while ((dp = readdir(info_dp)) != 0 && fp == 0) {
118             if (strnccmp(bp, dp->d_name, len) != 0)
119                 continue;
120             sprintf(filename, "%s/%s", infodir, dp->d_name);
121             fp = fopen(filename, "r");
122         }
123         closedir(info_dp);
124         if (fp == NULL) {
125             pr("Sorry, there is no info on %s\n", bp);
126             return RET_FAIL;
127         }
128     }
129     if (fstat(fileno(fp), &statb) < 0) {
130         pr("Error reading info file for %s\n", bp);
131         logerror("Cannot fstat for \"%s\" info file (%s)",
132             filename, strerror(errno));
133         fclose(fp);
134         return RET_SYS;
135     }
136     if ((statb.st_mode & S_IFREG) == 0) {
137         pr("Error reading info file for %s\n", bp);
138         logerror("The info file \"%s\" is not regular file\n", filename);
139         fclose(fp);
140         return RET_SYS;
141     }
142     pr("Information on:  %s    Last modification date: %s",
143        bp, ctime(&statb.st_mtime));
144     while (fgets(buf, sizeof(buf), fp) != 0)
145         pr("%s", buf);
146     (void)fclose(fp);
147     return RET_OK;
148 }
149
150 int
151 apro(void)
152 {
153     FILE *fp;
154     s_char *bp, *lbp;
155     s_char *fbuf;
156     s_char *lbuf;
157     struct dirent *dp;
158     s_char filename[1024];
159     DIR *info_dp;
160     long nf, nhf, nl, nlhl, nhl, nll;
161     int alreadyhit;
162     int lhitlim;
163
164     if (player->argp[1] == 0 || !*player->argp[1]) {
165         pr("Apropos what?\n");
166         return RET_FAIL;
167     }
168
169     lhitlim = 100;
170     if (player->argp[2]) {
171         lhitlim = atoi(player->argp[2]);
172         if (lhitlim <= 0)
173             lhitlim = 100;
174     }
175
176     info_dp = opendir(infodir);
177     if (info_dp == 0) {
178         pr("Can't open info dir \"%s\"\n", infodir);
179         return RET_SYS;
180     }
181
182     fbuf = (s_char *)malloc(256);
183     lbuf = (s_char *)malloc(256);
184     lbp = (s_char *)malloc(256);
185
186     /*
187      *  lower case search string into lbp
188      */
189     bp = player->argp[1];
190     lowerit(lbp, 256, bp);
191
192     /*
193      *  search
194      */
195     nf = nhf = nl = nhl = 0;
196     rewinddir(info_dp);
197     while ((dp = readdir(info_dp)) != 0) {
198         sprintf(filename, "%s/%s", infodir, dp->d_name);
199         fp = fopen(filename, "r");
200         alreadyhit = 0;
201         nll = nlhl = 0;
202         if (fp != NULL) {
203             while (fgets(fbuf, 256, fp)) {
204                 lowerit(lbuf, 256, fbuf);
205                 if (strstr(lbuf, lbp)) {
206                     if (!alreadyhit) {
207                         pr("*** %s ***\n", dp->d_name);
208                         alreadyhit = 1;
209                         nhf++;
210                     }
211                     fbuf[74] = '\n';
212                     fbuf[75] = 0;
213                     pr("   %s", fbuf);
214                     nlhl++;
215                     /*
216                      * break if too many lines
217                      */
218                     if ((nhl + nlhl) > lhitlim)
219                         break;
220                 }
221                 nll++;
222             }
223             fclose(fp);
224         }
225         nhl += nlhl;
226         nl += nll;
227         nf++;
228         if (nhl > lhitlim)
229             break;
230     }
231     closedir(info_dp);
232
233     free(fbuf);
234     free(lbuf);
235     free(lbp);
236
237     if ((nhl) > lhitlim) {
238         pr("Limit of %d lines exceeded\n", lhitlim);
239     }
240     pr("Found %s in %ld of %ld files and in %ld of %ld lines\n",
241        bp, nhf, nf, nhl, nl);
242     return RET_OK;
243 }
244
245 #else
246
247 int
248 info(void)
249 {
250     s_char buf[255];
251     FILE *fp;
252     s_char *bp;
253     s_char *bp2;
254     s_char filename[1024];
255
256     if (player->argp[1] == 0 || !*player->argp[1])
257         bp = "TOP";
258     else {
259         /*
260          * don't let sneaky people go outside the info directory
261          */
262         bp = player->argp[1];
263         if (NULL != (bp2 = strrchr(bp, '/')))
264             bp = ++bp2;
265         if (NULL != (bp2 = strrchr(bp, '\\')))
266             bp = ++bp2;
267         if (NULL != (bp2 = strrchr(bp, ':')))
268             bp = ++bp2;
269         if (!*bp)
270             bp = "TOP";
271     }
272
273     strncpy(filename, infodir, sizeof(filename) - 2);
274     strcat(filename, "\\");
275     strncat(filename, bp, sizeof(filename) - 1 - strlen(filename));
276     fp = fopen(filename, "r");
277     if (fp == NULL) {
278         /* may be a "partial" request.  */
279         HANDLE hDir;
280         WIN32_FIND_DATA fData;
281         int len = strlen(bp);
282         strncat(filename, "*", sizeof(filename) - 1 - strlen(filename));
283         hDir = FindFirstFile(filename, &fData);
284         if (hDir == INVALID_HANDLE_VALUE) {
285             switch (GetLastError()) {
286             case ERROR_FILE_NOT_FOUND:
287                 pr("Sorry, there is no info on %s\n", bp);
288                 return RET_FAIL;
289                 break;
290             case ERROR_PATH_NOT_FOUND:
291                 pr("Can't open info dir\n");
292                 logerror("Can't open info dir \"%s\"", infodir);
293                 break;
294             default:
295                 pr("Error reading info dir\n");
296                 logerror("Error (%d) reading info dir(%s)/file(%s)",
297                     infodir, filename, GetLastError());
298             }
299             return RET_SYS;
300         }
301         do {
302             if (((fData.dwFileAttributes == FILE_ATTRIBUTE_NORMAL) ||
303                  (fData.dwFileAttributes == FILE_ATTRIBUTE_ARCHIVE) ||
304                  (fData.dwFileAttributes == FILE_ATTRIBUTE_READONLY)) &&
305                 (strnccmp(bp, fData.cFileName, len) == 0)) {
306                 strncpy(filename, infodir, sizeof(filename) - 2);
307                 strcat(filename, "\\");
308                 strncat(filename, fData.cFileName,
309                         sizeof(filename) - 1 - strlen(filename));
310                 fp = fopen(filename, "r");
311             }
312         } while (!fp && FindNextFile(hDir, &fData));
313         FindClose(hDir);
314         if (fp == NULL) {
315             pr("Sorry, there is no info on %s\n", bp);
316             return RET_FAIL;
317         }
318     }
319     else {
320         DWORD fAttrib = GetFileAttributes(filename);
321         if ((fAttrib == (DWORD)-1) && //INVALID_FILE_ATTRIBUTES
322             (fAttrib != FILE_ATTRIBUTE_NORMAL) &&
323             (fAttrib != FILE_ATTRIBUTE_ARCHIVE) &&
324             (fAttrib != FILE_ATTRIBUTE_READONLY)) {
325             pr("Error reading info file for %s\n", bp);
326             logerror("The info file \"%s\" is not regular file\n", filename);
327             fclose(fp);
328             return RET_SYS;
329         }
330     }
331
332     pr("Information on:  %s", bp);
333     while (fgets(buf, sizeof(buf), fp) != 0)
334         pr("%s", buf);
335     (void)fclose(fp);
336     return RET_OK;
337 }
338
339 int
340 apro(void)
341 {
342     HANDLE hDir;
343     WIN32_FIND_DATA fData;
344     FILE *fp;
345     s_char *bp, *lbp;
346     s_char *fbuf;
347     s_char *lbuf;
348     s_char filename[1024];
349     long nf, nhf, nl, nlhl, nhl, nll;
350     int alreadyhit;
351     int lhitlim;
352
353     if (player->argp[1] == 0 || !*player->argp[1]) {
354         pr("Apropos what?\n");
355         return RET_FAIL;
356     }
357
358     lhitlim = 100;
359     if (player->argp[2]) {
360         lhitlim = atoi(player->argp[2]);
361         if (lhitlim <= 0)
362             lhitlim = 100;
363     }
364
365     strncpy(filename, infodir, sizeof(filename) - 3);
366     strcat(filename, "//*");
367     hDir = FindFirstFile(filename, &fData);
368     if (hDir == INVALID_HANDLE_VALUE) {
369         return RET_FAIL;
370     }
371
372     fbuf = (s_char *)malloc(256);
373     lbuf = (s_char *)malloc(256);
374     lbp = (s_char *)malloc(256);
375
376     /*
377      *  lower case search string into lbp
378      */
379     bp = player->argp[1];
380     lowerit(lbp, 256, bp);
381
382     /*
383      *  search
384      */
385     nf = nhf = nl = nhl = 0;
386     do {
387         strncpy(filename, infodir, sizeof(filename) - 3);
388         strcat(filename, "//");
389         strncat(filename, fData.cFileName,
390                 sizeof(filename) - 1 - strlen(filename));
391         fp = fopen(filename, "r");
392         alreadyhit = 0;
393         nll = nlhl = 0;
394         if (fp != NULL) {
395             while (fgets(fbuf, 256, fp)) {
396                 lowerit(lbuf, 256, fbuf);
397                 if (strstr(lbuf, lbp)) {
398                     if (!alreadyhit) {
399                         pr("*** %s ***\n", fData.cFileName);
400                         alreadyhit = 1;
401                         nhf++;
402                     }
403                     fbuf[74] = '\n';
404                     fbuf[75] = 0;
405                     pr("   %s", fbuf);
406                     nlhl++;
407                     /*
408                      * break if too many lines
409                      */
410                     if ((nhl + nlhl) > lhitlim)
411                         break;
412                 }
413                 nll++;
414             }
415             fclose(fp);
416         }
417         nhl += nlhl;
418         nl += nll;
419         nf++;
420         if (nhl > lhitlim)
421             break;
422     } while (FindNextFile(hDir, &fData));
423     FindClose(hDir);
424
425     free(fbuf);
426     free(lbuf);
427     free(lbp);
428
429     if ((nhl) > lhitlim) {
430         pr("Limit of %ld lines exceeded\n", lhitlim);
431     }
432     pr("Found %s in %ld of %ld files and in %ld of %ld lines\n",
433        bp, nhf, nf, nhl, nl);
434     return RET_OK;
435 }
436
437 #endif