source: trunk/src/sh_userfiles.c@ 173

Last change on this file since 173 was 149, checked in by katerina, 17 years ago

Make sh_hash.c thread-safe, remove plenty of tiny allocations, improve sh_mem_dump, modify port check to run as thread, and fix unsetting of sh_thread_pause_flag (was too early).

File size: 12.7 KB
Line 
1/*
2 * File: sh_userfiles.c
3 * Desc: A module for Samhain; adds files in user directories to the check list
4 * Auth: Jerry Connolly <jerry.connolly@eircom.net>
5 */
6/* This program is free software; you can redistribute it */
7/* and/or modify */
8/* it under the terms of the GNU General Public License as */
9/* published by */
10/* the Free Software Foundation; either version 2 of the License, or */
11/* (at your option) any later version. */
12/* */
13/* This program is distributed in the hope that it will be useful, */
14/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
15/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
16/* GNU General Public License for more details. */
17/* */
18/* You should have received a copy of the GNU General Public License */
19/* along with this program; if not, write to the Free Software */
20/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
21
22#include "config_xor.h"
23
24#include <stdio.h>
25#include <string.h>
26#include <ctype.h>
27#include <limits.h>
28#include <sys/types.h>
29#include <sys/stat.h>
30#include <pwd.h>
31
32#include "samhain.h"
33#include "sh_modules.h"
34#include "sh_userfiles.h"
35#include "sh_utils.h"
36#include "sh_schedule.h"
37#include "sh_error.h"
38#include "sh_hash.h"
39#include "sh_files.h"
40#define SH_NEED_PWD_GRP 1
41#include "sh_static.h"
42#include "sh_pthread.h"
43
44#ifdef SH_USE_USERFILES
45
46#define FIL__ _("sh_userfiles.c")
47
48/* We won't want to build this into yule */
49#if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)
50
51static int ShUserfilesActive = S_TRUE;
52
53struct userfileslist {
54 char filename[PATH_MAX];
55 int level;
56
57 struct userfileslist *next;
58};
59
60struct userhomeslist {
61 char *pw_dir;
62
63 struct userhomeslist *next;
64};
65
66struct useruidlist {
67 unsigned long lower;
68 unsigned long upper;
69 struct useruidlist *next;
70};
71
72static struct userfileslist *userFiles = NULL;
73static struct userhomeslist *userHomes = NULL;
74static struct useruidlist *userUids = NULL;
75
76static void sh_userfiles_free_fileslist(struct userfileslist *head);
77static void sh_userfiles_free_homeslist(struct userhomeslist *head);
78static void sh_userfiles_free_uidslist (struct useruidlist *head);
79
80sh_rconf sh_userfiles_table[] = {
81 {
82 N_("userfilesname"),
83 sh_userfiles_add_file,
84 },
85 {
86 N_("userfilesactive"),
87 sh_userfiles_set_active,
88 },
89 {
90 N_("userfilescheckuids"),
91 sh_userfiles_set_uid,
92 },
93 {
94 NULL,
95 NULL
96 }
97};
98
99static int sh_userfiles_check_uid (unsigned long uid)
100{
101 struct useruidlist * uids = userUids;
102
103 /* default is to include all
104 */
105 if (userUids == NULL)
106 return 1;
107
108 while (uids)
109 {
110 if ((uids->upper != 0) && (uid >= uids->lower) && (uid <= uids->upper))
111 return 1;
112 if ((uids->upper == 0) && (uid == uids->lower))
113 return 1;
114 uids = uids->next;
115 }
116 return 0;
117}
118
119int sh_userfiles_set_uid (const char * str)
120{
121 char * end;
122 const char * p = str;
123 unsigned long lower;
124 unsigned long upper = 0;
125 struct useruidlist * uids;
126
127 while ((p != NULL) && (*p != '\0'))
128 {
129 lower = strtoul(p, &end, 10);
130 if ( (lower == ULONG_MAX) || (end == p))
131 return -1;
132 p = end;
133 if (*p == '-')
134 {
135 ++p;
136 if (*p == '\0')
137 {
138 upper = ULONG_MAX;
139 p = NULL;
140 }
141 else
142 {
143 upper = strtoul(p, &end, 10);
144 if ( (upper == ULONG_MAX) || (end == p))
145 return -1;
146 p = end;
147 if ( (*p != ',') && (*p != '\0'))
148 return -1;
149 if (*p != '\0')
150 ++p;
151 }
152 }
153 else if (*p == '\0')
154 {
155 upper = 0;
156 p = NULL;
157 }
158 else if ((*p == ',') || (*p == ' ') || (*p == '\t'))
159 {
160 upper = 0;
161 ++p;
162 }
163 else
164 {
165 upper = strtoul(p, &end, 10);
166 if ( (upper == ULONG_MAX) || (end == p))
167 return -1;
168 p = end;
169 if ( (*p != ',') && (*p != ' ') && (*p != '\t') && (*p != '\0') )
170 return -1;
171 if (*p != '\0')
172 ++p;
173 }
174 uids = SH_ALLOC(sizeof(struct useruidlist));
175 uids->lower = lower;
176 uids->upper = upper;
177 uids->next = userUids;
178 userUids = uids;
179 /* fprintf(stderr, "range %lu %lu\n", lower, upper); */
180 }
181 return 0;
182}
183
184/* Add 'c' to the list of files (userFiles) relative to any given HOME
185 * directory that should be checked. */
186
187int sh_userfiles_add_file(const char *c) {
188 struct userfileslist *new;
189 char *s, *orig;
190 char *user_filename;
191
192 int default_level = SH_LEVEL_NOIGNORE;
193 char *separator = " ";
194
195 SL_ENTER(_("sh_userfiles_add_file"));
196
197 if( c == NULL )
198 SL_RETURN(-1, _("sh_userfiles_add_file") );
199
200 s = sh_util_strdup(c); /* Maybe c is needed elsewhere */
201 orig = s;
202
203 user_filename = sh_util_strsep(&s, separator);
204
205 if( user_filename == NULL || strlen(user_filename) > PATH_MAX )
206 SL_RETURN(-1, _("sh_userfiles_add_file") );
207
208 new = SH_ALLOC(sizeof(struct userfileslist));
209
210 (void) sl_strlcpy(new->filename, user_filename, PATH_MAX);
211 new->next = userFiles;
212 userFiles = new;
213
214 /* order is important here, since 'log' would match on 'glog'
215 * So, compare longest strings first */
216 if( s == NULL ) /* The default */ new->level = default_level;
217 else if ( strstr(s, "attributes")!= NULL ) new->level = SH_LEVEL_ATTRIBUTES;
218 else if ( strstr(s, "allignore") != NULL ) new->level = SH_LEVEL_ALLIGNORE;
219 else if ( strstr(s, "noignore") != NULL ) new->level = SH_LEVEL_NOIGNORE;
220 else if ( strstr(s, "logfiles") != NULL ) new->level = SH_LEVEL_LOGFILES;
221 else if ( strstr(s, "readonly") != NULL ) new->level = SH_LEVEL_READONLY;
222 else if ( strstr(s, "loggrow") != NULL ) new->level = SH_LEVEL_LOGGROW;
223 else if ( strstr(s, "user0") != NULL ) new->level = SH_LEVEL_USER0;
224 else if ( strstr(s, "user1") != NULL ) new->level = SH_LEVEL_USER1;
225 else if ( strstr(s, "user2") != NULL ) new->level = SH_LEVEL_USER2;
226 else if ( strstr(s, "user3") != NULL ) new->level = SH_LEVEL_USER3;
227 else if ( strstr(s, "user4") != NULL ) new->level = SH_LEVEL_USER4;
228 else if ( strstr(s, "prelink") != NULL ) new->level = SH_LEVEL_PRELINK;
229 else /* The default */ new->level = default_level;
230
231 SH_FREE(orig);
232
233 SL_RETURN(0, _("sh_userfiles_add_file") );
234}
235
236/* Decide if we're active.
237 */
238int sh_userfiles_set_active(const char *c) {
239 int value;
240
241 SL_ENTER(_("sh_userfiles_set_active"));
242 value = sh_util_flagval(c, &ShUserfilesActive);
243 SL_RETURN((value), _("sh_userfiles_set_active"));
244}
245
246/* Build the list of users, then use this to construct the filenames to
247 * be checked. */
248int sh_userfiles_init(struct mod_type * arg) {
249 struct passwd *cur_user;
250 struct userhomeslist *end;
251 struct userhomeslist *new;
252 struct userhomeslist *homes;
253 (void) arg;
254
255 SL_ENTER(_("sh_userfiles_init"));
256
257 /* We need to free anything allocated by the configuration functions if
258 * we find that the module is to be left inactive - otherwise _reconf()
259 * won't quite work. */
260 if( ShUserfilesActive == S_FALSE ) {
261 sh_userfiles_free_homeslist(userHomes);
262 sh_userfiles_free_fileslist(userFiles);
263 userHomes = NULL;
264 userFiles = NULL;
265 SL_RETURN(-1, _("sh_userfiles_init"));
266 }
267
268 /* We build a list in here because the samhain internals want to use
269 * getpwent() too */
270 SH_MUTEX_LOCK(mutex_pwent);
271 /*@-unrecog@*/
272 sh_setpwent();
273 /*@+unrecog@*/
274 while( ( cur_user = /*@-unrecog@*/sh_getpwent()/*@+unrecog@*/ ) != NULL ) {
275 int found = 0;
276
277 if (0 == sh_userfiles_check_uid( (unsigned long) cur_user->pw_uid))
278 continue;
279
280 for( end = userHomes; end != NULL; end = end->next ) {
281 if( sl_strcmp( end->pw_dir, cur_user->pw_dir) == 0 ) {
282 found = 1; /* Found a match, so flag it and stop searching */
283 break;
284 }
285 }
286
287 if( found == 0 ) {
288 /* Didn't find it, so add to the front of the list */
289 new = SH_ALLOC(sizeof(struct userhomeslist) );
290 new->next = userHomes;
291 new->pw_dir = sh_util_strdup(cur_user->pw_dir);
292
293 userHomes = new;
294 }
295 }
296 sh_endpwent();
297 SH_MUTEX_UNLOCK(mutex_pwent);
298
299 for (homes = userHomes; homes != NULL; homes = homes->next ) {
300 struct userfileslist *file_ptr;
301 char filepath[PATH_MAX];
302
303 for (file_ptr = userFiles; file_ptr != NULL; file_ptr = file_ptr->next) {
304 (void) sl_strncpy(filepath, homes->pw_dir, PATH_MAX);
305 (void) sl_strncat(filepath, "/", PATH_MAX);
306 (void) sl_strncat(filepath, file_ptr->filename, PATH_MAX);
307
308 switch(file_ptr->level) {
309 case SH_LEVEL_READONLY:
310 (void) sh_files_pushfile_ro(filepath);
311 break;
312 case SH_LEVEL_LOGFILES:
313 (void) sh_files_pushfile_log(filepath);
314 break;
315 case SH_LEVEL_LOGGROW:
316 (void) sh_files_pushfile_glog(filepath);
317 break;
318 case SH_LEVEL_NOIGNORE:
319 (void) sh_files_pushfile_noig(filepath);
320 break;
321 case SH_LEVEL_ALLIGNORE:
322 (void) sh_files_pushfile_allig(filepath);
323 break;
324 case SH_LEVEL_ATTRIBUTES:
325 (void) sh_files_pushfile_attr(filepath);
326 break;
327 case SH_LEVEL_USER0:
328 (void) sh_files_pushfile_user0(filepath);
329 break;
330 case SH_LEVEL_USER1:
331 (void) sh_files_pushfile_user1(filepath);
332 break;
333 case SH_LEVEL_USER2:
334 (void) sh_files_pushfile_user2(filepath);
335 break;
336 case SH_LEVEL_USER3:
337 (void) sh_files_pushfile_user3(filepath);
338 break;
339 case SH_LEVEL_USER4:
340 (void) sh_files_pushfile_user4(filepath);
341 break;
342 case SH_LEVEL_PRELINK:
343 (void) sh_files_pushfile_prelink(filepath);
344 break;
345 default: /* Should not reach here */
346 break;
347 }
348 }
349 }
350
351 SL_RETURN(0, _("sh_userfiles_init"));
352}
353
354/* This is pretty much NULL; we don't do anything in our checking routine,
355 * so we never need to run it. Just use tcurrent to avoid compiler warnings. */
356int sh_userfiles_timer(time_t tcurrent) {
357 SL_ENTER(_("sh_userfiles_timer"));
358 tcurrent = 0;
359 SL_RETURN((int)tcurrent, _("sh_userfiles_timer"));
360}
361
362int sh_userfiles_check(void) {
363 SL_ENTER(_("sh_userfiles_check"));
364 SL_RETURN(0, _("sh_userfiles_check"));
365}
366
367/* Free our lists and the associated memory */
368
369int sh_userfiles_cleanup(void) {
370 SL_ENTER(_("sh_userfiles_cleanup"));
371
372 sh_userfiles_free_homeslist(userHomes);
373 sh_userfiles_free_fileslist(userFiles);
374 sh_userfiles_free_uidslist (userUids);
375
376 SL_RETURN(0, _("sh_userfiles_cleanup"));
377}
378
379/* As with sh_userfiles_cleanup, but in preparation for re-reading the
380 * configuration files */
381
382int sh_userfiles_reconf(void) {
383 SL_ENTER(_("sh_userfiles_reconf"));
384
385 sh_userfiles_free_homeslist(userHomes);
386 sh_userfiles_free_fileslist(userFiles);
387 sh_userfiles_free_uidslist (userUids);
388
389 userHomes = NULL;
390 userFiles = NULL;
391
392 ShUserfilesActive = S_TRUE;
393
394 SL_RETURN(0, _("sh_userfiles_reconf"));
395}
396
397/* Recurse to the end of the list and then free the data as we return
398 * back up towards the start, making sure to free any strdupped strings
399 */
400
401static void sh_userfiles_free_homeslist(struct userhomeslist *head) {
402 if( head != NULL ) {
403 sh_userfiles_free_homeslist(head->next);
404 SH_FREE(head->pw_dir);
405 SH_FREE(head);
406 }
407}
408
409/* Recurse to the end of the list and then free the data as we return
410 * back up towards the start */
411
412static void sh_userfiles_free_fileslist(struct userfileslist *head) {
413 if( head != NULL ) {
414 sh_userfiles_free_fileslist(head->next);
415 SH_FREE(head);
416 }
417}
418
419/* Recurse to the end of the list and then free the data as we return
420 * back up towards the start */
421
422static void sh_userfiles_free_uidslist(struct useruidlist *head) {
423 if( head != NULL ) {
424 sh_userfiles_free_uidslist(head->next);
425 SH_FREE(head);
426 }
427}
428
429/* #if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE) */
430#endif
431
432/* #ifdef SH_USE_USERFILES */
433#endif
Note: See TracBrowser for help on using the repository browser.