source: trunk/athena/etc/athinfod/athinfod.c @ 25692

Revision 25692, 8.0 KB checked in by jdreed, 12 years ago (diff)
In athinfod: * Free memory correctly
Line 
1/* Copyright 1998 by the Massachusetts Institute of Technology.
2 *
3 * Permission to use, copy, modify, and distribute this
4 * software and its documentation for any purpose and without
5 * fee is hereby granted, provided that the above copyright
6 * notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting
8 * documentation, and that the name of M.I.T. not be used in
9 * advertising or publicity pertaining to distribution of the
10 * software without specific, written prior permission.
11 * M.I.T. makes no representations about the suitability of
12 * this software for any purpose.  It is provided "as is"
13 * without express or implied warranty.
14 */
15
16static const char rcsid[] = "$Id: athinfod.c,v 1.3 1999-10-19 20:22:56 danw Exp $";
17
18#include <sys/types.h>
19#include <sys/stat.h>
20#include <sys/socket.h>
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24#include <ctype.h>
25#include <unistd.h>
26#include <fcntl.h>
27#include <dirent.h>
28#include <fnmatch.h>
29#include <errno.h>
30
31#define PATH_ATHINFO_DEFS "/etc/athena/athinfo.defs"
32#define PATH_ATHINFO_ACCESS "/etc/athena/athinfo.access"
33#define PATH_ATHINFO_DEFS_D "/etc/athena/athinfo.defs.d"
34#define ATHINFO_DEFS_D_WILDCARD "*.defs" /* Files to be read in defs.d */
35
36static const char *read_query(void);
37static void shutdown_input(void);
38static const char *get_definition(const char *query);
39static void check_enabled(const char *query);
40static int first_field_matches(const char *s, const char *word);
41static const char *skip_spaces(const char *p);
42static const char *skip_nonspaces(const char *p);
43static int read_line(FILE *fp, char **buf, int *bufsize);
44static void *emalloc(size_t size);
45static void *erealloc(void *ptr, size_t size);
46
47int main(int argc, char **argv)
48{
49  const char *query, *cmd;
50
51  query = read_query();
52  shutdown_input();
53  cmd = get_definition(query);
54  check_enabled(query);
55  execl("/bin/sh", "sh", "-c", cmd, (char *) NULL);
56  fprintf(stderr, "athinfod: cannot run shell, aborting.\n");
57  return 1;
58}
59
60/* Read the query from stdin and validate it. */
61static const char *read_query(void)
62{
63  char *line = NULL;
64  int linesize;
65  const char *p;
66
67  if (read_line(stdin, &line, &linesize) != 0)
68    {
69      fprintf(stderr, "athinfod: couldn't read query.\n");
70      exit(0);
71    }
72
73  /* Make sure the query consists of printable nonspace characters. */
74  for (p = line; *p; p++)
75    {
76      if (!isprint((unsigned char)*p) || isspace((unsigned char)*p))
77        {
78          fprintf(stderr, "athinfod: invalid query.\n");
79          exit(0);
80        }
81    }
82  return line;
83}
84
85/* Shut down the input side of the inetd socket and repoint stdin at
86 * /dev/null.  This eliminates the possibility of malicious input
87 * affecting the commands we execute.
88 */
89static void shutdown_input(void)
90{
91  int fd;
92
93  shutdown(STDIN_FILENO, 0);
94  close(STDIN_FILENO);
95  fd = open("/dev/null", O_RDONLY);
96  if (fd == -1)
97    {
98      fprintf(stderr, "athinfod: cannot open /dev/null, aborting.\n");
99      exit(1);
100    }
101  if (fd != STDIN_FILENO)
102    {
103      dup2(fd, STDIN_FILENO);
104      close(fd);
105    }
106}
107
108/* Read the definition of query from the specified file. */
109static const char *get_definition_from_file(const char *query,
110                                            const char *filepath)
111{
112  char *line = NULL;
113  int linesize;
114  FILE *fp;
115
116  fp = fopen(filepath, "r");
117  if (!fp)
118    {
119      fprintf(stderr,
120              "athinfod: cannot open %s (%s), aborting.\n", filepath, strerror(errno));
121      exit(1);
122    }
123
124  while (read_line(fp, &line, &linesize) == 0)
125    {
126      /* Ignore comment lines. */
127      if (*line == '#')
128        continue;
129
130      if (first_field_matches(line, query))
131        {
132          fclose(fp);
133          return skip_spaces(skip_nonspaces(line));
134        }
135    }
136
137  fclose(fp);
138  return NULL;
139}
140
141static int defs_file_filter(const struct dirent *entry)
142{
143  return fnmatch(ATHINFO_DEFS_D_WILDCARD, entry->d_name, 0) == 0;
144}
145
146static const char *get_definition(const char *query)
147{
148  const char *definition;
149  definition = get_definition_from_file(query, PATH_ATHINFO_DEFS);
150  if (definition != NULL)
151    return definition;
152 
153  struct dirent **namelist;
154  int numfiles, i;
155  numfiles = scandir(PATH_ATHINFO_DEFS_D, &namelist,
156              defs_file_filter, alphasort);
157  if (numfiles < 0) {
158    if (errno != ENOENT) {
159      fprintf(stderr, "athinfod: %s while scanning %s.\n",
160              strerror(errno), PATH_ATHINFO_DEFS_D);
161      exit(1);
162    }
163  } else {
164    for (i = 0; i < numfiles; i++) {
165      int len;
166      char path[PATH_MAX];
167      len = snprintf(path, sizeof(path), "%s/%s", PATH_ATHINFO_DEFS_D,
168                     namelist[i]->d_name);
169      if (len < 0 || len >= (int)sizeof(path))
170        /* Should we print an error here?  I don't think so. */
171        continue;
172      definition = get_definition_from_file(query, path);
173      if (definition != NULL)
174        break;
175    }
176  }
177
178  for (i = 0; i < numfiles; i++)
179    free(namelist[i]);
180  free(namelist);
181
182  if (definition != NULL)
183    return definition;
184  fprintf(stderr, "athinfod: unrecognized query.\n");
185  exit(0);
186}
187
188/* See if this command is enabled. */
189static void check_enabled(const char *query)
190{
191  char *line = NULL;
192  int linesize, enabled = 0, val;
193  FILE *fp;
194  const char *p;
195
196  fp = fopen(PATH_ATHINFO_ACCESS, "r");
197  if (!fp)
198    {
199      fprintf(stderr,
200              "athinfod: cannot open athinfo access file, aborting.\n");
201      exit(1);
202    }
203
204  while (read_line(fp, &line, &linesize) == 0)
205    {
206      /* Only pay attention to lines starting with "enable" or "disable". */
207      if (first_field_matches(line, "enable"))
208        val = 1;
209      else if (first_field_matches(line, "disable"))
210        val = 0;
211      else
212        continue;
213
214      /* If we find an exact match, stop.  If we find a glob match,
215       * accept that value for now but hold out for an exact match.
216       * (This means if there are conflicting lines in the config
217       * file, we take the first exact match but the last glob match.
218       * Oh well.)
219       */
220      p = skip_spaces(skip_nonspaces(line));
221      if (first_field_matches(p, query))
222        {
223          enabled = val;
224          break;
225        }
226      else if (first_field_matches(p, "*"))
227        enabled = val;
228    }
229
230  fclose(fp);
231  free(line);
232  if (!enabled)
233    {
234      fprintf(stderr, "athinfod: query disabled.\n");
235      exit(0);
236    }
237}
238
239static int first_field_matches(const char *s, const char *word)
240{
241  int len = strlen(word);
242
243  return (strncasecmp(s, word, len) == 0 &&
244          (isspace((unsigned char)s[len]) || !s[len]));
245}
246
247static const char *skip_spaces(const char *p)
248{
249  while (isspace((unsigned char)*p))
250    p++;
251  return p;
252}
253
254static const char *skip_nonspaces(const char *p)
255{
256  while (*p && !isspace((unsigned char)*p))
257    p++;
258  return p;
259}
260
261/* Read a line from a file into a dynamically allocated buffer,
262 * zeroing the trailing newline if there is one.  The calling routine
263 * may call read_line multiple times with the same buf and bufsize
264 * pointers; *buf will be reallocated and *bufsize adjusted as
265 * appropriate.  The initial value of *buf should be NULL.  After the
266 * calling routine is done reading lines, it should free *buf.  This
267 * function returns 0 if a line was successfully read, 1 if the file
268 * ended, and -1 if there was an I/O error.
269 */
270static int read_line(FILE *fp, char **buf, int *bufsize)
271{
272  char *newbuf;
273  int offset = 0, len;
274
275  if (*buf == NULL)
276    {
277      *buf = emalloc(128);
278      *bufsize = 128;
279    }
280
281  while (1)
282    {
283      if (!fgets(*buf + offset, *bufsize - offset, fp))
284        return (offset != 0) ? 0 : (ferror(fp)) ? -1 : 1;
285      len = offset + strlen(*buf + offset);
286      if ((*buf)[len - 1] == '\n')
287        {
288          (*buf)[len - 1] = 0;
289          if (len > 1 && (*buf)[len - 2] == '\r')
290            (*buf)[len - 2] = 0;
291          return 0;
292        }
293      offset = len;
294
295      /* Allocate more space. */
296      newbuf = erealloc(*buf, *bufsize * 2);
297      *buf = newbuf;
298      *bufsize *= 2;
299    }
300}
301
302static void *emalloc(size_t size)
303{
304  void *ptr;
305
306  ptr = malloc(size);
307  if (!ptr)
308    {
309      fprintf(stderr, "athinfod: malloc failure, aborting.\n");
310      exit(1);
311    }
312  return ptr;
313}
314
315void *erealloc(void *ptr, size_t size)
316{
317  ptr = realloc(ptr, size);
318  if (!ptr)
319    {
320      fprintf(stderr, "athinfod: realloc failure, aborting.\n");
321      exit(1);
322    }
323  return ptr;
324}
Note: See TracBrowser for help on using the repository browser.