source: trunk/src/sh_userfiles.c@ 582

Last change on this file since 582 was 239, checked in by katerina, 15 years ago

Fix for ticket #159

File size: 12.8 KB
RevLine 
[1]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"
[111]40#define SH_NEED_PWD_GRP 1
41#include "sh_static.h"
[137]42#include "sh_pthread.h"
[1]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
[68]119int sh_userfiles_set_uid (const char * str)
[1]120{
121 char * end;
[68]122 const char * p = str;
[1]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
[68]187int sh_userfiles_add_file(const char *c) {
[1]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;
[203]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;
[1]229 else /* The default */ new->level = default_level;
230
231 SH_FREE(orig);
232
233 SL_RETURN(0, _("sh_userfiles_add_file") );
234}
235
[68]236/* Decide if we're active.
237 */
238int sh_userfiles_set_active(const char *c) {
[1]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. */
[140]248int sh_userfiles_init(struct mod_type * arg) {
[1]249 struct passwd *cur_user;
250 struct userhomeslist *end;
251 struct userhomeslist *new;
252 struct userhomeslist *homes;
[227]253 char * filepath;
[140]254 (void) arg;
[1]255
256 SL_ENTER(_("sh_userfiles_init"));
257
258 /* We need to free anything allocated by the configuration functions if
259 * we find that the module is to be left inactive - otherwise _reconf()
260 * won't quite work. */
261 if( ShUserfilesActive == S_FALSE ) {
262 sh_userfiles_free_homeslist(userHomes);
263 sh_userfiles_free_fileslist(userFiles);
264 userHomes = NULL;
265 userFiles = NULL;
266 SL_RETURN(-1, _("sh_userfiles_init"));
267 }
268
269 /* We build a list in here because the samhain internals want to use
270 * getpwent() too */
[134]271 SH_MUTEX_LOCK(mutex_pwent);
[1]272 /*@-unrecog@*/
[111]273 sh_setpwent();
[1]274 /*@+unrecog@*/
[111]275 while( ( cur_user = /*@-unrecog@*/sh_getpwent()/*@+unrecog@*/ ) != NULL ) {
[1]276 int found = 0;
277
278 if (0 == sh_userfiles_check_uid( (unsigned long) cur_user->pw_uid))
279 continue;
280
281 for( end = userHomes; end != NULL; end = end->next ) {
282 if( sl_strcmp( end->pw_dir, cur_user->pw_dir) == 0 ) {
283 found = 1; /* Found a match, so flag it and stop searching */
284 break;
285 }
286 }
287
288 if( found == 0 ) {
289 /* Didn't find it, so add to the front of the list */
290 new = SH_ALLOC(sizeof(struct userhomeslist) );
291 new->next = userHomes;
292 new->pw_dir = sh_util_strdup(cur_user->pw_dir);
293
294 userHomes = new;
295 }
296 }
[134]297 sh_endpwent();
298 SH_MUTEX_UNLOCK(mutex_pwent);
[1]299
[227]300 filepath = SH_ALLOC(PATH_MAX);
301
[1]302 for (homes = userHomes; homes != NULL; homes = homes->next ) {
303 struct userfileslist *file_ptr;
304
305 for (file_ptr = userFiles; file_ptr != NULL; file_ptr = file_ptr->next) {
306 (void) sl_strncpy(filepath, homes->pw_dir, PATH_MAX);
307 (void) sl_strncat(filepath, "/", PATH_MAX);
308 (void) sl_strncat(filepath, file_ptr->filename, PATH_MAX);
309
310 switch(file_ptr->level) {
311 case SH_LEVEL_READONLY:
312 (void) sh_files_pushfile_ro(filepath);
313 break;
314 case SH_LEVEL_LOGFILES:
315 (void) sh_files_pushfile_log(filepath);
316 break;
317 case SH_LEVEL_LOGGROW:
318 (void) sh_files_pushfile_glog(filepath);
319 break;
320 case SH_LEVEL_NOIGNORE:
321 (void) sh_files_pushfile_noig(filepath);
322 break;
323 case SH_LEVEL_ALLIGNORE:
324 (void) sh_files_pushfile_allig(filepath);
325 break;
326 case SH_LEVEL_ATTRIBUTES:
327 (void) sh_files_pushfile_attr(filepath);
328 break;
329 case SH_LEVEL_USER0:
330 (void) sh_files_pushfile_user0(filepath);
331 break;
332 case SH_LEVEL_USER1:
333 (void) sh_files_pushfile_user1(filepath);
334 break;
[27]335 case SH_LEVEL_USER2:
336 (void) sh_files_pushfile_user2(filepath);
337 break;
338 case SH_LEVEL_USER3:
339 (void) sh_files_pushfile_user3(filepath);
340 break;
341 case SH_LEVEL_USER4:
342 (void) sh_files_pushfile_user4(filepath);
343 break;
[1]344 case SH_LEVEL_PRELINK:
345 (void) sh_files_pushfile_prelink(filepath);
346 break;
347 default: /* Should not reach here */
348 break;
349 }
350 }
351 }
352
[227]353 SH_FREE(filepath);
354
[1]355 SL_RETURN(0, _("sh_userfiles_init"));
356}
357
358/* This is pretty much NULL; we don't do anything in our checking routine,
359 * so we never need to run it. Just use tcurrent to avoid compiler warnings. */
360int sh_userfiles_timer(time_t tcurrent) {
361 SL_ENTER(_("sh_userfiles_timer"));
362 tcurrent = 0;
363 SL_RETURN((int)tcurrent, _("sh_userfiles_timer"));
364}
365
366int sh_userfiles_check(void) {
367 SL_ENTER(_("sh_userfiles_check"));
368 SL_RETURN(0, _("sh_userfiles_check"));
369}
370
371/* Free our lists and the associated memory */
372
373int sh_userfiles_cleanup(void) {
374 SL_ENTER(_("sh_userfiles_cleanup"));
375
376 sh_userfiles_free_homeslist(userHomes);
377 sh_userfiles_free_fileslist(userFiles);
378 sh_userfiles_free_uidslist (userUids);
379
380 SL_RETURN(0, _("sh_userfiles_cleanup"));
381}
382
383/* As with sh_userfiles_cleanup, but in preparation for re-reading the
384 * configuration files */
385
386int sh_userfiles_reconf(void) {
387 SL_ENTER(_("sh_userfiles_reconf"));
388
389 sh_userfiles_free_homeslist(userHomes);
390 sh_userfiles_free_fileslist(userFiles);
391 sh_userfiles_free_uidslist (userUids);
392
393 userHomes = NULL;
394 userFiles = NULL;
[239]395 userUids = NULL;
[1]396
[149]397 ShUserfilesActive = S_TRUE;
398
[1]399 SL_RETURN(0, _("sh_userfiles_reconf"));
400}
401
402/* Recurse to the end of the list and then free the data as we return
403 * back up towards the start, making sure to free any strdupped strings
404 */
405
406static void sh_userfiles_free_homeslist(struct userhomeslist *head) {
407 if( head != NULL ) {
408 sh_userfiles_free_homeslist(head->next);
409 SH_FREE(head->pw_dir);
410 SH_FREE(head);
411 }
412}
413
414/* Recurse to the end of the list and then free the data as we return
415 * back up towards the start */
416
417static void sh_userfiles_free_fileslist(struct userfileslist *head) {
418 if( head != NULL ) {
419 sh_userfiles_free_fileslist(head->next);
420 SH_FREE(head);
421 }
422}
423
424/* Recurse to the end of the list and then free the data as we return
425 * back up towards the start */
426
427static void sh_userfiles_free_uidslist(struct useruidlist *head) {
428 if( head != NULL ) {
429 sh_userfiles_free_uidslist(head->next);
430 SH_FREE(head);
431 }
432}
433
434/* #if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE) */
435#endif
436
437/* #ifdef SH_USE_USERFILES */
438#endif
Note: See TracBrowser for help on using the repository browser.