source: trunk/src/sh_prelink.c @ 133

Last change on this file since 133 was 133, checked in by rainer, 12 years ago

Reentrant checksum/hash functions.

File size: 7.5 KB
Line 
1/* SAMHAIN file system integrity testing                                   */
2/* Copyright (C) 2004 Rainer Wichmann                                      */
3/*                                                                         */
4/*  This program is free software; you can redistribute it                 */
5/*  and/or modify                                                          */
6/*  it under the terms of the GNU General Public License as                */
7/*  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., 675 Mass Ave, Cambridge, MA 02139, USA.              */
19
20#include "config_xor.h"
21
22#include <string.h>
23#include <sys/types.h>
24#include <signal.h>
25
26#if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE)
27
28#include "samhain.h"
29#include "sh_tiger.h"
30#include "sh_extern.h"
31#include "sh_utils.h"
32#include "sh_unix.h"
33
34#undef  FIL__
35#define FIL__  _("sh_prelink.c")
36
37static char * prelink_path = NULL;
38static char * prelink_hash = NULL;
39
40int sh_prelink_set_path (const char * str)
41{
42  SL_ENTER(_("sh_prelink_set_path"));
43  if (prelink_path != NULL)
44    SH_FREE(prelink_path);
45  if (str[0] != '/')
46    {
47      prelink_path = NULL;
48      SL_RETURN((-1), _("sh_prelink_set_path")); 
49    }
50
51  prelink_path = sh_util_strdup(str);
52
53  SL_RETURN(0, _("sh_prelink_set_path")); 
54}
55
56int sh_prelink_set_hash (const char * str)
57{
58  size_t len;
59  SL_ENTER(_("sh_prelink_set_hash"));
60  if (prelink_hash != NULL)
61    SH_FREE(prelink_hash);
62  len = sl_strlen (str);
63  if (len != KEY_LEN)
64    {
65      prelink_hash = NULL;
66      SL_RETURN((-1), _("sh_prelink_set_hash")); 
67    }
68  prelink_hash = SH_ALLOC(len+1);
69  (void) sl_strlcpy(prelink_hash, str, len+1);
70  SL_RETURN(0, _("sh_prelink_set_hash")); 
71}
72
73int sh_prelink_iself (SL_TICKET fd, off_t size, int alert_timeout, char * path)
74{
75  long   status;
76  char   magic[4];
77  char * tmp;
78
79  /* 42 bytes is about the minimum an ELF binary might have
80   * (with plenty of hacks to reduce the size, such as interleaving
81   * the code with the header...)
82   */
83  if (size < 42)
84    return S_FALSE;
85
86  status = sl_read_timeout (fd, magic, 4, alert_timeout, SL_FALSE);
87  (void) sl_rewind(fd);
88  if (status == 4)
89    {
90      /*@-usedef@*/
91      if (magic[0] == (char) 0x7f &&
92          magic[1] == 'E'  &&
93          magic[2] == 'L'  &&
94          magic[3] == 'F')
95        return S_TRUE;
96      /*@+usedef@*/
97    }
98  else
99    {
100      tmp = sh_util_safe_name (path);
101      sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, status, MSG_E_SUBGPATH, 
102                      _("Error reading file"), _("sh_prelink_iself"), tmp);
103      SH_FREE(path);
104    }
105  return S_FALSE;
106}
107
108extern int get_the_fd (SL_TICKET ticket);
109
110static void sh_prelink_fd(sh_tas_t * task)
111{
112  SL_TICKET ticket;
113  char * tmp;
114  char hashbuf[KEYBUF_SIZE];
115
116  if (task->com_ti != (-1))
117    {
118      (void) sl_close(task->com_ti);
119      task->com_fd = -1;
120      task->com_ti = -1;
121    }
122  ticket = sl_open_read(task->command, 
123                        task->privileged == 0 ? SL_NOPRIV : SL_YESPRIV);
124  if (SL_ISERROR(ticket))
125    {
126      tmp = sh_util_safe_name (task->command);
127      sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, ticket, MSG_E_READ, tmp);
128      SH_FREE(tmp);
129      return;
130    }
131
132  if (*(task->checksum) == '\0' ||
133      0 == sl_strcmp(task->checksum, 
134                     sh_tiger_hash (task->command, ticket, 0, hashbuf, sizeof(hashbuf))))
135    {
136      task->com_fd = get_the_fd(ticket);
137      task->com_ti = ticket;
138    }
139  else
140    {
141      tmp = sh_util_safe_name (task->command);
142      sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, ticket, MSG_E_HASH, tmp);
143      SH_FREE(tmp);
144      (void) sl_close(ticket);
145    }
146  return;
147}
148
149/* returns static storage
150 */
151int sh_prelink_run (char * path, char * file_hash, int alert_timeout)
152{
153  static int      init = S_FALSE;
154  static int      args_filled = 0;
155  static sh_tas_t task;
156
157  int    status = 0;
158  char * p;
159  struct  sigaction  new_act;
160  struct  sigaction  old_act;
161
162  SL_ENTER(_("sh_prelink_run"));
163
164  /* reset if path == NULL
165   */
166  if (path == NULL)
167    {
168      if (init == S_FALSE)
169        {
170           SL_RETURN (0, _("sh_prelink_run"));
171        }
172      sh_ext_tas_free(&task);
173      init = S_FALSE;
174      args_filled = 0;
175      SL_RETURN (0, _("sh_prelink_run"));
176    }
177
178  /* initialize task structure
179   */
180  if (init == S_FALSE)
181    {
182      char dir[SH_PATHBUF];
183
184      sh_ext_tas_init(&task);
185      p = sh_unix_getUIDdir (SH_ERR_ERR, task.run_user_uid, dir, sizeof(dir));
186      if (p)
187        {
188          (void) sh_ext_tas_add_envv (&task, _("HOME"), p);
189        }
190      (void) sh_ext_tas_add_envv (&task, _("SHELL"), 
191                                  _("/bin/sh")); 
192      (void) sh_ext_tas_add_envv (&task, _("PATH"), 
193                                  _("/sbin:/usr/sbin:/bin:/usr/bin")); 
194      if (sh.timezone != NULL)
195        {
196          (void) sh_ext_tas_add_envv(&task,  "TZ", sh.timezone);
197        }
198      if (prelink_path == NULL)
199        {
200          sh_ext_tas_command(&task,  _("/usr/sbin/prelink"));
201          (void) sh_ext_tas_add_argv(&task,  _("/usr/sbin/prelink"));
202        }
203      else
204        {
205          sh_ext_tas_command(&task,  prelink_path);
206          (void) sh_ext_tas_add_argv(&task,  prelink_path);
207        }
208      args_filled = sh_ext_tas_add_argv(&task,  _("--verify"));
209
210      if (prelink_hash != NULL)
211        {
212          (void) sl_strlcpy(task.checksum, prelink_hash, KEY_LEN+1);
213        }
214      task.rw = 'r';
215      task.fork_twice = S_FALSE;
216
217      sh_prelink_fd(&task);
218
219      init = S_TRUE;
220    }
221
222  /* rm filename arg if set; fill in filename
223   */
224  if (args_filled == 3)
225    args_filled = sh_ext_tas_rm_argv(&task);
226  if (args_filled == 2)
227    args_filled = sh_ext_tas_add_argv(&task, path);
228  else
229    {
230      sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, args_filled, MSG_E_SUBGEN, 
231                      _("Bad argument count"), _("sh_prelink_run"));
232      SL_RETURN ((-1), _("sh_prelink_run"));
233    }
234
235  /* open pipe
236   */
237  status = sh_ext_popen(&task);
238  if (status != 0)
239    {
240      sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, status, MSG_E_SUBGEN, 
241                      _("Could not open pipe"), _("sh_prelink_run"));
242      SL_RETURN ((-1), _("sh_prelink_run"));
243    }
244
245  if (SL_ISERROR(task.pipeTI))
246    {
247      sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, task.pipeTI, MSG_E_SUBGEN, 
248                      _("No valid ticket"), _("sh_prelink_run"));
249      SL_RETURN ((-1), _("sh_prelink_run"));
250    }
251
252  /* ignore SIGPIPE (instead get EPIPE if connection is closed)
253   */
254  new_act.sa_handler = SIG_IGN;
255  (void) retry_sigaction (FIL__, __LINE__, SIGPIPE, &new_act, &old_act);
256
257  /* read from pipe
258   */
259  sl_read_timeout_prep (task.pipeTI);
260
261  {
262    char hashbuf[KEYBUF_SIZE];
263    sl_strlcpy(file_hash,
264               sh_tiger_generic_hash (path, task.pipeTI, TIGER_NOLIM, alert_timeout,
265                                      hashbuf, sizeof(hashbuf)),
266               KEY_LEN+1);
267  }
268
269  /* restore old signal handler
270   */
271  (void) retry_sigaction (FIL__, __LINE__, SIGPIPE, &old_act, NULL);
272
273  /* close pipe and return exit status
274   */
275  status = sh_ext_pclose(&task);
276  SL_RETURN ((status), _("sh_prelink_run"));
277}
278/* defined(SH_WITH_CLIENT) || defined(SH_STANDALONE)
279 */
280#endif
Note: See TracBrowser for help on using the repository browser.