source: trunk/src/sh_prelink.c@ 225

Last change on this file since 225 was 192, checked in by katerina, 16 years ago

Fixes for cygwin, and improved error diagnostics (tickets #126, #127, #128).

File size: 7.8 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 char errbuf[SH_ERRBUF_SIZE];
127 char errbuf2[SH_ERRBUF_SIZE];
128 sh_error_message(errno, errbuf2, sizeof(errbuf2));
129 sl_strlcpy(errbuf, sl_error_string(ticket), sizeof(errbuf));
130 tmp = sh_util_safe_name (task->command);
131 sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, ticket, MSG_E_READ, errbuf, errbuf2, tmp);
132 SH_FREE(tmp);
133 return;
134 }
135
136 if (*(task->checksum) == '\0' ||
137 0 == sl_strcmp(task->checksum,
138 sh_tiger_hash (task->command, ticket, TIGER_NOLIM, hashbuf, sizeof(hashbuf))))
139 {
140 task->com_fd = get_the_fd(ticket);
141 task->com_ti = ticket;
142 }
143 else
144 {
145 tmp = sh_util_safe_name (task->command);
146 sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, ticket, MSG_E_HASH, tmp);
147 SH_FREE(tmp);
148 (void) sl_close(ticket);
149 }
150 return;
151}
152
153/* returns static storage
154 */
155int sh_prelink_run (char * path, char * file_hash, int alert_timeout)
156{
157 static int init = S_FALSE;
158 static int args_filled = 0;
159 static sh_tas_t task;
160
161 int status = 0;
162 char * p;
163 struct sigaction new_act;
164 struct sigaction old_act;
165
166 SL_ENTER(_("sh_prelink_run"));
167
168 /* reset if path == NULL
169 */
170 if (path == NULL)
171 {
172 if (init == S_FALSE)
173 {
174 SL_RETURN (0, _("sh_prelink_run"));
175 }
176 sh_ext_tas_free(&task);
177 init = S_FALSE;
178 args_filled = 0;
179 SL_RETURN (0, _("sh_prelink_run"));
180 }
181
182 /* initialize task structure
183 */
184 if (init == S_FALSE)
185 {
186 char dir[SH_PATHBUF];
187
188 sh_ext_tas_init(&task);
189 p = sh_unix_getUIDdir (SH_ERR_ERR, task.run_user_uid, dir, sizeof(dir));
190 if (p)
191 {
192 (void) sh_ext_tas_add_envv (&task, _("HOME"), p);
193 }
194 (void) sh_ext_tas_add_envv (&task, _("SHELL"),
195 _("/bin/sh"));
196 (void) sh_ext_tas_add_envv (&task, _("PATH"),
197 _("/sbin:/usr/sbin:/bin:/usr/bin"));
198 if (sh.timezone != NULL)
199 {
200 (void) sh_ext_tas_add_envv(&task, "TZ", sh.timezone);
201 }
202 if (prelink_path == NULL)
203 {
204 sh_ext_tas_command(&task, _("/usr/sbin/prelink"));
205 (void) sh_ext_tas_add_argv(&task, _("/usr/sbin/prelink"));
206 }
207 else
208 {
209 sh_ext_tas_command(&task, prelink_path);
210 (void) sh_ext_tas_add_argv(&task, prelink_path);
211 }
212 args_filled = sh_ext_tas_add_argv(&task, _("--verify"));
213
214 if (prelink_hash != NULL)
215 {
216 (void) sl_strlcpy(task.checksum, prelink_hash, KEY_LEN+1);
217 }
218 task.rw = 'r';
219 task.fork_twice = S_FALSE;
220
221 sh_prelink_fd(&task);
222
223 init = S_TRUE;
224 }
225
226 /* rm filename arg if set; fill in filename
227 */
228 if (args_filled == 3)
229 args_filled = sh_ext_tas_rm_argv(&task);
230 if (args_filled == 2)
231 args_filled = sh_ext_tas_add_argv(&task, path);
232 else
233 {
234 sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, args_filled, MSG_E_SUBGEN,
235 _("Bad argument count"), _("sh_prelink_run"));
236 SL_RETURN ((-1), _("sh_prelink_run"));
237 }
238
239 /* open pipe
240 */
241 status = sh_ext_popen(&task);
242 if (status != 0)
243 {
244 sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, status, MSG_E_SUBGEN,
245 _("Could not open pipe"), _("sh_prelink_run"));
246 SL_RETURN ((-1), _("sh_prelink_run"));
247 }
248
249 if (SL_ISERROR(task.pipeTI))
250 {
251 sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, task.pipeTI, MSG_E_SUBGEN,
252 _("No valid ticket"), _("sh_prelink_run"));
253 SL_RETURN ((-1), _("sh_prelink_run"));
254 }
255
256 /* ignore SIGPIPE (instead get EPIPE if connection is closed)
257 */
258 new_act.sa_handler = SIG_IGN;
259 (void) retry_sigaction (FIL__, __LINE__, SIGPIPE, &new_act, &old_act);
260
261 /* read from pipe
262 */
263 sl_read_timeout_prep (task.pipeTI);
264
265 {
266 char hashbuf[KEYBUF_SIZE];
267 UINT64 length_nolim = TIGER_NOLIM;
268 sl_strlcpy(file_hash,
269 sh_tiger_generic_hash (path, task.pipeTI, &length_nolim, alert_timeout,
270 hashbuf, sizeof(hashbuf)),
271 KEY_LEN+1);
272 }
273
274 /* restore old signal handler
275 */
276 (void) retry_sigaction (FIL__, __LINE__, SIGPIPE, &old_act, NULL);
277
278 /* close pipe and return exit status
279 */
280 status = sh_ext_pclose(&task);
281 SL_RETURN ((status), _("sh_prelink_run"));
282}
283/* defined(SH_WITH_CLIENT) || defined(SH_STANDALONE)
284 */
285#endif
Note: See TracBrowser for help on using the repository browser.