authpf.c (153722) | authpf.c (171172) |
---|---|
1/* $OpenBSD: authpf.c,v 1.89 2005/02/10 04:24:15 joel Exp $ */ | 1/* $OpenBSD: authpf.c,v 1.104 2007/02/24 17:35:08 beck Exp $ */ |
2 3/* | 2 3/* |
4 * Copyright (C) 1998 - 2002 Bob Beck (beck@openbsd.org). | 4 * Copyright (C) 1998 - 2007 Bob Beck (beck@openbsd.org). |
5 * | 5 * |
6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. | 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. |
14 * | 9 * |
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. | 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
26 */ 27 28#include <sys/cdefs.h> | 17 */ 18 19#include <sys/cdefs.h> |
29__FBSDID("$FreeBSD: head/contrib/pf/authpf/authpf.c 153722 2005-12-25 22:57:08Z mlaier $"); | 20__FBSDID("$FreeBSD: head/contrib/pf/authpf/authpf.c 171172 2007-07-03 12:30:03Z mlaier $"); |
30 31#include <sys/param.h> 32#include <sys/file.h> 33#include <sys/ioctl.h> 34#include <sys/socket.h> 35#include <sys/stat.h> 36#include <sys/time.h> 37#include <sys/wait.h> --- 13 unchanged lines hidden (view full) --- 51#include <stdio.h> 52#include <stdlib.h> 53#include <string.h> 54#include <syslog.h> 55#include <unistd.h> 56 57#include "pathnames.h" 58 | 21 22#include <sys/param.h> 23#include <sys/file.h> 24#include <sys/ioctl.h> 25#include <sys/socket.h> 26#include <sys/stat.h> 27#include <sys/time.h> 28#include <sys/wait.h> --- 13 unchanged lines hidden (view full) --- 42#include <stdio.h> 43#include <stdlib.h> 44#include <string.h> 45#include <syslog.h> 46#include <unistd.h> 47 48#include "pathnames.h" 49 |
59extern int symset(const char *, const char *, int); 60 | |
61static int read_config(FILE *); 62static void print_message(char *); 63static int allowed_luser(char *); 64static int check_luser(char *, char *); 65static int remove_stale_rulesets(void); 66static int change_filter(int, const char *, const char *); | 50static int read_config(FILE *); 51static void print_message(char *); 52static int allowed_luser(char *); 53static int check_luser(char *, char *); 54static int remove_stale_rulesets(void); 55static int change_filter(int, const char *, const char *); |
67static int change_table(int, const char *, const char *); | 56static int change_table(int, const char *); |
68static void authpf_kill_states(void); 69 70int dev; /* pf device */ 71char anchorname[PF_ANCHOR_NAME_SIZE] = "authpf"; 72char rulesetname[MAXPATHLEN - PF_ANCHOR_NAME_SIZE - 2]; 73char tablename[PF_TABLE_NAME_SIZE] = "authpf_users"; 74 75FILE *pidfp; | 57static void authpf_kill_states(void); 58 59int dev; /* pf device */ 60char anchorname[PF_ANCHOR_NAME_SIZE] = "authpf"; 61char rulesetname[MAXPATHLEN - PF_ANCHOR_NAME_SIZE - 2]; 62char tablename[PF_TABLE_NAME_SIZE] = "authpf_users"; 63 64FILE *pidfp; |
76char *infile; /* file name printed by yyerror() in parse.y */ | |
77char luser[MAXLOGNAME]; /* username */ 78char ipsrc[256]; /* ip as a string */ 79char pidfile[MAXPATHLEN]; /* we save pid in this file. */ 80 81struct timeval Tstart, Tend; /* start and end times of session */ 82 83volatile sig_atomic_t want_death; 84static void need_death(int signo); --- 12 unchanged lines hidden (view full) --- 97int 98main(int argc, char *argv[]) 99{ 100 int lockcnt = 0, n, pidfd; 101 FILE *config; 102 struct in6_addr ina; 103 struct passwd *pw; 104 char *cp; | 65char luser[MAXLOGNAME]; /* username */ 66char ipsrc[256]; /* ip as a string */ 67char pidfile[MAXPATHLEN]; /* we save pid in this file. */ 68 69struct timeval Tstart, Tend; /* start and end times of session */ 70 71volatile sig_atomic_t want_death; 72static void need_death(int signo); --- 12 unchanged lines hidden (view full) --- 85int 86main(int argc, char *argv[]) 87{ 88 int lockcnt = 0, n, pidfd; 89 FILE *config; 90 struct in6_addr ina; 91 struct passwd *pw; 92 char *cp; |
93 gid_t gid; |
|
105 uid_t uid; 106 char *shell; 107 login_cap_t *lc; 108 109 config = fopen(PATH_CONFFILE, "r"); | 94 uid_t uid; 95 char *shell; 96 login_cap_t *lc; 97 98 config = fopen(PATH_CONFFILE, "r"); |
99 if (config == NULL) { 100 syslog(LOG_ERR, "can not open %s (%m)", PATH_CONFFILE); 101 exit(1); 102 } |
|
110 111 if ((cp = getenv("SSH_TTY")) == NULL) { 112 syslog(LOG_ERR, "non-interactive session connection for authpf"); 113 exit(1); 114 } 115 116 if ((cp = getenv("SSH_CLIENT")) == NULL) { 117 syslog(LOG_ERR, "cannot determine connection source"); --- 20 unchanged lines hidden (view full) --- 138 dev = open(PATH_DEVFILE, O_RDWR); 139 if (dev == -1) { 140 syslog(LOG_ERR, "cannot open packet filter device (%m)"); 141 goto die; 142 } 143 144 uid = getuid(); 145 pw = getpwuid(uid); | 103 104 if ((cp = getenv("SSH_TTY")) == NULL) { 105 syslog(LOG_ERR, "non-interactive session connection for authpf"); 106 exit(1); 107 } 108 109 if ((cp = getenv("SSH_CLIENT")) == NULL) { 110 syslog(LOG_ERR, "cannot determine connection source"); --- 20 unchanged lines hidden (view full) --- 131 dev = open(PATH_DEVFILE, O_RDWR); 132 if (dev == -1) { 133 syslog(LOG_ERR, "cannot open packet filter device (%m)"); 134 goto die; 135 } 136 137 uid = getuid(); 138 pw = getpwuid(uid); |
146 endpwent(); | |
147 if (pw == NULL) { 148 syslog(LOG_ERR, "cannot find user for uid %u", uid); 149 goto die; 150 } 151 152 if ((lc = login_getclass(pw->pw_class)) != NULL) 153 shell = (char *)login_getcapstr(lc, "shell", pw->pw_shell, 154 pw->pw_shell); --- 96 unchanged lines hidden (view full) --- 251 /* 252 * we try to kill the previous process and acquire the lock 253 * for 10 seconds, trying once a second. if we can't after 254 * 10 attempts we log an error and give up 255 */ 256 if (++lockcnt > 10) { 257 syslog(LOG_ERR, "cannot kill previous authpf (pid %d)", 258 otherpid); | 139 if (pw == NULL) { 140 syslog(LOG_ERR, "cannot find user for uid %u", uid); 141 goto die; 142 } 143 144 if ((lc = login_getclass(pw->pw_class)) != NULL) 145 shell = (char *)login_getcapstr(lc, "shell", pw->pw_shell, 146 pw->pw_shell); --- 96 unchanged lines hidden (view full) --- 243 /* 244 * we try to kill the previous process and acquire the lock 245 * for 10 seconds, trying once a second. if we can't after 246 * 10 attempts we log an error and give up 247 */ 248 if (++lockcnt > 10) { 249 syslog(LOG_ERR, "cannot kill previous authpf (pid %d)", 250 otherpid); |
251 fclose(pidfp); 252 pidfp = NULL; |
|
259 goto dogdeath; 260 } 261 sleep(1); 262 263 /* re-open, and try again. The previous authpf process 264 * we killed above should unlink the file and release 265 * it's lock, giving us a chance to get it now 266 */ 267 fclose(pidfp); | 253 goto dogdeath; 254 } 255 sleep(1); 256 257 /* re-open, and try again. The previous authpf process 258 * we killed above should unlink the file and release 259 * it's lock, giving us a chance to get it now 260 */ 261 fclose(pidfp); |
262 pidfp = NULL; |
|
268 } while (1); | 263 } while (1); |
264 265 /* whack the group list */ 266 gid = getegid(); 267 if (setgroups(1, &gid) == -1) { 268 syslog(LOG_INFO, "setgroups: %s", strerror(errno)); 269 do_death(0); 270 } |
|
269 270 /* revoke privs */ | 271 272 /* revoke privs */ |
271 seteuid(getuid()); 272 setuid(getuid()); 273 | 273 uid = getuid(); 274 if (setresuid(uid, uid, uid) == -1) { 275 syslog(LOG_INFO, "setresuid: %s", strerror(errno)); 276 do_death(0); 277 } |
274 openlog("authpf", LOG_PID | LOG_NDELAY, LOG_DAEMON); 275 276 if (!check_luser(PATH_BAN_DIR, luser) || !allowed_luser(luser)) { 277 syslog(LOG_INFO, "user %s prohibited", luser); 278 do_death(0); 279 } 280 | 278 openlog("authpf", LOG_PID | LOG_NDELAY, LOG_DAEMON); 279 280 if (!check_luser(PATH_BAN_DIR, luser) || !allowed_luser(luser)) { 281 syslog(LOG_INFO, "user %s prohibited", luser); 282 do_death(0); 283 } 284 |
281 if (config == NULL || read_config(config)) { 282 syslog(LOG_INFO, "bad or nonexistent %s", PATH_CONFFILE); | 285 if (read_config(config)) { 286 syslog(LOG_ERR, "invalid config file %s", PATH_CONFFILE); |
283 do_death(0); 284 } 285 286 if (remove_stale_rulesets()) { 287 syslog(LOG_INFO, "error removing stale rulesets"); 288 do_death(0); 289 } 290 291 /* We appear to be making headway, so actually mark our pid */ 292 rewind(pidfp); 293 fprintf(pidfp, "%ld\n%s\n", (long)getpid(), luser); 294 fflush(pidfp); 295 (void) ftruncate(fileno(pidfp), ftello(pidfp)); 296 297 if (change_filter(1, luser, ipsrc) == -1) { 298 printf("Unable to modify filters\r\n"); 299 do_death(0); 300 } | 287 do_death(0); 288 } 289 290 if (remove_stale_rulesets()) { 291 syslog(LOG_INFO, "error removing stale rulesets"); 292 do_death(0); 293 } 294 295 /* We appear to be making headway, so actually mark our pid */ 296 rewind(pidfp); 297 fprintf(pidfp, "%ld\n%s\n", (long)getpid(), luser); 298 fflush(pidfp); 299 (void) ftruncate(fileno(pidfp), ftello(pidfp)); 300 301 if (change_filter(1, luser, ipsrc) == -1) { 302 printf("Unable to modify filters\r\n"); 303 do_death(0); 304 } |
301 if (change_table(1, luser, ipsrc) == -1) { | 305 if (change_table(1, ipsrc) == -1) { |
302 printf("Unable to modify table\r\n"); 303 change_filter(0, luser, ipsrc); 304 do_death(0); 305 } 306 307 signal(SIGTERM, need_death); 308 signal(SIGINT, need_death); 309 signal(SIGALRM, need_death); 310 signal(SIGPIPE, need_death); 311 signal(SIGHUP, need_death); | 306 printf("Unable to modify table\r\n"); 307 change_filter(0, luser, ipsrc); 308 do_death(0); 309 } 310 311 signal(SIGTERM, need_death); 312 signal(SIGINT, need_death); 313 signal(SIGALRM, need_death); 314 signal(SIGPIPE, need_death); 315 signal(SIGHUP, need_death); |
312 signal(SIGSTOP, need_death); | 316 signal(SIGQUIT, need_death); |
313 signal(SIGTSTP, need_death); 314 while (1) { 315 printf("\r\nHello %s. ", luser); 316 printf("You are authenticated from host \"%s\"\r\n", ipsrc); 317 setproctitle("%s@%s", luser, ipsrc); 318 print_message(PATH_MESSAGE); 319 while (1) { 320 sleep(10); --- 233 unchanged lines hidden (view full) --- 554 luser, tmp); 555 556 /* reuse tmp */ 557 strlcpy(tmp, "\n\n-**- Sorry, you have been banned! -**-\n\n", 558 sizeof(tmp)); 559 while (fputs(tmp, stdout) != EOF && !feof(f)) { 560 if (fgets(tmp, sizeof(tmp), f) == NULL) { 561 fflush(stdout); | 317 signal(SIGTSTP, need_death); 318 while (1) { 319 printf("\r\nHello %s. ", luser); 320 printf("You are authenticated from host \"%s\"\r\n", ipsrc); 321 setproctitle("%s@%s", luser, ipsrc); 322 print_message(PATH_MESSAGE); 323 while (1) { 324 sleep(10); --- 233 unchanged lines hidden (view full) --- 558 luser, tmp); 559 560 /* reuse tmp */ 561 strlcpy(tmp, "\n\n-**- Sorry, you have been banned! -**-\n\n", 562 sizeof(tmp)); 563 while (fputs(tmp, stdout) != EOF && !feof(f)) { 564 if (fgets(tmp, sizeof(tmp), f) == NULL) { 565 fflush(stdout); |
566 fclose(f); |
|
562 return (0); 563 } 564 } | 567 return (0); 568 } 569 } |
570 fclose(f); |
|
565 } 566 fflush(stdout); 567 return (0); 568} 569 570/* 571 * Search for rulesets left by other authpf processes (either because they 572 * died ungracefully or were terminated) and remove them. --- 67 unchanged lines hidden (view full) --- 640 char *pargv[13] = { 641 "pfctl", "-p", "/dev/pf", "-q", "-a", "anchor/ruleset", 642 "-D", "user_ip=X", "-D", "user_id=X", "-f", 643 "file", NULL 644 }; 645 char *fdpath = NULL, *userstr = NULL, *ipstr = NULL; 646 char *rsn = NULL, *fn = NULL; 647 pid_t pid; | 571 } 572 fflush(stdout); 573 return (0); 574} 575 576/* 577 * Search for rulesets left by other authpf processes (either because they 578 * died ungracefully or were terminated) and remove them. --- 67 unchanged lines hidden (view full) --- 646 char *pargv[13] = { 647 "pfctl", "-p", "/dev/pf", "-q", "-a", "anchor/ruleset", 648 "-D", "user_ip=X", "-D", "user_id=X", "-f", 649 "file", NULL 650 }; 651 char *fdpath = NULL, *userstr = NULL, *ipstr = NULL; 652 char *rsn = NULL, *fn = NULL; 653 pid_t pid; |
654 gid_t gid; |
|
648 int s; 649 650 if (luser == NULL || !luser[0] || ipsrc == NULL || !ipsrc[0]) { 651 syslog(LOG_ERR, "invalid luser/ipsrc"); 652 goto error; 653 } 654 655 if (asprintf(&rsn, "%s/%s", anchorname, rulesetname) == -1) --- 23 unchanged lines hidden (view full) --- 679 pargv[9] = ipstr; 680 if (!add) 681 pargv[11] = "/dev/null"; 682 else 683 pargv[11] = fn; 684 685 switch (pid = fork()) { 686 case -1: | 655 int s; 656 657 if (luser == NULL || !luser[0] || ipsrc == NULL || !ipsrc[0]) { 658 syslog(LOG_ERR, "invalid luser/ipsrc"); 659 goto error; 660 } 661 662 if (asprintf(&rsn, "%s/%s", anchorname, rulesetname) == -1) --- 23 unchanged lines hidden (view full) --- 686 pargv[9] = ipstr; 687 if (!add) 688 pargv[11] = "/dev/null"; 689 else 690 pargv[11] = fn; 691 692 switch (pid = fork()) { 693 case -1: |
687 err(1, "fork failed"); | 694 syslog(LOG_ERR, "fork failed"); 695 goto error; |
688 case 0: | 696 case 0: |
697 /* revoke group privs before exec */ 698 gid = getgid(); 699 if (setregid(gid, gid) == -1) { 700 err(1, "setregid"); 701 } |
|
689 execvp(PATH_PFCTL, pargv); 690 warn("exec of %s failed", PATH_PFCTL); 691 _exit(1); 692 } 693 694 /* parent */ 695 waitpid(pid, &s, 0); 696 if (s != 0) { | 702 execvp(PATH_PFCTL, pargv); 703 warn("exec of %s failed", PATH_PFCTL); 704 _exit(1); 705 } 706 707 /* parent */ 708 waitpid(pid, &s, 0); 709 if (s != 0) { |
697 if (WIFEXITED(s)) { 698 syslog(LOG_ERR, "pfctl exited abnormally"); 699 goto error; 700 } | 710 syslog(LOG_ERR, "pfctl exited abnormally"); 711 goto error; |
701 } 702 703 if (add) { 704 gettimeofday(&Tstart, NULL); 705 syslog(LOG_INFO, "allowing %s, user %s", ipsrc, luser); 706 } else { 707 gettimeofday(&Tend, NULL); 708#ifdef __FreeBSD__ --- 4 unchanged lines hidden (view full) --- 713 ipsrc, luser, Tend.tv_sec - Tstart.tv_sec); 714#endif 715 } 716 return (0); 717no_mem: 718 syslog(LOG_ERR, "malloc failed"); 719error: 720 free(fdpath); | 712 } 713 714 if (add) { 715 gettimeofday(&Tstart, NULL); 716 syslog(LOG_INFO, "allowing %s, user %s", ipsrc, luser); 717 } else { 718 gettimeofday(&Tend, NULL); 719#ifdef __FreeBSD__ --- 4 unchanged lines hidden (view full) --- 724 ipsrc, luser, Tend.tv_sec - Tstart.tv_sec); 725#endif 726 } 727 return (0); 728no_mem: 729 syslog(LOG_ERR, "malloc failed"); 730error: 731 free(fdpath); |
721 fdpath = NULL; | |
722 free(rsn); | 732 free(rsn); |
723 rsn = NULL; | |
724 free(userstr); | 733 free(userstr); |
725 userstr = NULL; | |
726 free(ipstr); | 734 free(ipstr); |
727 ipstr = NULL; | |
728 free(fn); | 735 free(fn); |
729 fn = NULL; 730 infile = NULL; | |
731 return (-1); 732} 733 734/* 735 * Add/remove this IP from the "authpf_users" table. 736 */ 737static int | 736 return (-1); 737} 738 739/* 740 * Add/remove this IP from the "authpf_users" table. 741 */ 742static int |
738change_table(int add, const char *luser, const char *ipsrc) | 743change_table(int add, const char *ipsrc) |
739{ 740 struct pfioc_table io; 741 struct pfr_addr addr; 742 743 bzero(&io, sizeof(io)); | 744{ 745 struct pfioc_table io; 746 struct pfr_addr addr; 747 748 bzero(&io, sizeof(io)); |
744 strlcpy(io.pfrio_table.pfrt_name, tablename, sizeof(io.pfrio_table)); | 749 strlcpy(io.pfrio_table.pfrt_name, tablename, 750 sizeof(io.pfrio_table.pfrt_name)); |
745 io.pfrio_buffer = &addr; 746 io.pfrio_esize = sizeof(addr); 747 io.pfrio_size = 1; 748 749 bzero(&addr, sizeof(addr)); 750 if (ipsrc == NULL || !ipsrc[0]) 751 return (-1); 752 if (inet_pton(AF_INET, ipsrc, &addr.pfra_ip4addr) == 1) { --- 76 unchanged lines hidden (view full) --- 829static __dead void 830#endif 831do_death(int active) 832{ 833 int ret = 0; 834 835 if (active) { 836 change_filter(0, luser, ipsrc); | 751 io.pfrio_buffer = &addr; 752 io.pfrio_esize = sizeof(addr); 753 io.pfrio_size = 1; 754 755 bzero(&addr, sizeof(addr)); 756 if (ipsrc == NULL || !ipsrc[0]) 757 return (-1); 758 if (inet_pton(AF_INET, ipsrc, &addr.pfra_ip4addr) == 1) { --- 76 unchanged lines hidden (view full) --- 835static __dead void 836#endif 837do_death(int active) 838{ 839 int ret = 0; 840 841 if (active) { 842 change_filter(0, luser, ipsrc); |
837 change_table(0, luser, ipsrc); | 843 change_table(0, ipsrc); |
838 authpf_kill_states(); 839 remove_stale_rulesets(); 840 } | 844 authpf_kill_states(); 845 remove_stale_rulesets(); 846 } |
841 if (pidfp) 842 ftruncate(fileno(pidfp), 0); 843 if (pidfile[0]) | 847 if (pidfile[0] && (pidfp != NULL)) |
844 if (unlink(pidfile) == -1) 845 syslog(LOG_ERR, "cannot unlink %s (%m)", pidfile); 846 exit(ret); 847} | 848 if (unlink(pidfile) == -1) 849 syslog(LOG_ERR, "cannot unlink %s (%m)", pidfile); 850 exit(ret); 851} |