source: trunk/src/sh_userfiles.c @ 452

Last change on this file since 452 was 239, checked in by katerina, 13 years ago

Fix for ticket #159

File size: 12.8 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    char * filepath;
254    (void) arg;
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 */
271    SH_MUTEX_LOCK(mutex_pwent);
272    /*@-unrecog@*/
273    sh_setpwent();
274    /*@+unrecog@*/
275    while( ( cur_user = /*@-unrecog@*/sh_getpwent()/*@+unrecog@*/ ) != NULL ) {
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    }
297    sh_endpwent();
298    SH_MUTEX_UNLOCK(mutex_pwent);
299
300    filepath = SH_ALLOC(PATH_MAX);
301
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;
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;
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
353    SH_FREE(filepath);
354
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;
395    userUids  = NULL;
396
397    ShUserfilesActive   = S_TRUE;
398
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.