diff -Nru linux-2.6.10-2.3.legacy_FC2/fs/exec.c linux-2.6.10-2.3.legacy_FC2-snare/fs/exec.c --- linux-2.6.10-2.3.legacy_FC2/fs/exec.c 2006-02-19 20:25:00.000000000 +1100 +++ linux-2.6.10-2.3.legacy_FC2-snare/fs/exec.c 2006-04-13 06:35:52.000000000 +1000 @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -1124,6 +1125,9 @@ struct file *file; int retval; int i; + char *SNARE_arguments; + + SNARE_arguments=saudit_copy_argv(argv); retval = -ENOMEM; bprm = kmalloc(sizeof(*bprm), GFP_KERNEL); @@ -1185,6 +1189,7 @@ if (retval >= 0) { free_arg_pages(bprm); + saudit_execve((char *)NULL, filename, SNARE_arguments, retval); /* execve success */ security_bprm_free(bprm); kfree(bprm); @@ -1216,6 +1221,7 @@ kfree(bprm); out_ret: + saudit_execve((char *) NULL, filename, SNARE_arguments, retval); return retval; } diff -Nru linux-2.6.10-2.3.legacy_FC2/fs/namei.c linux-2.6.10-2.3.legacy_FC2-snare/fs/namei.c --- linux-2.6.10-2.3.legacy_FC2/fs/namei.c 2006-02-19 20:25:00.000000000 +1100 +++ linux-2.6.10-2.3.legacy_FC2-snare/fs/namei.c 2006-04-13 06:35:52.000000000 +1000 @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -1576,11 +1577,15 @@ struct dentry * dentry; struct nameidata nd; - if (S_ISDIR(mode)) + if (S_ISDIR(mode)) { + saudit_mknod((char *)NULL,filename,mode,dev,-EPERM); return -EPERM; + } tmp = getname(filename); - if (IS_ERR(tmp)) + if (IS_ERR(tmp)) { + saudit_mknod((char *)NULL,(char *)NULL,mode,dev,PTR_ERR(tmp)); return PTR_ERR(tmp); + } error = path_lookup(tmp, LOOKUP_PARENT, &nd); if (error) @@ -1613,6 +1618,7 @@ up(&nd.dentry->d_inode->i_sem); path_release(&nd); out: + saudit_mknod(tmp,(char *)NULL,mode,dev,error); putname(tmp); return error; @@ -1649,7 +1655,9 @@ tmp = getname(pathname); error = PTR_ERR(tmp); - if (!IS_ERR(tmp)) { + if (IS_ERR(tmp)) { + saudit_mkdir((char *)NULL,(char *)NULL,mode & ~current->fs->umask,error); + } else { struct dentry *dentry; struct nameidata nd; @@ -1667,6 +1675,7 @@ up(&nd.dentry->d_inode->i_sem); path_release(&nd); out: + saudit_mkdir(tmp,(char *)NULL,mode & ~current->fs->umask,error); putname(tmp); } @@ -1747,8 +1756,10 @@ struct nameidata nd; name = getname(pathname); - if(IS_ERR(name)) + if(IS_ERR(name)) { + saudit_rmdir((char *)NULL,(char *)NULL,PTR_ERR(name)); return PTR_ERR(name); + } error = path_lookup(name, LOOKUP_PARENT, &nd); if (error) @@ -1776,6 +1787,7 @@ exit1: path_release(&nd); exit: + saudit_rmdir(name,(char *)NULL,error); putname(name); return error; } @@ -1825,8 +1837,10 @@ struct inode *inode = NULL; name = getname(pathname); - if(IS_ERR(name)) + if(IS_ERR(name)) { + saudit_unlink((char *)NULL,pathname,PTR_ERR(name)); return PTR_ERR(name); + } error = path_lookup(name, LOOKUP_PARENT, &nd); if (error) @@ -1854,6 +1868,7 @@ exit1: path_release(&nd); exit: + saudit_unlink(name,(char *)NULL,error); putname(name); return error; @@ -1893,11 +1908,15 @@ char * to; from = getname(oldname); - if(IS_ERR(from)) + if(IS_ERR(from)) { + saudit_symlink((char *)NULL,(char *)NULL,(char *)NULL,newname,PTR_ERR(from)); return PTR_ERR(from); + } to = getname(newname); error = PTR_ERR(to); - if (!IS_ERR(to)) { + if(IS_ERR(to)) { + saudit_symlink(from,(char *)NULL,(char *)NULL,(char *)NULL,PTR_ERR(to)); + } else { struct dentry *dentry; struct nameidata nd; @@ -1913,6 +1932,7 @@ up(&nd.dentry->d_inode->i_sem); path_release(&nd); out: + saudit_symlink(from,(char *)NULL,to,(char *)NULL,error); putname(to); } putname(from); @@ -1976,8 +1996,10 @@ char * to; to = getname(newname); - if (IS_ERR(to)) + if (IS_ERR(to)) { + saudit_link((char *)NULL,oldname,(char *)NULL,(char *)NULL,PTR_ERR(to)); return PTR_ERR(to); + } error = __user_walk(oldname, 0, &old_nd); if (error) @@ -2000,6 +2022,7 @@ out: path_release(&old_nd); exit: + saudit_link((char *)NULL,oldname,to,(char *)NULL,error); putname(to); return error; @@ -2236,13 +2259,18 @@ char * to; from = getname(oldname); - if(IS_ERR(from)) + if(IS_ERR(from)) { + saudit_rename((char *)NULL,(char *)NULL,(char *)NULL,newname,PTR_ERR(from)); return PTR_ERR(from); + } to = getname(newname); error = PTR_ERR(to); if (!IS_ERR(to)) { error = do_rename(from,to); + saudit_rename(from,(char *)NULL,to,(char *)NULL,error); putname(to); + } else { + saudit_rename(from,(char *)NULL,(char *)NULL,(char *)NULL,error); } putname(from); return error; diff -Nru linux-2.6.10-2.3.legacy_FC2/fs/namespace.c linux-2.6.10-2.3.legacy_FC2-snare/fs/namespace.c --- linux-2.6.10-2.3.legacy_FC2/fs/namespace.c 2006-02-19 20:24:57.000000000 +1100 +++ linux-2.6.10-2.3.legacy_FC2-snare/fs/namespace.c 2006-04-13 06:35:52.000000000 +1000 @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -487,6 +488,7 @@ dput_and_out: path_release_on_umount(&nd); out: + saudit_umount((char *)NULL,name,flags,retval); return retval; } @@ -1156,17 +1158,23 @@ char *dir_page; retval = copy_mount_options (type, &type_page); - if (retval < 0) + if (retval < 0) { + saudit_mount((char *)NULL,dev_name,(char *)NULL,dir_name,flags,retval); return retval; + } dir_page = getname(dir_name); retval = PTR_ERR(dir_page); - if (IS_ERR(dir_page)) + if (IS_ERR(dir_page)) { + saudit_mount((char *)NULL,dev_name,(char *)NULL,dir_name,flags,retval); goto out1; + } retval = copy_mount_options (dev_name, &dev_page); - if (retval < 0) + if (retval < 0) { + saudit_mount((char *)NULL,dev_name,dir_page,(char *)NULL,flags,retval); goto out2; + } retval = copy_mount_options (data, &data_page); if (retval < 0) @@ -1179,6 +1187,7 @@ free_page(data_page); out3: + saudit_mount((char *)dev_page,(char *)NULL,dir_page,(char *)NULL,flags,retval); free_page(dev_page); out2: putname(dir_page); diff -Nru linux-2.6.10-2.3.legacy_FC2/fs/open.c linux-2.6.10-2.3.legacy_FC2-snare/fs/open.c --- linux-2.6.10-2.3.legacy_FC2/fs/open.c 2006-02-19 20:25:00.000000000 +1100 +++ linux-2.6.10-2.3.legacy_FC2-snare/fs/open.c 2006-04-13 06:35:52.000000000 +1000 @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -218,12 +219,16 @@ int error; error = -EINVAL; - if (length < 0) /* sorry, but loff_t says... */ + if (length < 0) { /* sorry, but loff_t says... */ + saudit_truncate((char *)NULL,path,length,error); goto out; + } error = user_path_walk(path, &nd); - if (error) + if (error) { + saudit_truncate((char *)NULL,path,length,error); goto out; + } inode = nd.dentry->d_inode; /* For directories it's -EISDIR, for other non-regulars - -EINVAL */ @@ -266,6 +271,7 @@ put_write_access(inode); dput_and_out: + saudit_truncate((char *)NULL,path,length,error); path_release(&nd); out: return error; @@ -575,8 +581,10 @@ int error; error = __user_walk(filename, LOOKUP_FOLLOW | LOOKUP_DIRECTORY | LOOKUP_NOALT, &nd); - if (error) + if (error) { + saudit_chroot((char *)NULL,filename,error); goto out; + } error = permission(nd.dentry->d_inode,MAY_EXEC,&nd); if (error) @@ -590,6 +598,7 @@ set_fs_altroot(); error = 0; dput_and_out: + saudit_chroot((char *)NULL,filename,error); path_release(&nd); out: return error; @@ -640,8 +649,10 @@ struct iattr newattrs; error = user_path_walk(filename, &nd); - if (error) + if (error) { + saudit_chmod((char *)NULL,filename,mode,error); goto out; + } inode = nd.dentry->d_inode; error = -EROFS; @@ -661,6 +672,7 @@ up(&inode->i_sem); dput_and_out: + saudit_chmod((char *)NULL,filename,mode,error); path_release(&nd); out: return error; @@ -711,6 +723,7 @@ error = chown_common(nd.dentry, user, group); path_release(&nd); } + saudit_chown((char *)NULL,filename,user,group,error); return error; } @@ -724,6 +737,7 @@ error = chown_common(nd.dentry, user, group); path_release(&nd); } + saudit_chown((char *)NULL,filename,user,group,error); return error; } @@ -953,16 +967,21 @@ #endif tmp = getname(filename); fd = PTR_ERR(tmp); - if (!IS_ERR(tmp)) { + if (IS_ERR(tmp)) { + saudit_open((char *)NULL,(char *)NULL,flags,mode,fd); + } else { fd = get_unused_fd(); if (fd >= 0) { struct file *f = filp_open(tmp, flags, mode); error = PTR_ERR(f); - if (IS_ERR(f)) + if (IS_ERR(f)) { + saudit_open(tmp,(char *)NULL,flags,mode,fd); goto out_error; + } fd_install(fd, f); } out: + saudit_open(tmp,(char *)NULL,flags,mode,fd); putname(tmp); } return fd; diff -Nru linux-2.6.10-2.3.legacy_FC2/include/linux/saudit.h linux-2.6.10-2.3.legacy_FC2-snare/include/linux/saudit.h --- linux-2.6.10-2.3.legacy_FC2/include/linux/saudit.h 1970-01-01 10:00:00.000000000 +1000 +++ linux-2.6.10-2.3.legacy_FC2-snare/include/linux/saudit.h 2006-04-13 06:35:52.000000000 +1000 @@ -0,0 +1,466 @@ +/* + * linux/saudit.h + * + * Original: + * Copyright (c) 1999-2004 InterSect Alliance Pty Ltd + * - http://www.intersectalliance.com/ + * Additions: + * Copyright (c) 2004 Silicon Graphics, Inc. All rights reserved. + */ + +#ifndef __C2_AUDIT_H +#define __C2_AUDIT_H + +#include +#include +#include +#include +#include + +// I was going to use __NR_xxx, but we need audit events for events that +// may NOT be system calls specifically (eg: login, connect/accept) +#define AUDIT_open 1 +#define AUDIT_mkdir 2 +#define AUDIT_unlink 3 +#define AUDIT_rmdir 4 +#define AUDIT_chown 5 +#define AUDIT_chmod 6 +#define AUDIT_symlink 7 +#define AUDIT_link 8 +#define AUDIT_rename 9 +#define AUDIT_mknod 10 +#define AUDIT_truncate 11 +#define AUDIT_ftruncate 12 +#define AUDIT_chroot 13 +#define AUDIT_execve 14 +#define AUDIT_exit 15 +#define AUDIT_setuid 16 +#define AUDIT_setreuid 17 +#define AUDIT_setresuid 18 +#define AUDIT_setgid 19 +#define AUDIT_setregid 20 +#define AUDIT_setresgid 21 +#define AUDIT_create_module 22 +#define AUDIT_delete_module 23 +#define AUDIT_reboot 24 +#define AUDIT_connect 25 +#define AUDIT_accept 26 +#define AUDIT_mount 27 +#define AUDIT_umount 28 +#define AUDIT_fork 29 + +// Size of the bitmask array that we need to store the information +// associated with whether an audit event is currently turned on. +#define MAXAUDIT AUDIT_fork + +// ioctl modes - note that '1' doesnt seem to work. Added 10. +#define AUDIT_STOP 10 // stop auditing +#define AUDIT_START 11 // start auditing +#define AUDIT_INFO 12 // Give me a list of events + // currently active, and other + // info such as the process ID +#define AUDIT_LOSTEVENTS 13 +#define AUDIT_FLUSH 14 // Stop all events. +#define AUDIT_EVENT_ON 15 // Turn on a selected event +#define AUDIT_EVENT_OFF 16 // Turn off a selected event +#define AUDIT_DELIVERY 17 // Do we want to guarantee audit event delivery +#define AUDIT_TOTALEVENTS 18 // How many events have been received this session? + +#define AUDIT_HIGHWATERMARK_MEM 19 // Set the High Water Mark memory usage +#define AUDIT_HIGHWATERMARK_PER 20 // Set the High Water Mark memory as a percentage mem. +#define AUDIT_HIGHWATERMARK_PAUSE 21 // Set the High Water Mark pause percetage +#define AUDIT_LOWWATERMARK_PAUSE 22 // Set the Low Water Mark to resume +#define AUDIT_HIGHWATERMARK_NICE 23 // Set the High Water Mark to change nice value +#define AUDIT_LOWWATERMARK_NICE 24 // Set the Low Water Mark to restore nice value +#define AUDIT_HIGHWATER_NICE_VAL 25 // The nice value to change the audit daemon to + + + + + +#define AUDIT_CLASS_NONE 0 +#define AUDIT_CLASS_IO 1 // Input/output (file opens) +#define AUDIT_CLASS_PC 2 // Process Control +#define AUDIT_CLASS_EXEC 3 // Execution +#define AUDIT_CLASS_NET 4 // Network related +#define AUDIT_CLASS_ADMIN 5 // Administrative events +#define AUDIT_CLASS_CH 6 // CHMOD event. Might not use this for anything else. +#define AUDIT_CLASS_CP 7 // Where more than one pathname is required +#define AUDIT_CLASS_SU 8 // SetUID +#define AUDIT_CLASS_AD 9 // Admin such as create/delete module + +#define SNAREAUDIT_MAJOR_VERSION 0 +#define SNAREAUDIT_MINOR_VERSION 9 +#define SNAREAUDIT_PATCH_VERSION 7 + + +// /proc entry +#define AUDITDEV_NAME "snare" // device name in /dev and /proc/devices +#define AUDITINFO_NAME "snareinfo" // Information about the process +#define AUDITDEV_FILE "/proc/snare" // full file name +#define AUDITINFO_FILE "/proc/snareinfo" // Information about the process. +#define MAX_PATH 512 // NOTE: will migrgate this to PATH_MAX eventually +#define MAXCOMMAND 25 + + +// This contains the details that are common to ALL audit events. +typedef struct +{ + unsigned short event_class; // event class. Each class has a predictable format for tokens. + unsigned short event_id; // number of the event + unsigned short event_size; // size of the event struct - don't include header + // since it's always the same + struct timeval time; // time + + int user_id; // User ID + int euser_id; // Effective User ID + int group_id; // Group ID + int egroup_id; // Effective Group ID + + int returncode; // Make sure that this is big enough to contain the largest returncode. + + pid_t pid; // process ID. + pid_t ppid; // Parent process ID. + char processname[MAXCOMMAND]; // Same as in /usr/include/linux/sched.h for current->comm +} header_token; + +typedef struct +{ + char path[MAX_PATH]; +} path_token; + +typedef struct +{ + int mode; // How the file was attempted to be opened or created + unsigned long createmode; // Flags associated with the file creation. Ulong for mknod. +} attributes_token; + +typedef struct +{ + int owner; // new owner of a file - was uid_t, but these are different between kernel and user. + int group; // new group of a file +} owner_token; + +typedef struct +{ + char args[MAX_PATH]; // Should really allocate more here. Whats is the max command line size? +} execargs_token; + +// System calls like setuid +typedef struct +{ + int id; // uid/gid/euid depending on the call + int rid; // ruid/rgid + int sid; // suid/sgid +} target_token; + +// Network connections +typedef struct +{ + char src_ip[40]; // String containing source dotted ip address - 40 bytes, for IPv6 + int src_port; // Source port + char dst_ip[40]; // String containing destination dotted ip address - 40 bytes, for IPv6 + int dst_port; // Destination port + int protocol; // Protocol type - IPPROTO_UDP or IPPROTO_TCP +} connection_token; + + + +// Now for the audit event classes + +// Just a bare class with the minimal data +// note that this will mean that EVERY class must start with header_token +typedef struct +{ + header_token t_header; +} null_class; + + +// NOTE: ANY CLASS STRUCTURE SHOULD HAVE THE RETURN TOKEN AS THE SECOND ELEMENT. +// SEE AUDITD FOR MORE INFO. +// io - reads/writes +typedef struct +{ + header_token t_header; + path_token t_path; + path_token t_pwd; // Working directory + attributes_token t_attributes; +} io_class; + +typedef struct +{ + header_token t_header; + path_token t_path; + path_token t_pwd; // Working directory + owner_token t_owner; +} ch_class; + +typedef struct +{ + header_token t_header; + path_token t_path; + path_token t_pwd; // Working directory + execargs_token t_execargs; + // environment variables too? +} ex_class; + +typedef struct +{ + header_token t_header; +} pc_class; + +// copy one file to another (amongst others - eg: symlink) +typedef struct +{ + header_token t_header; + path_token t_sourcepath; + path_token t_pwd; // Working directory + path_token t_destpath; +} cp_class; + +typedef struct +{ + header_token t_header; + target_token t_target; // target UID or GID.. I really only need a single value here. +} su_class; + +typedef struct +{ + header_token t_header; + connection_token t_connection; +} nt_class; // Network + +typedef struct +{ + header_token t_header; + path_token t_name; // Name of the module loaded / removed +} ad_class; // General Administrative + +struct _auditnode +{ + void * location; // Location in RAM of the allocated chunk + int size; // Size of the chunk + struct _auditnode *next; // Next node in the series. +}; + +typedef struct _auditnode AuditNode; + + +#ifdef __KERNEL__ +#include + +int _audit_mknod(const char * kfile, const char __user * ufile, int mode, dev_t dev, int retval); +int _audit_execve(const char * kfilename, const char __user * ufilename, char *arguments, int retval); +// Add this back in.. +// _char *audit_copy_exec_strings(char **argv); +int _audit_exit(int retval); +int _audit_fork(int retval); +int _audit_open(const char * kfile,const char __user *ufile, int flags, int mode, int retval); +int _audit_mkdir(const char * kfile, const char __user * ufile, int mode, int retval); +int _audit_unlink(const char * kfile,const char __user * ufile, int retval); +int _audit_rmdir(const char * kfile, const char __user * ufile, int retval); +int _audit_chown(const char * kfile,const char __user * ufile, uid_t user, gid_t group, int retval); +int _audit_chmod(const char * kfile, const char __user * ufile, mode_t mode, int retval); +int _audit_symlink(const char * kfrom,const char __user * ufrom, const char * kto,const char __user * uto, int retval); +int _audit_link(const char * kfrom,const char __user * ufrom, const char * kto,const char __user * uto, int retval); +int _audit_rename(const char * kfrom,const char __user * ufrom, const char * kto, const char __user * uto, int retval); +int _audit_truncate(const char * kfile,const char __user * ufile, loff_t length, int retval); +int _audit_ftruncate(const char * file, loff_t length, int retval); +int _audit_chroot(const char * kfile, const char * ufile, int retval); +int _audit_setuid(uid_t uid, int retval); +int _audit_setreuid(uid_t ruid, uid_t euid, int retval); +int _audit_setresuid(uid_t ruid, uid_t euid, uid_t suid, int retval); +int _audit_setgid(gid_t gid, int retval); +int _audit_setregid(gid_t rgid, gid_t egid, int retval); +int _audit_setresgid(gid_t rgid, gid_t egid, gid_t sgid, int retval); +int _audit_create_module(const char * kname, const char __user * uname, int retval); +int _audit_delete_module(const char * kname, const char __user * uname, int retval); +int _audit_reboot(int magic1, int magic2, unsigned int cmd, void __user * arg, int retval); +int _audit_connect(int sockfd, struct sockaddr __user *serv_addr, int addrlen, int retval); +int _audit_accept(int sockfd, struct sockaddr __user *serv_addr, int *addrlen, int retval); +int _audit_mount(const char *kdev_name, const char __user *udev_name, const char *kdir_name, const char __user *udir_name, unsigned long flags, int retval); +int _audit_umount(const char *kname, const char __user *uname, int flags, int retval); + +void saudit_init(void); +char * saudit_copy_argv(char __user *__user *argv); + +extern int AUDIT_IS_RUNNING; + +// Inline routines in order to speed things up a little. +static inline int saudit_mknod(const char * kfile, const char * ufile, int mode, dev_t dev, int retval) { + if (unlikely(AUDIT_IS_RUNNING)) + return (_audit_mknod(kfile,ufile,mode,dev,retval)); + else + return(0); +} +static inline int saudit_execve(const char * kfilename, const char * ufilename, char *arguments, int retval) { + if (unlikely(AUDIT_IS_RUNNING)) + return (_audit_execve(kfilename,ufilename,arguments,retval)); + else + return(0); +} +static inline int saudit_exit(int retval) { + if (unlikely(AUDIT_IS_RUNNING)) + return (_audit_exit(retval)); + else + return(0); +} +static inline int saudit_fork(int retval) { + if (unlikely(AUDIT_IS_RUNNING)) + return (_audit_fork(retval)); + else + return(0); +} +static inline int saudit_open(const char * kfile,const char *ufile, int flags, int mode, int retval) { + if (unlikely(AUDIT_IS_RUNNING)) + return (_audit_open(kfile,ufile,flags,mode,retval)); + else + return(0); +} +static inline int saudit_mkdir(const char * kfile, const char * ufile, int mode, int retval) { + if (unlikely(AUDIT_IS_RUNNING)) + return (_audit_mkdir(kfile,ufile,mode,retval)); + else + return(0); +} +static inline int saudit_unlink(const char * kfile,const char * ufile, int retval) { + if (unlikely(AUDIT_IS_RUNNING)) + return (_audit_unlink(kfile,ufile,retval)); + else + return(0); +} +static inline int saudit_rmdir(const char * kfile, const char * ufile, int retval) { + if (unlikely(AUDIT_IS_RUNNING)) + return (_audit_rmdir(kfile,ufile,retval)); + else + return(0); +} +static inline int saudit_chown(const char * kfile,const char * ufile, uid_t user, gid_t group, int retval) { + if (unlikely(AUDIT_IS_RUNNING)) + return (_audit_chown(kfile,ufile,user,group,retval)); + else + return(0); +} +static inline int saudit_chmod(const char * kfile, const char * ufile, mode_t mode, int retval) { + if (unlikely(AUDIT_IS_RUNNING)) + return (_audit_chmod(kfile,ufile,mode,retval)); + else + return(0); +} +static inline int saudit_symlink(const char * kfrom,const char * ufrom, const char * kto,const char * uto, int retval) { + if (unlikely(AUDIT_IS_RUNNING)) + return (_audit_symlink(kfrom,ufrom,kto,uto,retval)); + else + return(0); +} +static inline int saudit_link(const char * kfrom,const char * ufrom, const char * kto,const char * uto, int retval) { + if (unlikely(AUDIT_IS_RUNNING)) + return (_audit_link(kfrom,ufrom,kto,uto,retval)); + else + return(0); +} +static inline int saudit_rename(const char * kfrom,const char * ufrom, const char * kto, const char * uto, int retval) { + if (unlikely(AUDIT_IS_RUNNING)) + return (_audit_rename(kfrom,ufrom,kto,uto,retval)); + else + return(0); +} +static inline int saudit_truncate(const char * kfile,const char * ufile, loff_t length, int retval) { + if (unlikely(AUDIT_IS_RUNNING)) + return (_audit_truncate(kfile,ufile,length,retval)); + else + return(0); +} +static inline int saudit_ftruncate(const char * file, loff_t length, int retval) { + if (unlikely(AUDIT_IS_RUNNING)) + return (_audit_ftruncate(file,length,retval)); + else + return(0); +} +static inline int saudit_chroot(const char * kfile, const char * ufile, int retval) { + if (unlikely(AUDIT_IS_RUNNING)) + return (_audit_chroot(kfile,ufile,retval)); + else + return(0); +} +static inline int saudit_setuid(uid_t uid, int retval) { + if (unlikely(AUDIT_IS_RUNNING)) + return (_audit_setuid(uid,retval)); + else + return(0); +} +static inline int saudit_setreuid(uid_t ruid, uid_t euid, int retval) { + if (unlikely(AUDIT_IS_RUNNING)) + return (_audit_setreuid(ruid,euid,retval)); + else + return(0); +} +static inline int saudit_setresuid(uid_t ruid, uid_t euid, uid_t suid, int retval) { + if (unlikely(AUDIT_IS_RUNNING)) + return (_audit_setresuid(ruid,euid,suid,retval)); + else + return(0); +} +static inline int saudit_setgid(gid_t gid, int retval) { + if (unlikely(AUDIT_IS_RUNNING)) + return (_audit_setgid(gid,retval)); + else + return(0); +} +static inline int saudit_setregid(gid_t rgid, gid_t egid, int retval) { + if (unlikely(AUDIT_IS_RUNNING)) + return (_audit_setregid(rgid,egid,retval)); + else + return(0); +} +static inline int saudit_setresgid(gid_t rgid, gid_t egid, gid_t sgid, int retval) { + if (unlikely(AUDIT_IS_RUNNING)) + return (_audit_setresgid(rgid,egid,sgid,retval)); + else + return(0); +} +static inline int saudit_create_module(const char * kname, const char * uname, int retval) { + if (unlikely(AUDIT_IS_RUNNING)) + return (_audit_create_module(kname,uname,retval)); + else + return(0); +} +static inline int saudit_delete_module(const char * kname, const char * uname, int retval) { + if (unlikely(AUDIT_IS_RUNNING)) + return (_audit_delete_module(kname,uname,retval)); + else + return(0); +} +static inline int saudit_reboot(int magic1, int magic2, unsigned int cmd, void __user * arg, int retval) { + if (unlikely(AUDIT_IS_RUNNING)) + return (_audit_reboot(magic1,magic2,cmd,arg,retval)); + else + return(0); +} +static inline int saudit_connect(int sockfd, void __user *serv_addr, int addrlen, int retval) { + if (unlikely(AUDIT_IS_RUNNING)) + return (_audit_connect(sockfd,serv_addr,addrlen,retval)); + else + return(0); +} +static inline int saudit_accept(int sockfd, void __user *serv_addr, int *addrlen, int retval) { + if (unlikely(AUDIT_IS_RUNNING)) + return (_audit_accept(sockfd,serv_addr,addrlen,retval)); + else + return(0); +} +static inline int saudit_mount(const char *kdev_name, const char *udev_name, const char *kdir_name, const char *udir_name, unsigned long flags, int retval) { + if (unlikely(AUDIT_IS_RUNNING)) + return (_audit_mount(kdev_name,udev_name,kdir_name,udir_name,flags,retval)); + else + return(0); +} +static inline int saudit_umount(const char *kname, const char *uname, int flags, int retval) { + if (unlikely(AUDIT_IS_RUNNING)) + return (_audit_umount(kname,uname,flags,retval)); + else + return(0); +} + +#endif /* __KERNEL__ */ +#endif /* __C2_AUDIT_H */ diff -Nru linux-2.6.10-2.3.legacy_FC2/include/linux/sched.h linux-2.6.10-2.3.legacy_FC2-snare/include/linux/sched.h --- linux-2.6.10-2.3.legacy_FC2/include/linux/sched.h 2006-02-19 20:24:58.000000000 +1100 +++ linux-2.6.10-2.3.legacy_FC2-snare/include/linux/sched.h 2006-04-13 06:46:26.000000000 +1000 @@ -658,6 +658,9 @@ /* journalling filesystem info */ void *journal_info; +/* Audit record pointer */ + void *saudit_record; + /* VM state */ struct reclaim_state *reclaim_state; diff -Nru linux-2.6.10-2.3.legacy_FC2/init/main.c linux-2.6.10-2.3.legacy_FC2-snare/init/main.c --- linux-2.6.10-2.3.legacy_FC2/init/main.c 2006-02-19 20:25:00.000000000 +1100 +++ linux-2.6.10-2.3.legacy_FC2-snare/init/main.c 2006-04-13 06:35:52.000000000 +1000 @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -573,6 +574,8 @@ #ifdef CONFIG_PROC_FS proc_root_init(); #endif + saudit_init(); + check_bugs(); acpi_early_init(); /* before LAPIC and SMP init */ diff -Nru linux-2.6.10-2.3.legacy_FC2/kernel/exit.c linux-2.6.10-2.3.legacy_FC2-snare/kernel/exit.c --- linux-2.6.10-2.3.legacy_FC2/kernel/exit.c 2006-02-19 20:25:00.000000000 +1100 +++ linux-2.6.10-2.3.legacy_FC2-snare/kernel/exit.c 2006-04-13 06:47:25.000000000 +1000 @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -861,6 +862,7 @@ asmlinkage long sys_exit(int error_code) { + saudit_exit(error_code); do_exit((error_code&0xff)<<8); } diff -Nru linux-2.6.10-2.3.legacy_FC2/kernel/fork.c linux-2.6.10-2.3.legacy_FC2-snare/kernel/fork.c --- linux-2.6.10-2.3.legacy_FC2/kernel/fork.c 2006-02-19 20:24:57.000000000 +1100 +++ linux-2.6.10-2.3.legacy_FC2-snare/kernel/fork.c 2006-04-13 06:53:53.000000000 +1000 @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -790,25 +791,32 @@ int pid) { int retval; + int auditretval=0; struct task_struct *p = NULL; - if ((clone_flags & (CLONE_NEWNS|CLONE_FS)) == (CLONE_NEWNS|CLONE_FS)) + if ((clone_flags & (CLONE_NEWNS|CLONE_FS)) == (CLONE_NEWNS|CLONE_FS)) { + saudit_fork(-1); return ERR_PTR(-EINVAL); + } /* * Thread groups must share signals as well, and detached threads * can only be started up within the thread group. */ - if ((clone_flags & CLONE_THREAD) && !(clone_flags & CLONE_SIGHAND)) + if ((clone_flags & CLONE_THREAD) && !(clone_flags & CLONE_SIGHAND)) { + saudit_fork(-1); return ERR_PTR(-EINVAL); + } /* * Shared signal handlers imply shared VM. By way of the above, * thread groups also imply shared VM. Blocking this case allows * for various simplifications in other code. */ - if ((clone_flags & CLONE_SIGHAND) && !(clone_flags & CLONE_VM)) + if ((clone_flags & CLONE_SIGHAND) && !(clone_flags & CLONE_VM)) { + saudit_fork(-1); return ERR_PTR(-EINVAL); + } retval = security_task_create(clone_flags); if (retval) @@ -820,6 +828,9 @@ goto fork_out; p->tux_info = NULL; + p->saudit_record = NULL; + + retval = -EAGAIN; if (atomic_read(&p->user->processes) >= p->signal->rlim[RLIMIT_NPROC].rlim_cur) { @@ -1025,6 +1036,11 @@ retval = 0; fork_out: + if (auditretval == -1) + saudit_fork(-1); + else + saudit_fork(p->pid); + if (retval) return ERR_PTR(retval); return p; @@ -1065,6 +1081,7 @@ free_uid(p->user); bad_fork_free: free_task(p); + auditretval = -1; goto fork_out; } diff -Nru linux-2.6.10-2.3.legacy_FC2/kernel/module.c linux-2.6.10-2.3.legacy_FC2-snare/kernel/module.c --- linux-2.6.10-2.3.legacy_FC2/kernel/module.c 2006-02-19 20:25:00.000000000 +1100 +++ linux-2.6.10-2.3.legacy_FC2-snare/kernel/module.c 2006-04-13 06:35:52.000000000 +1000 @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -530,15 +531,21 @@ char name[MODULE_NAME_LEN]; int ret, forced = 0; - if (!capable(CAP_SYS_MODULE)) + if (!capable(CAP_SYS_MODULE)) { + saudit_delete_module((char *)NULL, name_user, -EPERM); return -EPERM; + } - if (strncpy_from_user(name, name_user, MODULE_NAME_LEN-1) < 0) + if (strncpy_from_user(name, name_user, MODULE_NAME_LEN-1) < 0) { + saudit_delete_module((char *)NULL, name_user, -EPERM); return -EFAULT; + } name[MODULE_NAME_LEN-1] = '\0'; - if (down_interruptible(&module_mutex) != 0) + if (down_interruptible(&module_mutex) != 0) { + saudit_delete_module((char *)NULL, name_user, -EPERM); return -EINTR; + } mod = find_module(name); if (!mod) { @@ -594,6 +601,7 @@ out: up(&module_mutex); + saudit_delete_module((char *)NULL, name_user, ret); return ret; } @@ -1770,17 +1778,22 @@ int ret = 0; /* Must have permission */ - if (!capable(CAP_SYS_MODULE)) + if (!capable(CAP_SYS_MODULE)) { + saudit_create_module((char *)NULL, uargs, -EPERM); return -EPERM; + } /* Only one module load at a time, please */ - if (down_interruptible(&module_mutex) != 0) + if (down_interruptible(&module_mutex) != 0) { + saudit_create_module((char *)NULL, uargs, -EINTR); return -EINTR; + } /* Do all the hard work */ mod = load_module(umod, len, uargs); if (IS_ERR(mod)) { up(&module_mutex); + saudit_create_module((char *)NULL, uargs, PTR_ERR(mod)); return PTR_ERR(mod); } @@ -1822,6 +1835,7 @@ free_module(mod); up(&module_mutex); } + saudit_create_module(mod->name, (char *)NULL, ret); return ret; } @@ -1836,6 +1850,7 @@ mod->init_text_size = 0; up(&module_mutex); + saudit_create_module(mod->name, (char *)NULL, 0); return 0; } diff -Nru linux-2.6.10-2.3.legacy_FC2/kernel/sys.c linux-2.6.10-2.3.legacy_FC2-snare/kernel/sys.c --- linux-2.6.10-2.3.legacy_FC2/kernel/sys.c 2006-02-19 20:24:56.000000000 +1100 +++ linux-2.6.10-2.3.legacy_FC2-snare/kernel/sys.c 2006-04-13 07:01:23.000000000 +1000 @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -370,17 +371,24 @@ char buffer[256]; /* We only trust the superuser with rebooting the system. */ - if (!capable(CAP_SYS_BOOT)) + if (!capable(CAP_SYS_BOOT)) { + saudit_reboot(magic1,magic2,cmd,arg,-EPERM); return -EPERM; + } /* For safety, we require "magic" arguments. */ if (magic1 != LINUX_REBOOT_MAGIC1 || (magic2 != LINUX_REBOOT_MAGIC2 && magic2 != LINUX_REBOOT_MAGIC2A && magic2 != LINUX_REBOOT_MAGIC2B && - magic2 != LINUX_REBOOT_MAGIC2C)) + magic2 != LINUX_REBOOT_MAGIC2C)) { + saudit_reboot(magic1,magic2,cmd,arg,-EINVAL); return -EINVAL; + } + // Try and audit before we go down. + saudit_reboot(magic1,magic2,cmd,arg,0); + lock_kernel(); switch (cmd) { case LINUX_REBOOT_CMD_RESTART: @@ -499,16 +507,20 @@ int retval; retval = security_task_setgid(rgid, egid, (gid_t)-1, LSM_SETID_RE); - if (retval) + if (retval) { + saudit_setregid(rgid,egid,retval); return retval; + } if (rgid != (gid_t) -1) { if ((old_rgid == rgid) || (current->egid==rgid) || capable(CAP_SETGID)) new_rgid = rgid; - else + else { + saudit_setregid(rgid,egid,-EPERM); return -EPERM; + } } if (egid != (gid_t) -1) { if ((old_rgid == egid) || @@ -517,6 +529,7 @@ capable(CAP_SETGID)) new_egid = egid; else { + saudit_setregid(rgid,egid,-EPERM); return -EPERM; } } @@ -532,6 +545,7 @@ current->egid = new_egid; current->gid = new_rgid; key_fsgid_changed(current); + saudit_setregid(rgid,egid,0); return 0; } @@ -546,11 +560,14 @@ int retval; retval = security_task_setgid(gid, (gid_t)-1, (gid_t)-1, LSM_SETID_ID); - if (retval) + if (retval) { + saudit_setgid(gid,retval); return retval; + } if (capable(CAP_SETGID)) { + saudit_setgid(gid,0); if(old_egid != gid) { current->mm->dumpable = suid_dumpable; @@ -560,6 +577,7 @@ } else if ((gid == current->gid) || (gid == current->sgid)) { + saudit_setgid(gid,0); if(old_egid != gid) { current->mm->dumpable = suid_dumpable; @@ -567,8 +585,10 @@ } current->egid = current->fsgid = gid; } - else + else { + saudit_setgid(gid,-EPERM); return -EPERM; + } key_fsgid_changed(current); return 0; @@ -621,8 +641,10 @@ int retval; retval = security_task_setuid(ruid, euid, (uid_t)-1, LSM_SETID_RE); - if (retval) + if (retval) { + saudit_setreuid(ruid, euid, retval); return retval; + } new_ruid = old_ruid = current->uid; new_euid = old_euid = current->euid; @@ -632,8 +654,10 @@ new_ruid = ruid; if ((old_ruid != ruid) && (current->euid != ruid) && - !capable(CAP_SETUID)) + !capable(CAP_SETUID)) { + saudit_setreuid(ruid,euid,-EPERM); return -EPERM; + } } if (euid != (uid_t) -1) { @@ -641,12 +665,18 @@ if ((old_ruid != euid) && (current->euid != euid) && (current->suid != euid) && - !capable(CAP_SETUID)) + !capable(CAP_SETUID)) { + saudit_setreuid(ruid,euid,-EPERM); return -EPERM; + } } - if (new_ruid != old_ruid && set_user(new_ruid, new_euid != old_euid) < 0) + if (new_ruid != old_ruid && set_user(new_ruid, new_euid != old_euid) < 0) { + saudit_setreuid(ruid,euid,-EAGAIN); return -EAGAIN; + } + + saudit_setreuid(ruid,euid,0); // Before current->*id is changed if (new_euid != old_euid) { @@ -684,20 +714,28 @@ int retval; retval = security_task_setuid(uid, (uid_t)-1, (uid_t)-1, LSM_SETID_ID); - if (retval) + if (retval) { + saudit_setuid(uid,retval); return retval; + } old_ruid = new_ruid = current->uid; old_suid = current->suid; new_suid = old_suid; if (capable(CAP_SETUID)) { - if (uid != old_ruid && set_user(uid, old_euid != uid) < 0) + if (uid != old_ruid && set_user(uid, old_euid != uid) < 0) { + saudit_setuid(uid,-EAGAIN); return -EAGAIN; + } new_suid = uid; - } else if ((uid != current->uid) && (uid != new_suid)) + } else if ((uid != current->uid) && (uid != new_suid)) { + saudit_setuid(uid,-EPERM); return -EPERM; - + } + + saudit_setuid(uid,0); // Before current->*id is changed + if (old_euid != uid) { current->mm->dumpable = suid_dumpable; @@ -724,24 +762,37 @@ int retval; retval = security_task_setuid(ruid, euid, suid, LSM_SETID_RES); - if (retval) + if (retval) { + saudit_setresuid(ruid,euid,suid,retval); return retval; + } if (!capable(CAP_SETUID)) { if ((ruid != (uid_t) -1) && (ruid != current->uid) && - (ruid != current->euid) && (ruid != current->suid)) + (ruid != current->euid) && (ruid != current->suid)) { + saudit_setresuid(ruid,euid,suid,-EPERM); return -EPERM; + } if ((euid != (uid_t) -1) && (euid != current->uid) && - (euid != current->euid) && (euid != current->suid)) + (euid != current->euid) && (euid != current->suid)) { + saudit_setresuid(ruid,euid,suid,-EPERM); return -EPERM; + } if ((suid != (uid_t) -1) && (suid != current->uid) && - (suid != current->euid) && (suid != current->suid)) + (suid != current->euid) && (suid != current->suid)) { + saudit_setresuid(ruid,euid,suid,-EPERM); return -EPERM; + } } if (ruid != (uid_t) -1) { - if (ruid != current->uid && set_user(ruid, euid != current->euid) < 0) + if (ruid != current->uid && set_user(ruid, euid != current->euid) < 0) { + saudit_setresuid(ruid,euid,suid,-EAGAIN); return -EAGAIN; + } } + + saudit_setresuid(ruid,euid,suid,0); // Before current->uids change + if (euid != (uid_t) -1) { if (euid != current->euid) { @@ -778,20 +829,31 @@ int retval; retval = security_task_setgid(rgid, egid, sgid, LSM_SETID_RES); - if (retval) + if (retval) { + saudit_setresgid(rgid,egid,sgid,retval); return retval; + } if (!capable(CAP_SETGID)) { if ((rgid != (gid_t) -1) && (rgid != current->gid) && - (rgid != current->egid) && (rgid != current->sgid)) + (rgid != current->egid) && (rgid != current->sgid)) { + saudit_setresgid(rgid,egid,sgid,-EPERM); return -EPERM; + } if ((egid != (gid_t) -1) && (egid != current->gid) && - (egid != current->egid) && (egid != current->sgid)) + (egid != current->egid) && (egid != current->sgid)) { + saudit_setresgid(rgid,egid,sgid,-EPERM); return -EPERM; + } if ((sgid != (gid_t) -1) && (sgid != current->gid) && - (sgid != current->egid) && (sgid != current->sgid)) + (sgid != current->egid) && (sgid != current->sgid)) { + saudit_setresgid(rgid,egid,sgid,-EPERM); return -EPERM; + } } + + saudit_setresgid(rgid,egid,sgid,0); // Before our current process UIDs change + if (egid != (gid_t) -1) { if (egid != current->egid) { diff -Nru linux-2.6.10-2.3.legacy_FC2/net/socket.c linux-2.6.10-2.3.legacy_FC2-snare/net/socket.c --- linux-2.6.10-2.3.legacy_FC2/net/socket.c 2006-02-19 20:25:00.000000000 +1100 +++ linux-2.6.10-2.3.legacy_FC2-snare/net/socket.c 2006-04-13 06:35:52.000000000 +1000 @@ -44,6 +44,7 @@ * Tigran Aivazian : sys_send(args) calls sys_sendto(args, NULL, 0) * Tigran Aivazian : Made listen(2) backlog sanity checks * protocol-independent + * Leigh Purdie : Socketcall auditing. * * * This program is free software; you can redistribute it and/or @@ -76,6 +77,7 @@ #include #include #include +#include #include #include #include @@ -1944,12 +1946,14 @@ break; case SYS_CONNECT: err = sys_connect(a0, (struct sockaddr __user *)a1, a[2]); + saudit_connect(a0, (struct sockaddr __user *)a1, a[2],err); break; case SYS_LISTEN: err = sys_listen(a0,a1); break; case SYS_ACCEPT: err = sys_accept(a0,(struct sockaddr __user *)a1, (int __user *)a[2]); + saudit_accept(a0, (struct sockaddr __user*)a1, (int __user *)a[2],err); break; case SYS_GETSOCKNAME: err = sys_getsockname(a0,(struct sockaddr __user *)a1, (int __user *)a[2]); diff -Nru linux-2.6.10-2.3.legacy_FC2/security/Makefile linux-2.6.10-2.3.legacy_FC2-snare/security/Makefile --- linux-2.6.10-2.3.legacy_FC2/security/Makefile 2004-12-25 08:35:23.000000000 +1100 +++ linux-2.6.10-2.3.legacy_FC2-snare/security/Makefile 2006-04-13 07:03:36.000000000 +1000 @@ -4,6 +4,7 @@ obj-$(CONFIG_KEYS) += keys/ subdir-$(CONFIG_SECURITY_SELINUX) += selinux +subdir-y += snare # if we don't select a security model, use the default capabilities ifneq ($(CONFIG_SECURITY),y) @@ -17,3 +18,4 @@ obj-$(CONFIG_SECURITY_CAPABILITIES) += commoncap.o capability.o obj-$(CONFIG_SECURITY_ROOTPLUG) += commoncap.o root_plug.o obj-$(CONFIG_SECURITY_SECLVL) += seclvl.o +obj-y += snare/built-in.o diff -Nru linux-2.6.10-2.3.legacy_FC2/security/snare/auditapi.c linux-2.6.10-2.3.legacy_FC2-snare/security/snare/auditapi.c --- linux-2.6.10-2.3.legacy_FC2/security/snare/auditapi.c 1970-01-01 10:00:00.000000000 +1000 +++ linux-2.6.10-2.3.legacy_FC2-snare/security/snare/auditapi.c 2006-04-13 06:35:52.000000000 +1000 @@ -0,0 +1,2075 @@ +/* $Id: auditapi.c,v 1.3 2005/10/06 14:55:04 redphoenix Exp $ + * + * security/snare/auditapi.c + * + * Original Copyright (c) 2002-2004 InterSect Alliance Pty Ltd + * - www.intersectalliance.com + * + * Additions: + * 2005: Incorporated Marks GrabString changes for audit_mount + * 2004: Modified by Mark Westerman mark.westerman at westcam dot com + * 2004: Copyright (c) 2004 Silicon Graphics, Inc. All rights reserved. + * 2004: Modified by Jonathan Abbey, UTexas + * + */ + +// Memory usage +#include + +// Total events and lost events not working now do not show +// Modification By mark.westerman at westcam dot com +#define SHOW_EVENT_COUNTER 0 +#define SNARE_RED_HAT_LINUX_KERNEL 1 + +#define MAX_SOCK_ADDR 128 /* 108 for Unix domain */ + +#include +#include +#include +#include +#include +#include +#include + +// #include +#include +#include +#include + +#include +#include + +#include + +// Externals +// Not certain that we need this. +extern struct socket *sockfd_lookup (int fd, int *err); + + +// Function prototypes +static int auditproc_ioctl(struct inode *, struct file *, unsigned int, + unsigned long); +static int auditproc_open(struct inode *, struct file *); +static int auditproc_close(struct inode *, struct file *); +static ssize_t auditproc_read(struct file *, char *, size_t, loff_t *); + +static int info_open(struct inode *inode, struct file *file); +static ssize_t info_read(struct file *file, char *ubuf, size_t length, + loff_t * ppos); +static int info_close(struct inode *inode, struct file *file); + +static void audit_on(int auditnumber); +static void audit_off(int auditnumber); +static AuditNode *alloc_event(int token_size); +static void append_event(AuditNode * nodepointer); + +static long GrabString(char *destination, const char *kernelstring, + const char __user *userstring, int length); + +static void audit_hwcheck(void); +int saudit_return(int returncode); + +static DECLARE_MUTEX(audit_lock); +static struct task_struct *auditdaemon_task_struct = NULL; // Daemon interaction + +// If we have the audit daemon attached +int AUDIT_IS_RUNNING = 0; +static int AUDIT_IS_PAUSED = 0; // Used for High Water Mark memory testing + +#if defined(SNARE_RED_HAT_LINUX_KERNEL) || ( LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ) +#define PRIO_TO_NICE(prio) ((prio) - MAX_RT_PRIO - 20) +#endif + +// How many packets have we lost this session due to low buffer size? +static int lost_events = 0; +static int total_events = 0; + +// Linked list of audit events - used as an internal buffer +// so that we don't slow down the kernel significantly while waiting +// for the user space audit daemon to catch up. +static AuditNode *list_head = (AuditNode *) NULL; +static AuditNode *list_tail = (AuditNode *) NULL; + +// Audit daemon read position +static void *read_position = (void *) NULL; + +// Setup a bitmask to work out which audit events are currently active. +// Declare as volatile for the compiler not lock for test events +volatile static unsigned long active_events[(MAXAUDIT + sizeof(long) - 1) / + sizeof(long)] = { 0, }; + +#define saudit_active(auditnumber) \ + (test_bit((auditnumber),active_events)) + +static struct file_operations info_ops = { + read:info_read, // read + open:info_open, + release:info_close +}; + +static struct file_operations file_ops = { + read:auditproc_read, // read + open:auditproc_open, // open + ioctl:auditproc_ioctl, // ioctl + release:auditproc_close // release +}; + + +static struct proc_dir_entry *ProcEntry; +static struct proc_dir_entry *ProcInfoEntry; + +// +// For compatibility with Non RedHat i.e. vanilla kernels +// including debian kernels +// + +#if !defined(SNARE_RED_HAT_LINUX_KERNEL) && ( LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) ) +#define set_user_nice(tsk, n) do { (tsk)->nice = n; } while(0) +#endif + +// +// Highwater mark varables for memory utilization +// +static unsigned long highwater_mark = 15000000; // Set to 15 MB by Default +static unsigned long memory_usage = 0; // Current Memory Usage +static int nicevalue; // Nice Value that the + // Audit Daemon was stated with +static int prio_change = 0; // Has priority Changed +static int highwater_pause = 100; // % to of memory usage to pause +static int lowwater_pause = 90; // % to resume auditing +static int highwater_nice = 80; // % to change audit priority +static int highwater_nice_val = -10; // Nice value to change to +static int lowwater_nice = 60; // % to change back the priority +static int highwater_mark_percent = 10; // % of memory to use for High water mark + +wait_queue_head_t proc_audit_queue; + +// Use to calculate total ram +#define BSHIFT(x) ((unsigned long)(x) << PAGE_SHIFT) + +// Initialise our audit environment +void saudit_init(void) +{ + struct sysinfo i; + + // Initialise audit here + // - create /proc entries etc. + printk("SNARE Audit capability is initialising\n"); + + // Create the proc file system entries. + if ((ProcInfoEntry = + create_proc_entry(AUDITINFO_NAME, S_IRUGO | S_IWUSR, + NULL)) == NULL) { + printk("Audit: Cannot create snare information interface in /proc"); + return; + } + ProcInfoEntry->proc_fops = &info_ops; + + if ((ProcEntry = + create_proc_entry(AUDITDEV_NAME, S_IRUSR | S_IWUSR, + NULL)) == NULL) { + printk("Audit: Cannot create snare daemon interface in /proc"); + return; + } + + ProcEntry->proc_fops = &file_ops; + + // Initialise the wait queue for blocking read + init_waitqueue_head(&proc_audit_queue); + // Initialise the highwater mark system + memory_usage = 0; + AUDIT_IS_PAUSED = 0; + si_meminfo(&i); + // Set the highwater mark as a percentage of total ram + highwater_mark = (BSHIFT(i.totalram) / 100) * highwater_mark_percent; + +} + +static int info_open(struct inode *inode, struct file *file) +{ + enum { DATA_LEN = 500 }; + char *data; + char processid[20]; + int nv; + pid_t ad_task = 0; + int daemon_running = 0; +#if SHOW_EVENT_COUNTER + int l_lost_events, l_total_events; +#endif + + if ((data = kmalloc(DATA_LEN, GFP_KERNEL)) == NULL) + return (0); + + down(&audit_lock); + + if (auditdaemon_task_struct != NULL) { + daemon_running = 1; + ad_task = auditdaemon_task_struct->pid; + } + +#if SHOW_EVENT_COUNTER + l_lost_events = lost_events; + l_total_events = total_events; +#endif + + up(&audit_lock); + + if(daemon_running) { + snprintf(processid, 20, "%d", (int) ad_task); +#if !defined(SNARE_RED_HAT_LINUX_KERNEL) && ( LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) ) + nv = auditdaemon_task_struct->nice; +#else + nv = PRIO_TO_NICE(auditdaemon_task_struct->static_prio); +#endif + } else { + snprintf(processid, 20, "No Daemon Running"); + nv = 0; + } + + +#if SHOW_EVENT_COUNTER + // Just my perference I like the output lined up + snprintf(data, DATA_LEN, + "SNARE Version: %d.%d.%d\n" + "Audit Active: %s\n" + "Audit Process ID: %s\n" + "Events Lost This Session: %d\n" + "Events Processed This Session: %d\n" + "HighWater Mark: %lu\n" + "Memory Usage: %lu\n" + "Audit Paused: %s\n" + "Audit Nice Value: %d\n", + SNAREAUDIT_MAJOR_VERSION, SNAREAUDIT_MINOR_VERSION, + SNAREAUDIT_PATCH_VERSION, + (AUDIT_IS_RUNNING ? "yes" : "no"), processid, l_lost_events, + l_total_events, highwater_mark, memory_usage, + (AUDIT_IS_PAUSED ? "yes" : "no"), nv); +#else + snprintf(data, DATA_LEN, + "SNARE Version: %d.%d.%d\n" + "Audit Active: %s\n" + "Audit Process ID: %s\n" + "HighWater Mark: %lu\n" + "Memory Usage: %lu\n" + "Audit Paused: %s\n" + "Audit Nice Value: %d\n", + SNAREAUDIT_MAJOR_VERSION, SNAREAUDIT_MINOR_VERSION, + SNAREAUDIT_PATCH_VERSION, + (AUDIT_IS_RUNNING ? "yes" : "no"), processid, + highwater_mark, memory_usage, + (AUDIT_IS_PAUSED ? "yes" : "no"), nv); +#endif + + if (data == NULL) + return -ENODEV; + + file->private_data = data; + + return (0); +} + +static void audit_hwcheck(void) +{ + unsigned long per; + int paused; + + + // We lock the kernel here to handle the + // the highwater mark system use lot of + // global varables + + down(&audit_lock); + paused = AUDIT_IS_PAUSED; + per = memory_usage / (highwater_mark / 100); + + if (per > highwater_pause) { + AUDIT_IS_PAUSED = 1; + ++lost_events; + up(&audit_lock); + if (!paused) { + printk("Auditing: is paused\n"); + } + return; + } + if (per > highwater_nice) { + if (!AUDIT_IS_PAUSED) { + if (!prio_change) { + prio_change = 1; + up(&audit_lock); + printk + ("Auditing: Changing Audit daemon Priority\n"); + set_user_nice(auditdaemon_task_struct, + highwater_nice_val); + return; + } + up(&audit_lock); + return; + } + ++lost_events; + up(&audit_lock); + return; + } + if (AUDIT_IS_PAUSED && (per < lowwater_pause)) { + AUDIT_IS_PAUSED = 0; + } else { + paused = 0; + } + if (prio_change && per < lowwater_nice) { + prio_change = 0; + up(&audit_lock); + printk("Auditing: Resuming Audit daemon Priority\n"); + set_user_nice(auditdaemon_task_struct, nicevalue); + return; + } + if (AUDIT_IS_PAUSED) { + ++lost_events; + } + + up(&audit_lock); + if (paused) { + printk("Auditing: is resuming\n"); + } +} + +static int info_close(struct inode *inode, struct file *file) +{ + kfree(file->private_data); + return (0); +} + +static ssize_t info_read(struct file *file, char *ubuf, size_t length, + loff_t * ppos) +{ + int bytes_to_write = 0; + int pos = *ppos; + char *data = file->private_data; + + // User has asked for a zero-length read? + if (length == 0) + return (0); + + if ((bytes_to_write = strlen(data) - pos) <= 0) + return 0; // EOF + if (bytes_to_write >= length) + bytes_to_write = length; + if (copy_to_user(ubuf, data + pos, bytes_to_write)) + return -EFAULT; + *ppos = pos + bytes_to_write; + return (bytes_to_write); +} + + +//////////////////////////////////////////////////////////////////////////////// +// This routine handles ioctl messages from the audit daemon. +//////////////////////////////////////////////////////////////////////////////// + +int auditproc_ioctl(struct inode *node, struct file *the_file, + unsigned int command, unsigned long arg) +{ + // If the audit facility is running, there is not much point starting again! + if ((AUDIT_IS_RUNNING) && (command == AUDIT_START)) { + return -EBUSY; + } + + // Don't alllow a forked or cloned task to ioctl. + // Only the task which opened the audit device may + // control this device. + if(auditdaemon_task_struct != current) { + return -EBUSY; + } + + if (command == AUDIT_START) { + down(&audit_lock); + AUDIT_IS_RUNNING = 1; + up(&audit_lock); + } else if (command == AUDIT_STOP) { + down(&audit_lock); + AUDIT_IS_RUNNING = 0; + up(&audit_lock); + } else if (command == AUDIT_LOSTEVENTS) { + return (lost_events); + } else if (command == AUDIT_TOTALEVENTS) { + return (total_events); + } else if (command == AUDIT_EVENT_ON) { + if(arg <= 0 || arg > MAXAUDIT) { + return -EINVAL; + } + audit_on(arg); + } else if (command == AUDIT_EVENT_OFF) { + if(arg <= 0 || arg > MAXAUDIT) { + return -EINVAL; + } + audit_off(arg); + // Eg: ioctl(x,SYS_exit); + } else if (command == AUDIT_FLUSH) { + // Turn off all auditing. + // This is generally sent when /etc/audit/snare.conf has been updated + // and the user wishes to establish a new audit policy. + int counter; + for (counter = 1; counter <= MAXAUDIT; counter++) { + if (saudit_active(counter)) + audit_off(counter); + } + + // Also reset the lost/total event counters here. + lost_events = 0; + total_events = 0; + // High water mark system should add error checking here. + } else if (command == AUDIT_HIGHWATERMARK_MEM) { + highwater_mark = arg; + } else if (command == AUDIT_HIGHWATERMARK_PER) { + struct sysinfo i; + si_meminfo(&i); + highwater_mark_percent = arg; + highwater_mark = + (BSHIFT(i.totalram) / 100) * highwater_mark_percent; + } else if (command == AUDIT_HIGHWATERMARK_PAUSE) { + highwater_pause = arg; + } else if (command == AUDIT_LOWWATERMARK_PAUSE) { + lowwater_pause = arg; + } else if (command == AUDIT_HIGHWATERMARK_NICE) { + highwater_nice_val = arg; + } else if (command == AUDIT_LOWWATERMARK_NICE) { + lowwater_nice = arg; + } else if (command == AUDIT_HIGHWATER_NICE_VAL) { + highwater_nice_val = arg; + } else { + return -ENOSYS; // Redhat kernel team suggest ENOTTY ? Clarify this. + } + + return 0; +} + + +//////////////////////////////////////////////////////////////////////////////// +// Here we give the user the data. +// NOTE that this module may be executed at any time - even in the middle +// of the execution of something else. Hence, any variables that are changed +// by this routine should be surrounded by a kernel lock if they are used +// elsewhere! +// +// In particular: +// read_position +// list_head +// list_tail +// +// Let me just repeat this in another way: +// WARNING: DO NOT CHANGE OR RELY ON THE VARIABLES ABOVE UNLESS YOU ARE +// IN A LOCKED STATE - THEY MAY BE CORRUPTED BY THE +// AUDIT_READ MODULE, WHICH IS CALLED BY SIGNAL/INTERRUPT +// +// Unfortunately, we also need lock within this routine also. +// Otherwise, an interrupt might occur when we were half way through modifying +// something like read_position - and if the interrupt happens to generate an +// audit event, then we may be copying data to the wrong location in the array, +// leading to data corruption. +// Locking too much code slows down the system unfortunately. I'll try +// and keep it minimal. +//////////////////////////////////////////////////////////////////////////////// + +static ssize_t auditproc_read(struct file *file, char *filebuffer, + size_t length, loff_t * ppos) +{ + // Number of bytes actually written to the buffer + int bytes_avail_to_send = 0; + int bytes_to_write = 0; + + + // Don't allow a forked or cloned task to read. + // Only the task which opened the audit device may read. + if(auditdaemon_task_struct != current) { + return -EBUSY; + } + + if (length == 0) { + return (0); // Only want zero bytes? Here they are. + } + + // if (ppos != &file->f_pos) { + // return -ESPIPE; // No pread() thanks. + //} + + BUG_ON(auditdaemon_task_struct == NULL); + + // Do we have any data? + if (list_head == (AuditNode *) NULL) { + if (file->f_flags & O_NONBLOCK) { + return -EAGAIN; + } + if (wait_event_interruptible(proc_audit_queue, list_head)) { + return -ERESTARTSYS; + } + } + + // Lock the kernel + down(&audit_lock); + if (read_position == (void *) NULL) { + // Our first time into this routine, or first time back after all data has been read. + read_position = list_head->location; + } + + bytes_avail_to_send = + (int) (((void *) list_head->location + list_head->size) - + (void *) read_position); + + up(&audit_lock); + + /* + * Give the caller all available data up to length. + * We know that at least one byte will be available, + * because we have the head node, all nodes must + * have some data, and the head node must have some + * data available (otherwise the head node would + * have been tossed in the last call to this function). + */ + if(bytes_avail_to_send > length) { + bytes_to_write = length; + } else { + bytes_to_write = bytes_avail_to_send; + } +// while (bytes_avail_to_send < length) { +// // up(&audit_lock); +// +// if (file->f_flags & O_NONBLOCK) { +// return -EAGAIN; +// } +// +// if (wait_event_interruptible(proc_audit_queue, +// (bytes_avail_to_send = +// (int) (list_head->location + +// list_head->size - +// read_position)) >= +// length)) { +// return -ERESTARTSYS; +// } +// // down(&audit_lock); +// } +// bytes_to_write = length; + + + if (copy_to_user(filebuffer, read_position, bytes_to_write)) { + // up(&audit_lock); + return -EFAULT; + } + + down(&audit_lock); + read_position += bytes_to_write; + + // Have we reached the end of the current nodes data? + if ((void *) read_position >= + ((void *) list_head->location + list_head->size)) { + AuditNode *tempnode; + + tempnode = list_head; + list_head = list_head->next; + + if (tempnode->size > memory_usage) { + memory_usage = 0; + } else { + memory_usage -= tempnode->size; + } + // Excellent, we're at the end of the current audit event. + // Remove this from the linked list, and set the read_position to the next record. + if (list_head != (AuditNode *) NULL) { + read_position = list_head->location; + } else { + read_position = (AuditNode *) NULL; + } + + // No events remaining? Set list_tail to null also. + if (tempnode->next == (AuditNode *) NULL) { + list_tail = (AuditNode *) NULL; + } + + // Free our tempnode->location pointer, which actually + // is a pointer to ex current->saudit_record + kfree(tempnode->location); + kfree(tempnode); + } + + up(&audit_lock); + + return (bytes_to_write); +} + + +//////////////////////////////////////////////////////////////////////////////// +// open the device +//////////////////////////////////////////////////////////////////////////////// +static int auditproc_open(struct inode *node, struct file *the_file) +{ + // Note: This changes to minor(node...) in 2.6 + // int device_minor = MINOR(node->i_rdev) & 0xf; // Device minor number + + // We can only have one audit device, and it can only be open once + //if (device_minor) { + // return -EBUSY; + //} + + down(&audit_lock); + + if (auditdaemon_task_struct != NULL) { + up(&audit_lock); + return -EBUSY; + } + + // reset the lost packets indicator + lost_events = 0; + total_events = 0; + memory_usage = 0; + AUDIT_IS_PAUSED = 0; + + // Fetch the task structure of the process that opened the device + auditdaemon_task_struct = current; +#if !defined(SNARE_RED_HAT_LINUX_KERNEL) && ( LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) ) + nicevalue = auditdaemon_task_struct->nice; +#else + nicevalue = PRIO_TO_NICE(auditdaemon_task_struct->static_prio); +#endif + + // reset our read position to the beginning of head event data + read_position = NULL; + + up(&audit_lock); + + printk("Auditing: Process %d has opened the device\n", + auditdaemon_task_struct->pid); + + return 0; +} + +//////////////////////////////////////////////////////////////////////////////// +// close the device and release resources +//////////////////////////////////////////////////////////////////////////////// +static int auditproc_close(struct inode *node, struct file *the_file) +{ + int counter; +#if SHOW_EVENT_COUNTER + int l_lost_events, l_total_events; +#endif + + // Only the task that opened the audit device can + // close the device. We don't want another thread + // to interfere. + if(auditdaemon_task_struct != current) { + return(0); + } + + for (counter = 1; counter <= MAXAUDIT; counter++) { + audit_off(counter); + } + + down(&audit_lock); + AUDIT_IS_RUNNING = 0; + + auditdaemon_task_struct = NULL; +#if SHOW_EVENT_COUNTER + l_lost_events = lost_events; + l_total_events = total_events; +#endif + lost_events = 0; + total_events = 0; + memory_usage = 0; + AUDIT_IS_PAUSED = 0; + + up(&audit_lock); + + printk("AUDIT: Audit daemon has closed /proc/audit.\n"); +#if SHOW_EVENT_COUNTER + printk("AUDIT: Events lost due low memory this session: %d\n", + l_lost_events); + printk("AUDIT: Total Events processed this session: %d\n", + l_total_events); +#endif + + return 0; +} + +static void audit_on(int auditnumber) +{ + if(auditnumber <= 0 || auditnumber > MAXAUDIT) { + return; + } + down(&audit_lock); + set_bit(auditnumber, active_events); + up(&audit_lock); +} + +static void audit_off(int auditnumber) +{ + if(auditnumber <= 0 || auditnumber > MAXAUDIT) { + return; + } + down(&audit_lock); + clear_bit(auditnumber, active_events); + up(&audit_lock); +} + +int _audit_mknod(const char *kfile, const char __user *ufile, int mode, dev_t dev, + int retval) +{ + io_class *record; + + // If noone has requested MKNOD to be active, return quickly. + if (!saudit_active(AUDIT_mknod)) + return (0); + audit_hwcheck(); + if (current == auditdaemon_task_struct || AUDIT_IS_PAUSED) + return (0); + if (current->saudit_record) + return (1); + + // alloc the audit record + current->saudit_record = kmalloc(sizeof(io_class), GFP_KERNEL); + if (!current->saudit_record) { + return (0); + } + + record = (io_class *) current->saudit_record; + + // Filename. + GrabString(record->t_path.path, kfile, ufile, MAX_PATH); + + record->t_attributes.mode = (int) mode; + record->t_attributes.createmode = (unsigned long) dev; + + record->t_header.event_id = AUDIT_mknod; + record->t_header.event_class = AUDIT_CLASS_IO; + saudit_return(retval); + return (1); +} + +/* + * argcount() counts the number of strings in array ARGV. + */ +static int argcount(char __user * __user * argv, int max) +{ + int i = 0; + + if (argv != NULL) { + for (;;) { + char __user * p; + + if (get_user(p, argv)) + return -EFAULT; + if (!p) + break; + argv++; + if(++i > max) + return -E2BIG; + } + } + return i; +} + +char *saudit_copy_argv(char __user *__user *argv) +{ + char *returnstring; + // char tempstring[MAX_PATH]; + char *tempstring; + int argc, argi; + char __user *str; + unsigned int delimiter_required = 0; + + if (!saudit_active(AUDIT_execve)) + return ((char *) NULL); + audit_hwcheck(); + if (current == auditdaemon_task_struct || AUDIT_IS_PAUSED) + return ((char *) NULL); + + argc=argcount(argv, 1024); /* avoid infinite loop on bad data */ + if (argc < 0) { + return ((char *) NULL); + } + + // + // Dont check saudit_record for NULL Since it it will be here + // + tempstring = kmalloc(MAX_PATH, GFP_KERNEL); + if (!tempstring) + return ((char *) NULL); // Out of mem + + tempstring[0] = '\0'; + returnstring = kmalloc(MAX_PATH, GFP_KERNEL); + if (!returnstring) { + kfree(tempstring); + return ((char *) NULL); // Out of mem + } + returnstring[0] = '\0'; + argi=0; + + while (argi < argc) { + if (get_user(str, argv+argi)) { + continue; + } + strncpy_from_user(tempstring, str, MAX_PATH - 1); + tempstring[MAX_PATH-1] = '\0'; + + // Allow for the delimiter + if ((strlen(returnstring) + strlen(tempstring) + 1) < + (MAX_PATH - 1)) { + if (!delimiter_required) { + delimiter_required = 1; + } else { + strcat(returnstring, " "); + } + strcat(returnstring, tempstring); + } else { + // If the argument size is greater than MAX_PATH, then + // ignore this argument, continue on to the next. + argi++; + continue; + } + argi++; + } + kfree(tempstring); + + return (returnstring); +} + +int _audit_execve(const char __user *ufilename, const char *kfilename, + char *arguments, int retval) +{ + ex_class *record; + + if (!saudit_active(AUDIT_execve)) { + if (arguments) { + kfree(arguments); + } + return (0); + } + audit_hwcheck(); + if (current == auditdaemon_task_struct || AUDIT_IS_PAUSED) { + if (arguments) { + kfree(arguments); + } + return (0); + } + + if (current->saudit_record) { + if (arguments) { + kfree(arguments); + } + return (1); + } + + // alloc the audit record + current->saudit_record = kmalloc(sizeof(ex_class), GFP_KERNEL); + if (!current->saudit_record) { + if (arguments) { + kfree(arguments); + } + return (0); + } + + record = (ex_class *) current->saudit_record; + + // Use our new grabstring routine + GrabString(record->t_path.path, kfilename, ufilename, MAX_PATH); + + if (arguments) { + strncpy(record->t_execargs.args, arguments, MAX_PATH); + kfree(arguments); + } else { + strcat(record->t_execargs.args, ""); + } + + record->t_header.event_id = AUDIT_execve; + record->t_header.event_class = AUDIT_CLASS_EXEC; + + saudit_return(retval); + return (0); +} + + +int _audit_exit(int retval) +{ + pc_class *record; + + if (!saudit_active(AUDIT_exit)) + return (0); + audit_hwcheck(); + if (current == auditdaemon_task_struct || AUDIT_IS_PAUSED) + return (0); + if (current->saudit_record) + return (1); + + // alloc the audit record + current->saudit_record = kmalloc(sizeof(pc_class), GFP_KERNEL); + if (!current->saudit_record) { + return (0); + } + + record = (pc_class *) current->saudit_record; + record->t_header.event_id = AUDIT_exit; + record->t_header.event_class = AUDIT_CLASS_PC; + saudit_return(retval); + return (1); +} + +int _audit_fork(int retval) +{ + pc_class *record; + + if (!saudit_active(AUDIT_fork)) + return (0); + audit_hwcheck(); + if (current == auditdaemon_task_struct || AUDIT_IS_PAUSED) + return (0); + if (current->saudit_record) + return (1); + + // alloc the audit record + current->saudit_record = kmalloc(sizeof(pc_class), GFP_KERNEL); + if (!current->saudit_record) { + return (0); + } + + record = (pc_class *) current->saudit_record; + record->t_header.event_id = AUDIT_fork; + record->t_header.event_class = AUDIT_CLASS_PC; + saudit_return(retval); + return (1); +} + +int _audit_open(const char *kfile, const char __user *ufile, int flags, int mode, + int retval) +{ + io_class *record; + + if (!saudit_active(AUDIT_open)) + return (0); + audit_hwcheck(); + if (current == auditdaemon_task_struct || AUDIT_IS_PAUSED) + return (0); + if (current->saudit_record) + return (1); + + // alloc the audit record + current->saudit_record = kmalloc(sizeof(io_class), GFP_KERNEL); + if (!current->saudit_record) { + return (0); + } + + record = (io_class *) current->saudit_record; + + // Filename. + GrabString(record->t_path.path, kfile, ufile, MAX_PATH); + + record->t_attributes.mode = flags; + record->t_attributes.createmode = mode; + + record->t_header.event_id = AUDIT_open; + record->t_header.event_class = AUDIT_CLASS_IO; + + saudit_return(retval); + return (1); +} + +int _audit_mkdir(const char *kfile, const char __user *ufile, int mode, int retval) +{ + io_class *record; + + // If noone has requested the system call to be active, return quickly. + if (!saudit_active(AUDIT_mkdir)) + return (0); + audit_hwcheck(); + if (current == auditdaemon_task_struct || AUDIT_IS_PAUSED) + return (0); + if (current->saudit_record) + return (1); + + // alloc the audit record + current->saudit_record = kmalloc(sizeof(io_class), GFP_KERNEL); + if (!current->saudit_record) { + return (0); + } + + record = (io_class *) current->saudit_record; + + // Filename. + GrabString(record->t_path.path, kfile, ufile, MAX_PATH); + + record->t_attributes.mode = 0; + record->t_attributes.createmode = mode; + + record->t_header.event_id = AUDIT_mkdir; + record->t_header.event_class = AUDIT_CLASS_IO; + saudit_return(retval); + return (1); +} + +int _audit_unlink(const char *kfile, const char __user *ufile, int retval) +{ + io_class *record; + + // If noone has requested the system call to be active, return quickly. + if (!saudit_active(AUDIT_unlink)) + return (0); + audit_hwcheck(); + if (current == auditdaemon_task_struct || AUDIT_IS_PAUSED) + return (0); + if (current->saudit_record) + return (1); + + // alloc the audit record + current->saudit_record = kmalloc(sizeof(io_class), GFP_KERNEL); + if (!current->saudit_record) { + return (0); + } + + record = (io_class *) current->saudit_record; + + // Filename. + GrabString(record->t_path.path, kfile, ufile, MAX_PATH); + + record->t_attributes.mode = 0; + record->t_attributes.createmode = 0; + + record->t_header.event_id = AUDIT_unlink; + record->t_header.event_class = AUDIT_CLASS_IO; + saudit_return(retval); + return (1); +} + +int _audit_rmdir(const char *kfile, const char __user *ufile, int retval) +{ + io_class *record; + + // If noone has requested the system call to be active, return quickly. + if (!saudit_active(AUDIT_rmdir)) + return (0); + audit_hwcheck(); + if (current == auditdaemon_task_struct || AUDIT_IS_PAUSED) + return (0); + if (current->saudit_record) + return (1); + + // alloc the audit record + current->saudit_record = kmalloc(sizeof(io_class), GFP_KERNEL); + if (!current->saudit_record) { + return (0); + } + + record = (io_class *) current->saudit_record; + + // Filename. + GrabString(record->t_path.path, kfile, ufile, MAX_PATH); + + record->t_attributes.mode = 0; + record->t_attributes.createmode = 0; + + record->t_header.event_id = AUDIT_rmdir; + record->t_header.event_class = AUDIT_CLASS_IO; + saudit_return(retval); + return (1); +} + +int _audit_chown(const char *kfile, const char __user *ufile, uid_t user, + gid_t group, int retval) +{ + ch_class *record; + + // If noone has requested the system call to be active, return quickly. + if (!saudit_active(AUDIT_chown)) + return (0); + audit_hwcheck(); + if (current == auditdaemon_task_struct || AUDIT_IS_PAUSED) + return (0); + if (current->saudit_record) + return (1); + + // alloc the audit record + current->saudit_record = kmalloc(sizeof(ch_class), GFP_KERNEL); + if (!current->saudit_record) { + return (0); + } + + record = (ch_class *) current->saudit_record; + + // Filename. + GrabString(record->t_path.path, kfile, ufile, MAX_PATH); + + record->t_owner.owner = (int) user; + record->t_owner.group = (int) group; + + record->t_header.event_id = AUDIT_chown; + record->t_header.event_class = AUDIT_CLASS_CH; + saudit_return(retval); + return (1); +} + +int _audit_chmod(const char *kfile, const char __user *ufile, mode_t mode, + int retval) +{ + io_class *record; + + // If noone has requested the system call to be active, return quickly. + if (!saudit_active(AUDIT_chmod)) + return (0); + audit_hwcheck(); + if (current == auditdaemon_task_struct || AUDIT_IS_PAUSED) + return (0); + if (current->saudit_record) + return (1); + + // alloc the audit record + current->saudit_record = kmalloc(sizeof(io_class), GFP_KERNEL); + if (!current->saudit_record) { + return (0); + } + + record = (io_class *) current->saudit_record; + + // Filename. + GrabString(record->t_path.path, kfile, ufile, MAX_PATH); + + record->t_attributes.mode = 0; + record->t_attributes.createmode = (unsigned long) mode; + + record->t_header.event_id = AUDIT_chmod; + record->t_header.event_class = AUDIT_CLASS_IO; + saudit_return(retval); + return (1); +} + +int _audit_symlink(const char *kfrom, const char __user *ufrom, const char *kto, + const char __user *uto, int retval) +{ + cp_class *record; + + // If noone has requested the system call to be active, return quickly. + if (!saudit_active(AUDIT_symlink)) + return (0); + audit_hwcheck(); + if (current == auditdaemon_task_struct || AUDIT_IS_PAUSED) + return (0); + + if (current->saudit_record) { + return (1); + } + // alloc the audit record + current->saudit_record = kmalloc(sizeof(cp_class), GFP_KERNEL); + if (!current->saudit_record) { + return (0); + } + + record = (cp_class *) current->saudit_record; + + // Filename. + GrabString(record->t_sourcepath.path, kfrom, ufrom, MAX_PATH); + GrabString(record->t_destpath.path, kto, uto, MAX_PATH); + + record->t_header.event_id = AUDIT_symlink; + record->t_header.event_class = AUDIT_CLASS_CP; + + saudit_return(retval); + return (1); +} + +int _audit_link(const char *kfrom, const char __user *ufrom, const char *kto, + const char __user *uto, int retval) +{ + cp_class *record; + + // If noone has requested the system call to be active, return quickly. + if (!saudit_active(AUDIT_link)) + return (0); + audit_hwcheck(); + if (current == auditdaemon_task_struct || AUDIT_IS_PAUSED) + return (0); + + if (current->saudit_record) { + return (1); + } + // alloc the audit record + current->saudit_record = kmalloc(sizeof(cp_class), GFP_KERNEL); + if (!current->saudit_record) { + return (0); + } + + record = (cp_class *) current->saudit_record; + + // Filename. + GrabString(record->t_sourcepath.path, kfrom, ufrom, MAX_PATH); + GrabString(record->t_destpath.path, kto, uto, MAX_PATH); + + record->t_header.event_id = AUDIT_link; + record->t_header.event_class = AUDIT_CLASS_CP; + + saudit_return(retval); + return (1); +} + +int _audit_rename(const char *kfrom, const char __user *ufrom, const char *kto, + const char __user *uto, int retval) +{ + cp_class *record; + + // If noone has requested the system call to be active, return quickly. + if (!saudit_active(AUDIT_rename)) + return (0); + audit_hwcheck(); + if (current == auditdaemon_task_struct || AUDIT_IS_PAUSED) + return (0); + if (current->saudit_record) + return (1); + + // alloc the audit record + current->saudit_record = kmalloc(sizeof(cp_class), GFP_KERNEL); + if (!current->saudit_record) { + return (0); + } + + record = (cp_class *) current->saudit_record; + + // Filename. + GrabString(record->t_sourcepath.path, kfrom, ufrom, MAX_PATH); + GrabString(record->t_destpath.path, kto, uto, MAX_PATH); + + record->t_header.event_id = AUDIT_rename; + record->t_header.event_class = AUDIT_CLASS_CP; + saudit_return(retval); + return (1); +} + +// Truncate - note that we need to grab the data from userspace. +int _audit_truncate(const char *kfile, const char __user *ufile, loff_t length, + int retval) +{ + io_class *record; + + // If noone has requested the system call to be active, return quickly. + if (!saudit_active(AUDIT_truncate)) + return (0); + audit_hwcheck(); + if (current == auditdaemon_task_struct || AUDIT_IS_PAUSED) + return (0); + + if (current->saudit_record) { + return (1); + } + // alloc the audit record + current->saudit_record = kmalloc(sizeof(io_class), GFP_KERNEL); + if (!current->saudit_record) { + return (0); + } + + record = (io_class *) current->saudit_record; + + // Filename. + GrabString(record->t_path.path, kfile, ufile, MAX_PATH); + + record->t_attributes.createmode = (unsigned long) length; + + record->t_header.event_id = AUDIT_truncate; + record->t_header.event_class = AUDIT_CLASS_IO; + saudit_return(retval); + return (1); +} + +int _audit_chroot(const char *kfile, const char __user *ufile, int retval) +{ + io_class *record; + + // If noone has requested the system call to be active, return quickly. + if (!saudit_active(AUDIT_chroot)) + return (0); + audit_hwcheck(); + if (current == auditdaemon_task_struct || AUDIT_IS_PAUSED) + return (0); + + if (current->saudit_record) { + return (1); + } + // alloc the audit record + current->saudit_record = kmalloc(sizeof(io_class), GFP_KERNEL); + if (!current->saudit_record) { + return (0); + } + + record = (io_class *) current->saudit_record; + + // Filename. + GrabString(record->t_path.path, kfile, ufile, MAX_PATH); + + record->t_attributes.createmode = (unsigned long) 0; + + record->t_header.event_id = AUDIT_chroot; + record->t_header.event_class = AUDIT_CLASS_IO; + + saudit_return(retval); + return (1); +} + +int _audit_mount(const char *kdev_name, const char __user *udev_name, + const char *kdir_name, const char __user *udir_name, + unsigned long flags, int retval) +{ + cp_class *record; + + // If noone has requested the system call to be active, return quickly. + if (!saudit_active(AUDIT_mount)) + return (0); + + audit_hwcheck(); + if (current == auditdaemon_task_struct || AUDIT_IS_PAUSED) + return (0); + if (current->saudit_record) + return (1); + + // alloc the audit record + current->saudit_record = kmalloc(sizeof(cp_class), GFP_KERNEL); + if (!current->saudit_record) { + return (0); + } + + record = (cp_class *) current->saudit_record; + + GrabString(record->t_sourcepath.path, kdev_name, udev_name, + MAX_PATH); + GrabString(record->t_destpath.path, kdir_name, udir_name, + MAX_PATH); + + record->t_header.event_id = AUDIT_mount; + record->t_header.event_class = AUDIT_CLASS_CP; + + saudit_return(retval); + return (1); +} + +int _audit_umount(const char *kname, const char __user *uname, int flags, + int retval) +{ + cp_class *record; + + // If noone has requested the system call to be active, return quickly. + if (!saudit_active(AUDIT_umount)) + return (0); + audit_hwcheck(); + if (current == auditdaemon_task_struct || AUDIT_IS_PAUSED) + return (0); + if (current->saudit_record) + return (1); + + // alloc the audit record + current->saudit_record = kmalloc(sizeof(cp_class), GFP_KERNEL); + if (!current->saudit_record) { + return (0); + } + + record = (cp_class *) current->saudit_record; + + record->t_sourcepath.path[0] = '\0'; + // Name has not yet been grabbed from userspace by sys_umount + // Copy it from userspace here. + GrabString(record->t_sourcepath.path, kname, uname, MAX_PATH); + + record->t_destpath.path[0] = '\0'; + + record->t_header.event_id = AUDIT_umount; + record->t_header.event_class = AUDIT_CLASS_CP; + saudit_return(retval); + return (1); +} + +int _audit_setuid(uid_t uid, int retval) +{ + su_class *record; + + // If noone has requested the system call to be active, return quickly. + if (!saudit_active(AUDIT_setuid)) + return (0); + audit_hwcheck(); + if (current == auditdaemon_task_struct || AUDIT_IS_PAUSED) + return (0); + if (current->saudit_record) + return (1); + + // alloc the audit record + current->saudit_record = kmalloc(sizeof(su_class), GFP_KERNEL); + if (!current->saudit_record) { + return (0); + } + + record = (su_class *) current->saudit_record; + + record->t_target.id = uid; + + record->t_header.event_id = AUDIT_setuid; + record->t_header.event_class = AUDIT_CLASS_SU; + saudit_return(retval); + return (1); +} + +int _audit_setreuid(uid_t ruid, uid_t euid, int retval) +{ + su_class *record; + + // If noone has requested the system call to be active, return quickly. + if (!saudit_active(AUDIT_setreuid)) + return (0); + audit_hwcheck(); + if (current == auditdaemon_task_struct || AUDIT_IS_PAUSED) + return (0); + if (current->saudit_record) + return (1); + + // alloc the audit record + current->saudit_record = kmalloc(sizeof(su_class), GFP_KERNEL); + if (!current->saudit_record) { + return (0); + } + + record = (su_class *) current->saudit_record; + + record->t_target.id = euid; + record->t_target.rid = ruid; + + record->t_header.event_id = AUDIT_setreuid; + record->t_header.event_class = AUDIT_CLASS_SU; + saudit_return(retval); + return (1); +} + +int _audit_setresuid(uid_t ruid, uid_t euid, uid_t suid, int retval) +{ + su_class *record; + + // If noone has requested the system call to be active, return quickly. + if (!saudit_active(AUDIT_setresuid)) + return (0); + audit_hwcheck(); + if (current == auditdaemon_task_struct || AUDIT_IS_PAUSED) + return (0); + if (current->saudit_record) + return (1); + + // alloc the audit record + current->saudit_record = kmalloc(sizeof(su_class), GFP_KERNEL); + if (!current->saudit_record) { + return (0); + } + + record = (su_class *) current->saudit_record; + + record->t_target.id = euid; + record->t_target.rid = ruid; + record->t_target.sid = suid; + + record->t_header.event_id = AUDIT_setresuid; + record->t_header.event_class = AUDIT_CLASS_SU; + saudit_return(retval); + return (1); +} + +int _audit_setregid(gid_t rgid, gid_t egid, int retval) +{ + su_class *record; + + // If noone has requested the system call to be active, return quickly. + if (!saudit_active(AUDIT_setregid)) + return (0); + audit_hwcheck(); + if (current == auditdaemon_task_struct || AUDIT_IS_PAUSED) + return (0); + if (current->saudit_record) + return (1); + + // alloc the audit record + current->saudit_record = kmalloc(sizeof(su_class), GFP_KERNEL); + if (!current->saudit_record) { + return (0); + } + + record = (su_class *) current->saudit_record; + + record->t_target.id = egid; + record->t_target.rid = rgid; + + record->t_header.event_id = AUDIT_setregid; + record->t_header.event_class = AUDIT_CLASS_SU; + saudit_return(retval); + return (1); +} + +int _audit_setresgid(gid_t rgid, gid_t egid, gid_t sgid, int retval) +{ + su_class *record; + + // If noone has requested the system call to be active, return quickly. + if (!saudit_active(AUDIT_setresgid)) + return (0); + audit_hwcheck(); + if (current == auditdaemon_task_struct || AUDIT_IS_PAUSED) + return (0); + if (current->saudit_record) + return (1); + + // alloc the audit record + current->saudit_record = kmalloc(sizeof(su_class), GFP_KERNEL); + if (!current->saudit_record) { + return (0); + } + + record = (su_class *) current->saudit_record; + + record->t_target.id = egid; + record->t_target.rid = rgid; + record->t_target.sid = sgid; + + record->t_header.event_id = AUDIT_setresgid; + record->t_header.event_class = AUDIT_CLASS_SU; + saudit_return(retval); + return (1); +} + +int _audit_setgid(gid_t gid, int retval) +{ + su_class *record; + + // If noone has requested the system call to be active, return quickly. + if (!saudit_active(AUDIT_setgid)) + return (0); + audit_hwcheck(); + if (current == auditdaemon_task_struct || AUDIT_IS_PAUSED) + return (0); + if (current->saudit_record) + return (1); + + // alloc the audit record + current->saudit_record = kmalloc(sizeof(su_class), GFP_KERNEL); + if (!current->saudit_record) { + return (0); + } + + record = (su_class *) current->saudit_record; + + record->t_target.id = gid; + + record->t_header.event_id = AUDIT_setgid; + record->t_header.event_class = AUDIT_CLASS_SU; + saudit_return(retval); + return (1); +} + +// Create module +int _audit_create_module(const char *kname, const char __user *uname, int retval) +{ + ad_class *record; + + // If noone has requested the system call to be active, return quickly. + if (!saudit_active(AUDIT_create_module)) + return (0); + audit_hwcheck(); + if (current == auditdaemon_task_struct || AUDIT_IS_PAUSED) + return (0); + + if (current->saudit_record) { + return (1); + } + // alloc the audit record + current->saudit_record = kmalloc(sizeof(ad_class), GFP_KERNEL); + if (!current->saudit_record) { + return (0); + } + + record = (ad_class *) current->saudit_record; + + // Module name + GrabString(record->t_name.path, kname, uname, MAX_PATH); + + record->t_header.event_id = AUDIT_create_module; + record->t_header.event_class = AUDIT_CLASS_AD; + saudit_return(retval); + return (1); +} + +// Delete module +int _audit_delete_module(const char *kname, const char __user *uname, int retval) +{ + ad_class *record; + + // If noone has requested the system call to be active, return quickly. + if (!saudit_active(AUDIT_delete_module)) + return (0); + audit_hwcheck(); + if (current == auditdaemon_task_struct || AUDIT_IS_PAUSED) + return (0); + + if (current->saudit_record) { + return (1); + } + // alloc the audit record + current->saudit_record = kmalloc(sizeof(ad_class), GFP_KERNEL); + if (!current->saudit_record) { + return (0); + } + + record = (ad_class *) current->saudit_record; + + // Module name + GrabString(record->t_name.path, kname, uname, MAX_PATH); + + record->t_header.event_id = AUDIT_delete_module; + record->t_header.event_class = AUDIT_CLASS_AD; + saudit_return(retval); + return (1); +} + +int _audit_reboot(int magic1, int magic2, unsigned int cmd, void __user *arg, + int retval) +{ + pc_class *record; + + // If noone has requested the system call to be active, return quickly. + if (!saudit_active(AUDIT_reboot)) + return (0); + audit_hwcheck(); + if (current == auditdaemon_task_struct || AUDIT_IS_PAUSED) + return (0); + if (current->saudit_record) + return (1); + + // alloc the audit record + current->saudit_record = kmalloc(sizeof(pc_class), GFP_KERNEL); + if (!current->saudit_record) { + return (0); + } + + record = (pc_class *) current->saudit_record; + record->t_header.event_id = AUDIT_reboot; + record->t_header.event_class = AUDIT_CLASS_PC; + saudit_return(retval); + return (1); +} + +int _audit_connect(int sockfd, struct sockaddr __user *serv_addr, int addrlen, + int retval) +{ + nt_class *record; + struct socket *sock; + int err; + struct sockaddr_in *si; + + // If noone has requested the system call to be active, return quickly. + if (!saudit_active(AUDIT_connect)) { + return (0); + } + + audit_hwcheck(); + if (current == auditdaemon_task_struct || AUDIT_IS_PAUSED) + return (0); + if (current->saudit_record) + return (0); + + // If this is not an AF_INET, drop it. + if (!serv_addr) { + return (0); + } + if (serv_addr->sa_family != AF_INET) { + return (0); + } + + if (serv_addr->sa_data) { + return (0); + } + + // alloc the audit record + current->saudit_record = kmalloc(sizeof(nt_class), GFP_KERNEL); + if (!current->saudit_record) { + return (0); + } + + record = (nt_class *) current->saudit_record; + record->t_header.event_id = AUDIT_connect; + record->t_header.event_class = AUDIT_CLASS_NET; + + snprintf(record->t_connection.dst_ip, 16, "%u.%u.%u.%u", + serv_addr->sa_data[2] & 255, + serv_addr->sa_data[3] & 255, + serv_addr->sa_data[4] & 255, serv_addr->sa_data[5] & 255); + strncpy(record->t_connection.src_ip, "127.0.0.1", 16); + + si = (struct sockaddr_in *) serv_addr; + + record->t_connection.src_port = 0; + record->t_connection.dst_port = ntohs(si->sin_port); + + record->t_connection.protocol = 0; + + if(sockfd) { + if ((sock = sockfd_lookup(sockfd, &err)) != NULL) { + // 2.4 + // record->t_connection.src_port = sock->sk->num; + // record->t_connection.protocol = sock->sk->protocol; + // 2.6 + record->t_connection.src_port = htons(inet_sk(sock->sk)->num); + record->t_connection.protocol = 0; + // fput(sock->file); + sockfd_put(sock); + } + } + saudit_return(retval); + return (1); +} + +int _audit_accept(int sockfd, struct sockaddr __user *peer_addr, int *addrlen, + int retval) +{ + nt_class *record; + struct sockaddr_in *si; + struct socket *sock; + int err; + + // If noone has requested the system call to be active, return quickly. + if (!saudit_active(AUDIT_accept)) { + return (0); + } + + audit_hwcheck(); + if (current == auditdaemon_task_struct || AUDIT_IS_PAUSED) + return (0); + if (current->saudit_record) + return (0); + + // If this is not an AF_INET, drop it. + if (!peer_addr) { + return (0); + } + if (peer_addr->sa_family != AF_INET) { + return (0); + } + + if (peer_addr->sa_data) { + return (0); + } + // alloc the audit record + current->saudit_record = kmalloc(sizeof(nt_class), GFP_KERNEL); + if (!current->saudit_record) { + return (0); + } + + record = (nt_class *) current->saudit_record; + record->t_header.event_id = AUDIT_accept; + record->t_header.event_class = AUDIT_CLASS_NET; + + snprintf(record->t_connection.src_ip, 16, "%u.%u.%u.%u", + peer_addr->sa_data[2] & 255, + peer_addr->sa_data[3] & 255, + peer_addr->sa_data[4] & 255, peer_addr->sa_data[5] & 255); + strncpy(record->t_connection.dst_ip, "127.0.0.1", 16); + + si = (struct sockaddr_in *) peer_addr; + + record->t_connection.dst_port = 0; + record->t_connection.src_port = ntohs(si->sin_port); + + record->t_connection.protocol = 0; + + if(sockfd) { + if ((sock = sockfd_lookup(sockfd, &err)) != NULL) { + // 2.4 + // record->t_connection.dst_port = ntohs(sock->sk->sport); + // record->t_connection.protocol = sock->sk->protocol; + // 2.6 + record->t_connection.dst_port = ntohs(inet_sk(sock->sk)->sport); + record->t_connection.protocol = 0; + sockfd_put(sock); + // fput(sock->file); + } + } + saudit_return(retval); + return (1); +} + +int saudit_return(int returncode) +{ + // The static null_class and timeval were changed to + // Local varable for smp machines + + int class; + null_class *any_event; + AuditNode *node = (AuditNode *) NULL; + struct timeval time_temp; + + if (!auditdaemon_task_struct) { + goto out; + } + + if (current == auditdaemon_task_struct) { + return (0); + } + + // Unaudited event + if (!current->saudit_record) { + goto out; + } + + any_event = current->saudit_record; + + do_gettimeofday(&time_temp); + + class = any_event->t_header.event_class; + + // Fill out as much of the header structure as we can. + any_event->t_header.user_id = current->uid; + any_event->t_header.group_id = current->gid; + any_event->t_header.euser_id = current->euid; + any_event->t_header.egroup_id = current->egid; + any_event->t_header.time.tv_sec = time_temp.tv_sec; + any_event->t_header.time.tv_usec = time_temp.tv_usec; + any_event->t_header.returncode = returncode; + strncpy(any_event->t_header.processname, current->comm, + MAXCOMMAND); + any_event->t_header.pid = current->pid; + +#if defined(SNARE_RED_HAT_LINUX_KERNEL) + // Note: RHEL 2.4.18 doesn't have current->parent.. + if (current->parent) { + any_event->t_header.ppid = current->parent->pid; + } else { + any_event->t_header.ppid = 0; + } +#else + if(current->p_pptr) { + any_event->t_header.ppid=current->p_pptr->pid; + } else { + any_event->t_header.ppid=0; + } +#endif + + // Modified by Mark Westerman Replaced the if else code with + // a switch to help perfromace. + switch (class) { + case AUDIT_CLASS_IO: + { + io_class *record; + char tmp[MAX_PATH]; + record = (io_class *) current->saudit_record; + + // Current PWD - IO CLASS, EXEC, CH, CP + // NOTE: This will just tell you the file name the user + // tried to access. If it's linked to another file, or + // from a mountpoint, it will just show you the filename + // used in the system call - not the RESOLVED path. + strncpy(record->t_pwd.path, + d_path(current->fs->pwd, + current->fs->pwdmnt, tmp, MAX_PATH), + MAX_PATH); + + record->t_header.event_size = + sizeof(io_class) - sizeof(header_token); + + if ((node = alloc_event(sizeof(io_class))) == NULL) { + goto out; + } + node->location=record; + } + break; + case AUDIT_CLASS_EXEC: + { + ex_class *record; + char tmp[MAX_PATH]; + record = (ex_class *) current->saudit_record; + + // Current PWD - IO CLASS, EXEC, CH, CP + strncpy(record->t_pwd.path, + d_path(current->fs->pwd, + current->fs->pwdmnt, tmp, MAX_PATH), + MAX_PATH); + + record->t_header.event_size = + sizeof(ex_class) - sizeof(header_token); + + if ((node = alloc_event(sizeof(ex_class))) == NULL) { + goto out; + } + node->location=record; + } + break; + case AUDIT_CLASS_PC: + { + pc_class *record; + record = (pc_class *) current->saudit_record; + + // Current PWD - IO CLASS, EXEC, CH, CP + record->t_header.event_size = + sizeof(pc_class) - sizeof(header_token); + + if ((node = alloc_event(sizeof(pc_class))) == NULL) { + goto out; + } + node->location=record; + } + break; + case AUDIT_CLASS_CH: + { + ch_class *record; + char tmp[MAX_PATH]; + record = (ch_class *) current->saudit_record; + + // Current PWD - IO CLASS, EXEC, CH, CP + strncpy(record->t_pwd.path, + d_path(current->fs->pwd, + current->fs->pwdmnt, tmp, MAX_PATH), + MAX_PATH); + record->t_header.event_size = + sizeof(ch_class) - sizeof(header_token); + + if ((node = alloc_event(sizeof(ch_class))) == NULL) { + goto out; + } + node->location=record; + } + break; + case AUDIT_CLASS_CP: + { + cp_class *record; + char tmp[MAX_PATH]; + record = (cp_class *) current->saudit_record; + + // Current PWD - IO CLASS, EXEC, CH, CP + strncpy(record->t_pwd.path, + d_path(current->fs->pwd, + current->fs->pwdmnt, tmp, MAX_PATH), + MAX_PATH); + record->t_header.event_size = + sizeof(cp_class) - sizeof(header_token); + + if ((node = alloc_event(sizeof(cp_class))) == NULL) { + goto out; + } + node->location=record; + } + break; + case AUDIT_CLASS_SU: + { + su_class *record; + record = (su_class *) current->saudit_record; + + record->t_header.event_size = + sizeof(su_class) - sizeof(header_token); + + if ((node = alloc_event(sizeof(su_class))) == NULL) { + goto out; + } + node->location=record; + } + break; + case AUDIT_CLASS_AD: + { + ad_class *record; + record = (ad_class *) current->saudit_record; + + record->t_header.event_size = + sizeof(ad_class) - sizeof(header_token); + + if ((node = alloc_event(sizeof(ad_class))) == NULL) { + goto out; + } + node->location=record; + } + break; + case AUDIT_CLASS_NET: + { + nt_class *record; + record = (nt_class *) current->saudit_record; + + record->t_header.event_size = + sizeof(nt_class) - sizeof(header_token); + + if ((node = alloc_event(sizeof(nt_class))) == NULL) { + goto out; + } + node->location=record; + + } + break; + default: + printk("Auditing Invalid class\n"); + } + + // Cant free this here.. we're still using it. + current->saudit_record = NULL; + + // Send the audit record out the door. + append_event(node); + wake_up_interruptible(&proc_audit_queue); + + return (1); + + out: + if (current->saudit_record) { + current->saudit_record = NULL; + } + if(auditdaemon_task_struct) { + down(&audit_lock); + lost_events++; + up(&audit_lock); + } + return (0); +} + +static void append_event(AuditNode * nodepointer) +{ + down(&audit_lock); + + if (list_tail != (AuditNode *) NULL) { + list_tail->next = nodepointer; + } + + list_tail = nodepointer; + + // Is this the first node in our linked list? + if (list_head == (AuditNode *) NULL) { + list_head = nodepointer; + } + memory_usage += nodepointer->size; + ++total_events; + up(&audit_lock); +} + +AuditNode *alloc_event(int token_size) +{ + AuditNode *nodepointer; + + nodepointer = (AuditNode *) kmalloc(sizeof(AuditNode), GFP_KERNEL); + if (nodepointer == (AuditNode *) NULL) { + return (0); + } + + nodepointer->location = (void *)NULL; + nodepointer->size = token_size; + nodepointer->next = (AuditNode *) NULL; // This is the end. + return nodepointer; +} + +// This grabs data from either kernel or userspace into a string. +long GrabString(char *destination, const char *kernelstring, + const char __user *userstring, int length) +{ + if (!destination) + return (0); + + if (length < 1) + return (0); + + if (!userstring && !kernelstring) { + strncpy(destination, "AUDIT: Invalid data", length); + return (0); + } + + if (kernelstring) { + strncpy(destination, kernelstring, length); + return (1); + } else { + if (strncpy_from_user(destination, userstring, length) == + -EFAULT) { + strncpy(destination, "AUDIT: Invalid data", + length); + return (0); + } + return (1); + } +} diff -Nru linux-2.6.10-2.3.legacy_FC2/security/snare/Makefile linux-2.6.10-2.3.legacy_FC2-snare/security/snare/Makefile --- linux-2.6.10-2.3.legacy_FC2/security/snare/Makefile 1970-01-01 10:00:00.000000000 +1000 +++ linux-2.6.10-2.3.legacy_FC2-snare/security/snare/Makefile 2006-04-13 06:35:52.000000000 +1000 @@ -0,0 +1,8 @@ +# +# Makefile for building snare as part of the kernel tree. +# + +obj-y := auditapi.o + +snare-y := auditapi.o +