├── .gitignore ├── AUTHORS ├── COPYING ├── COPYING.DOC ├── ChangeLog ├── ChangeLog-1.x ├── ChangeLog-2.x ├── HACKING ├── INSTALL ├── KERNEL_SUPPORT.md ├── Makefile.am ├── NEWS ├── README ├── autogen.sh ├── configure.ac ├── contrib └── systemd │ ├── oidentd.service │ ├── oidentd.socket │ └── oidentd@.service ├── doc ├── Makefile.am ├── book │ ├── .gitignore │ ├── book.toml │ └── src │ │ ├── SUMMARY.md │ │ ├── download.md │ │ ├── getting-started │ │ ├── capabilities.md │ │ ├── configuration │ │ │ ├── examples.md │ │ │ └── index.md │ │ ├── index.md │ │ ├── installation.md │ │ ├── starting-the-server.md │ │ └── support.md │ │ ├── guides │ │ ├── index.md │ │ ├── using-oidentd-with-quassel.md │ │ └── using-oidentd-with-znc.md │ │ ├── index.md │ │ ├── nat │ │ ├── forwarding.md │ │ ├── index.md │ │ ├── introduction.md │ │ └── static-replies.md │ │ └── security │ │ ├── dropping-privileges.md │ │ ├── hiding-connections.md │ │ ├── identification-vs-authentication.md │ │ └── index.md ├── oidentd.8.adoc ├── oidentd.conf.5.adoc ├── oidentd_masq.conf.5.adoc └── rfc1413 ├── oidentd.conf ├── oidentd_masq.conf └── src ├── Makefile.am ├── cfg_parse.y ├── cfg_scan.l ├── forward.c ├── forward.h ├── inet_util.c ├── inet_util.h ├── kernel ├── dflybsd1.c ├── freebsd5.c ├── linux.c ├── netbsd5.c └── openbsd30.c ├── masq.c ├── masq.h ├── missing ├── Makefile.am ├── getopt.c ├── getopt_missing.h ├── inet_aton.c ├── inet_ntop.c ├── ipv6_missing.c ├── missing.h └── vasprintf.c ├── netlink.h ├── oidentd.c ├── oidentd.h ├── options.c ├── options.h ├── user_db.c ├── user_db.h ├── util.c └── util.h /.gitignore: -------------------------------------------------------------------------------- 1 | # Backup files 2 | *~ 3 | 4 | # GNU automake 5 | Makefile 6 | Makefile.in 7 | /ar-lib 8 | /dist 9 | /mdate-sh 10 | /py-compile 11 | /test-driver 12 | /ylwrap 13 | 14 | # GNU autoconf 15 | /autom4te.cache 16 | /autoscan.log 17 | /autoscan-*.log 18 | /aclocal.m4 19 | /compile 20 | /config.log 21 | /config.guess 22 | /config.h 23 | /config.h.in 24 | /config.status 25 | /config.sub 26 | /configure 27 | /configure.scan 28 | /depcomp 29 | /install-sh 30 | /missing 31 | /stamp-h1 32 | .deps/ 33 | 34 | # GNU libtool 35 | /ltmain.sh 36 | 37 | # GNU texinfo 38 | /texinfo.tex 39 | 40 | # GNU m4 41 | m4/libtool.m4 42 | m4/ltoptions.m4 43 | m4/ltsugar.m4 44 | m4/ltversion.m4 45 | m4/lt~obsolete.m4 46 | autom4te.cache 47 | 48 | # Archives, prerequisites and object files 49 | *.a 50 | *.d 51 | *.o 52 | *.tar.* 53 | *.zip 54 | 55 | # Generated source files and executables 56 | src/oidentd 57 | src/cfg_parse.c 58 | src/cfg_parse.h 59 | src/cfg_scan.c 60 | src/os.c 61 | 62 | # Generated manual pages 63 | doc/oidentd.8 64 | doc/oidentd.conf.5 65 | doc/oidentd_masq.conf.5 66 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Bjarni R. Einarsson 2 | Support for libudb 3 | 4 | Chris Taylor 5 | Linux masquerading improvements 6 | 7 | Christian Kellner 8 | Linux DNAT patch 9 | 10 | Christof Douma 11 | Linux netfilter permissions fix 12 | 13 | Daniel Brafford 14 | Initial IPv6 support and IPv6 implementation for Linux 15 | 16 | Dessa 17 | Build script improvements 18 | 19 | Douglas Henke 20 | Improvements to PRNG seeding 21 | Flags --foreground and --nosyslog 22 | Support for inetd and daemontools 23 | 24 | Elliott Mitchell 25 | Fixed memory leaks in configuration parser 26 | 27 | Eric LeBlanc 28 | Fixed a bug that caused IP masquerading to fail 29 | 30 | Fabian Knittel 31 | Bind to IPv6 socket by default 32 | 33 | Fardale 34 | Fixed incorrect filter order in range specifications 35 | 36 | Guus Sliepen 37 | Initial netfilter (Linux >= 2.3 Support) 38 | 39 | Hanno Böck 40 | Fixed overflow due to incorrect sizeof type 41 | 42 | Jan Alexander Steffens 43 | Forwarding capability 44 | 45 | Jan Rękorajski 46 | Support for listening on multiple IPs 47 | 48 | Janik Rabe 49 | Everything else (project maintainer) 50 | 51 | Joerg Sonnenberger 52 | Initial DragonFly BSD support 53 | 54 | Johnny A. Solbu 55 | Various improvements to the build system 56 | 57 | Kamil Andrusz 58 | OpenBSD >= 3.0 Packet Filter support 59 | 60 | Krzysztof Oledzki 61 | Fix for IPv6 connection lookups 62 | 63 | Kufat 64 | Compatibility of inline functions with C99 65 | 66 | Martin Waitz 67 | UDB fixes 68 | 69 | Matthias Scheler 70 | Replaced hardcoded configuration file path 71 | 72 | Motohiko Takemura 73 | Fixed a bug in the command-line argument handler 74 | Fixed a bug that caused IP masquerading to fail 75 | Fixed bugs with the --forward and --other flags 76 | 77 | Petr Písař 78 | Linux masquerading improvements 79 | Fixes for several compiler warnings 80 | 81 | Ryan McCabe 82 | Everything else (original author) 83 | 84 | Simon Arlott 85 | Local NAT support for Linux 86 | Linux nf_conntrack support 87 | MASQ_OVERRIDE (--masquerade-first) option 88 | 89 | Slawomir Piotrowski 90 | IP masquerading (NAT) support for OpenBSD 91 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | 2023-03-11 Janik Rabe 2 | 3 | * Released as version 3.1.0. 4 | 5 | 2023-03-09 Janik Rabe 6 | 7 | * Remove `-S` (`--nosyslog`) from systemd unit files 8 | * Warn about missing logs if forking with NOSYSLOG set 9 | 10 | 2021-08-17 Janik Rabe 11 | 12 | * Allow using masquerading without IPv6 support on Linux. 13 | 14 | 2021-08-16 Janik Rabe 15 | 16 | * Released as version 3.0.0. 17 | 18 | 2021-04-25 Janik Rabe 19 | 20 | * Fail on non-zero EUID if NEED_ROOT is set. 21 | * Drop support for very old FreeBSD versions. 22 | * Drop NAT support for DragonFly BSD. 23 | * Drop NAT support for FreeBSD. 24 | * Create separate kernel module for DragonFly BSD. 25 | 26 | 2020-09-12 Janik Rabe 27 | 28 | * Remove '--forward-last' flag (renamed to '--masquerade-first'). 29 | * Remove libudb support (deprecated). 30 | * Remove '\e' escape sequence for strings in configuration files 31 | (deprecated). 32 | * Remove support for legacy kernels (deprecated). 33 | * Remove Linux MASQFILE support (deprecated). 34 | * Remove Linux IPCONNTRACK support (deprecated). 35 | * Update default configuration file to hide root connections. 36 | 37 | 2020-05-04 Janik Rabe 38 | 39 | * Compile with ENABLE_DEBUGGING by default. 40 | -------------------------------------------------------------------------------- /ChangeLog-1.x: -------------------------------------------------------------------------------- 1 | Fri Feb 9 05:11:08 EST 2001 Ryan McCabe 2 | 3 | * Increased the allowed length of spoofed ident replies to 512 4 | characters. 5 | 6 | * Simply drop connections that send a malformed request instead of 7 | replying with INVALID-PORT. 8 | 9 | Fri Jan 12 23:40:56 EST 2001 Ryan McCabe 10 | 11 | * Applied patches from Arkadiusz Miskiewicz 12 | to fix some IPv6 problems 13 | 14 | Sat Dec 09 17:47:15 EST 2000 Ryan McCabe 15 | 16 | * Fixes for IPv6 support from Daniel Brafford. 17 | 18 | Thu Dec 07 00:03:58 EST 2000 Ryan McCabe 19 | 20 | * Applied patch from Daniel Brafford for 21 | IPv6 support on Linux. 22 | 23 | Sun Oct 22 14:54:06 EDT 2000 Ryan McCabe 24 | 25 | * Released as version 1.7.1 26 | 27 | Thu Oct 19 17:02:22 EDT 2000 Ryan McCabe 28 | 29 | * Applied a patch from Sean 'Shaleh' Perry to 30 | fix a bug that prevented oidentd from running in stand-alone mode. 31 | 32 | Tue Oct 03 02:12:39 EDT 2000 Ryan McCabe 33 | 34 | * Ported to FreeBSD 4.* 35 | 36 | Mon Aug 21 03:58:52 EDT 2000 Ryan McCabe 37 | 38 | * Applied patch from Slawomir Piotrowski 39 | adding IP masq support for OpenBSD. 40 | 41 | * Code cleanup. 42 | 43 | Wed May 31 14:58:18 EDT 2000 Ryan McCabe 44 | 45 | * Applied patch from Bjarni R. Einarsson that 46 | adds libudb support. 47 | 48 | Sun Jan 16 12:32:35 EST 2000 Ryan McCabe 49 | 50 | * Fix a typo. 51 | 52 | Sat Jan 15 13:28:58 EST 2000 Ryan McCabe 53 | 54 | * Added 'F' and 'O' options. Original patch was from 55 | Jeroen Massar 56 | 57 | Fri Jan 14 23:55:24 EST 2000 Ryan McCabe 58 | 59 | * Integraded patch from Guus Sliepen that adds 60 | netfilter support to oidentd. 61 | 62 | Sun Jan 02 22:43:13 EST 2000 Ryan McCabe 63 | 64 | * Added the ability to specify an identd response for users in the 65 | /etc/identd.spoof file. For example, an entry of "nobody:UNKNOWN" 66 | will cause the string "UNKNOWN" to be returned upon every successful 67 | lookup of a connection owned by user nobody. 68 | 69 | * Code cleanups. 70 | 71 | * Documentation updates. 72 | 73 | Sun Dec 12 20:06:21 EST 1999 Ryan McCabe 74 | 75 | * Fix a bug that caused an incorrect port to be returned upon a 76 | successful forward of an ident request. 77 | - Reported by Pawel Mojski 78 | 79 | Sun Aug 22 21:17:15 EDT 1999 Ryan McCabe 80 | 81 | * Release as version 1.6.3. 82 | 83 | Sun Jul 25 15:06:00 EDT 1999 Ryan McCabe 84 | 85 | * Merged in Solaris 2.x support from ultr0s 86 | 87 | * Added a -q option (quiet) to suppress logging messages via syslog. 88 | 89 | Mon May 31 01:29:24 EDT 1999 Ryan McCabe 90 | 91 | * Fixed a bug that caused specifying a forward port other than 113 92 | to fail. 93 | 94 | * Fixed a typo in oidentd.c. 95 | - Thanks to Stuart Adamson for 96 | pointing both out. 97 | 98 | Fri May 28 19:22:13 EDT 1999 Ryan McCabe 99 | 100 | * Released version 1.6.2 101 | 102 | Thu May 27 02:56:19 EDT 1999 Ryan McCabe 103 | 104 | * Documentation updates. 105 | 106 | * Fixed a problem with wait mode. 107 | 108 | * Add new flag -x .. If a lookup fails and this flag is 109 | set, the username specified will be returned to the client as if 110 | the query had succeeded. 111 | 112 | Tue Apr 6 19:31:55 EDT 1999 Ryan McCabe 113 | 114 | * Cleaned up the forward timeout stuff. 115 | 116 | * Allow service names when specifying ports. 117 | 118 | * Other small cleanups. 119 | 120 | Mon Mar 29 02:29:59 EST 1999 Ryan McCabe 121 | 122 | * Changed the default maximum length of spoofed identd responses 123 | to 24 (was 10). 124 | 125 | Sat Mar 6 20:33:19 EST 1999 Ryan McCabe 126 | 127 | * If our connection times out to a host we're forwarding to, 128 | fallback to /etc/oidentd.users instead of exiting. 129 | (Bug reported by Lourdes Jones ) 130 | 131 | * Changed timeout interval to 15 seconds when forwarding a 132 | connection to a masqd host (was 30). 133 | 134 | Fri Feb 26 03:30:31 EST 1999 Ryan McCabe 135 | 136 | * dmess0r noticed that when running in standalone mode, -r was 137 | broken (it would use the same username over and over again). 138 | This is fixed now. 139 | 140 | Fri Feb 19 17:58:45 EST 1999 Ryan McCabe 141 | 142 | * Allow masks in /etc/oidentd.users (eg, 192.168.1.0/24) 143 | 144 | * Allow hostnames in /etc/oidentd.users 145 | 146 | Mon Feb 1 01:15:17 EST 1999 Ryan McCabe 147 | 148 | * All users are allowed to spoof with -S even if /etc/identd.spoof 149 | doesn't exist. 150 | 151 | * Install the manual page. 152 | 153 | Sat Jan 23 21:22:29 EST 1999 Ryan McCabe 154 | 155 | * Bumped version number up to 1.6.0. 156 | 157 | * Rewrote the INSTALL file. 158 | 159 | * Added the '-P' option, which enables oidentd to allow for a 160 | proxy to successfully issue a query for a masqueraded 161 | connection. 162 | 163 | * Fixed (hopefully) the forwarding stuff. 164 | 165 | Tue Jan 12 22:43:07 EST 1999 Ryan McCabe 166 | 167 | * Bumped version number up to 1.5.1. 168 | 169 | * Regenerate scripts using autoconf 2.13. 170 | 171 | * More minor code and documentation updates. 172 | 173 | Sat Jan 9 20:04:53 EST 1999 Ryan McCabe 174 | 175 | * Various code and documentation cleanups. 176 | 177 | * Removed CHARSET flag. 178 | 179 | Mon Jan 4 18:22:51 EST 1999 Ryan McCabe 180 | 181 | * Released version 1.5 182 | 183 | * Added new option '-S' that does the same thing as '-s' only all 184 | users are allowed to spoof their identd replies except those 185 | users listed in the oidentd users file (by default 186 | /etc/identd.spoof) 187 | -------------------------------------------------------------------------------- /HACKING: -------------------------------------------------------------------------------- 1 | Modifying oidentd 2 | ***************** 3 | 4 | Copyright (c) 2018-2019 Janik Rabe 5 | 6 | Copying and distribution of this file, with or without modification, 7 | are permitted in any medium without royalty provided the copyright 8 | notice and this notice are preserved. This file is offered as-is, 9 | without any warranty. 10 | 11 | Introduction 12 | ============ 13 | 14 | This project uses the GNU Build System, also known as Autotools. The 15 | instructions in this file assume that Autotools has already been installed; 16 | specifically, it is assumed that autoconf, autoheader, automake and aclocal 17 | are installed and available in '$PATH'. For more information on installing 18 | and using the GNU Build System, please consult the documentation of autoconf 19 | and automake, or run './autogen.sh'. 20 | 21 | The command './autogen.sh' checks for the existence of these programs 22 | and, if they are present, generates a './configure' script. This script can 23 | then be used to configure the build and generate the files required to build 24 | and install oidentd. For more information on installing oidentd, please 25 | consult the INSTALL file. 26 | 27 | Note that the source files generated by flex and bison are included only 28 | in release tarballs. For this reason, flex and bison must be installed before 29 | building oidentd from any source other than one of the published releases. 30 | Please consult the documentation of flex and bison for more information. 31 | Likewise, AsciiDoc is required for building the manual pages and must be 32 | installed when building from git. 33 | 34 | After modifying the sources, oidentd can be recompiled by issuing the 35 | 'make' command. When making changes to a file in the 'src/kernel/' directory, 36 | the modified file must first be copied to 'src/os.c', and 'make' must be 37 | issued on an operating system kernel corresponding to the changed file. 38 | 39 | Source Tree 40 | =========== 41 | 42 | . 43 | |-- doc: Documentation and manual pages 44 | `-- src: Source code 45 | |-- kernel: Kernel-specific functions 46 | `-- missing: Portable implementations of missing functions 47 | 48 | Kernel Support 49 | ============== 50 | 51 | The './configure' script copies the appropriate source file for the 52 | current operating system from the 'src/kernel/' directory to 'src/os.c'. 53 | This behavior can be modified by editing 'configure.ac'. The './configure' 54 | script will automatically be regenerated the next time the 'make' command 55 | is issued. 56 | 57 | When making changes that affect kernel support, please ensure that the 58 | 'KERNEL_SUPPORT.md' file is updated to reflect these changes. 59 | 60 | Releasing 61 | ========= 62 | 63 | Before releasing a new version, please ensure that all documentation 64 | is up-to-date. This includes the files 'AUTHORS', 'ChangeLog', 'HACKING', 65 | 'INSTALL', 'KERNEL_SUPPORT.md', 'README', and the manual pages in the 'doc/' 66 | directory. New versions should be released only by the project maintainers. 67 | 68 | In 'ChangeLog', add an entry '* Released as version .' to the top 69 | of the file, replacing '' with the version number of the new release. 70 | 71 | Prepend a summary of all significant changes to the 'NEWS' file. Each 72 | change should be added as a separate line and prefixed with an asterisk and a 73 | space character ('* '). The last change should be followed by a blank line to 74 | separate the summary from that of the previous version. At the top of the 75 | file, add the line "Changes in version ", replacing '' with 76 | the version number of the new release. 77 | 78 | Update the version number in 'configure.ac', 'doc/book/book.toml', and 79 | 'README'. Change the date in each of the manual pages to the release date of 80 | the new version. 81 | 82 | Commit the changes and tag the commit with "v", where '' 83 | is the version number of the release. 84 | 85 | Finally, run 'make distcheck' to produce a set of release tarballs which 86 | can then be distributed to users. 87 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | Installing oidentd 2 | ****************** 3 | 4 | Copyright (c) 2019 Janik Rabe 5 | 6 | Copying and distribution of this file, with or without modification, 7 | are permitted in any medium without royalty provided the copyright 8 | notice and this notice are preserved. This file is offered as-is, 9 | without any warranty. 10 | 11 | Introduction 12 | ============ 13 | 14 | This document describes how to install oidentd from a release tarball. 15 | For instructions for building from git, please refer to the 'HACKING' file. 16 | 17 | Optional Dependencies 18 | ===================== 19 | 20 | Unless the '--disable-libnfct' flag is used, oidentd is compiled with 21 | support for libnetfilter_conntrack on Linux systems on which it is available. 22 | Please note that this requires the libnetfilter_conntrack library and its 23 | headers to be installed. libnetfilter_conntrack allows oidentd to obtain 24 | connection tracking information without using the '/proc' filesystem. This is 25 | useful on kernels without CONFIG_NF_CONNTRACK_PROCFS, on which 26 | '/proc/net/nf_conntrack' is not available. 27 | 28 | Build Configuration 29 | =================== 30 | 31 | Run './configure' to configure the build. The './configure' script accepts 32 | a number of optional flags: 33 | 34 | - '--disable-nat': disable NAT support 35 | Disables '--forward', '--masquerade' and '--masquerade-first' 36 | - '--disable-ipv6': disable IPv6 support 37 | Disables listening on IPv6 and ignores all IPv6 connections 38 | - '--disable-libnfct': disable Linux libnetfilter_conntrack support 39 | See "Optional Dependencies" above for more information 40 | - '--disable-xdgbdir': disable XDG Base Directory support 41 | Do not look for '~/.config/oidentd.conf' before '~/.oidentd.conf' 42 | - '--disable-debug': disable debugging support 43 | Disables support for the '--debug' option 44 | - '--enable-warn': enable additional compiler warnings 45 | Show more warnings during compilation 46 | 47 | By default, oidentd is configured with a prefix of '/usr/local'. This is 48 | the directory that files will be installed to. For example, the oidentd binary 49 | will be installed to '/usr/local/sbin/oidentd'. The prefix can be changed by 50 | passing the '--prefix' option to the './configure' script. A complete list of 51 | options can be viewed by running './configure --help'. 52 | 53 | Compilation and Installation 54 | ============================ 55 | 56 | Run 'make' to compile the source code and documentation, then 'make install' 57 | to install the compiled files. Note that 'make install' must be run as root if 58 | the current user does not have permission to write to the directory that was 59 | specified with the '--prefix' option to './configure'. 60 | 61 | Running oidentd 62 | =============== 63 | 64 | Like most internet-facing services, oidentd should not run as root. For 65 | this reason, it drops its privileges after starting up. However, oidentd still 66 | needs to be started as root for a number of reasons: 67 | 68 | - to bind the privileged port 113 (unless the '--port' option is used) 69 | - to open the kernel memory device (on systems where this is required) 70 | - to open the connection tracking file (on systems where this is required) 71 | 72 | The user and group oidentd runs as after dropping privileges can be 73 | specified with the '--user' and '--group' options, respectively. Documentation 74 | for these options are available in oidentd.conf(5). 75 | 76 | Note that in some cases, oidentd may be unable to run as an unprivileged 77 | user on FreeBSD, NetBSD, and DragonFly BSD. On affected systems, a warning 78 | will be shown at runtime and when running './configure'. 79 | -------------------------------------------------------------------------------- /KERNEL_SUPPORT.md: -------------------------------------------------------------------------------- 1 | # Kernel Support Table 2 | 3 | | Kernel | IPv4 | IPv6 | IPv4 NAT | IPv6 NAT | Needs kmem | Needs root | 4 | | ----------------- | ---- | ---- | -------- | -------- | ---------- | ---------- | 5 | | DragonFly BSD | Yes | Yes | No | No | No | Yes | 6 | | FreeBSD 5+ | Yes | Yes | No | No | No | Yes | 7 | | Linux | Yes | Yes | Yes | Yes | No | No | 8 | | NetBSD 5+ | Yes | Yes | No | No | No | Yes | 9 | | OpenBSD 3+ | Yes | Yes | Yes | No | No | No | 10 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = src doc 2 | 3 | sysconf_DATA = oidentd.conf \ 4 | oidentd_masq.conf 5 | 6 | EXTRA_DIST = KERNEL_SUPPORT.md \ 7 | $(sysconf_DATA) \ 8 | contrib 9 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- 1 | Changes in version 3.1.0 2 | 3 | * Allow using masquerading without IPv6 support on Linux. 4 | * Remove `-S` (`--nosyslog`) from systemd unit files. 5 | * Warn about missing logs if forking with NOSYSLOG set. 6 | 7 | Changes in version 3.0.0 8 | 9 | * Support for '--debug' is now included by default. 10 | * Run './configure' with '--disable-debug' to disable. 11 | * Removed '--forward-last' ('-M') flag. 12 | * Renamed to '--masquerade-first' ('-M'). 13 | * Removed libudb support. 14 | * Removed '\e' escape sequence for strings in configuration files. 15 | * Removed support for legacy kernels. 16 | * Removed Linux MASQFILE support. 17 | * Removed Linux IPCONNTRACK support. 18 | * Updated default configuration file to hide root connections. 19 | * Removed ipf NAT support for FreeBSD and DragonFly BSD. 20 | * NAT support for these systems required access to kernel memory and 21 | was not compatible with modern versions. 22 | 23 | Changes in version 2.5.1 24 | 25 | * Fixed ident lookups on FreeBSD 13+. 26 | 27 | Changes in version 2.5.0 28 | 29 | * Added '--reply-all' option. 30 | * Imported documentation from website. 31 | 32 | Changes in version 2.4.0 33 | 34 | * Linux: removed optional dependency on libcap-ng. 35 | * Deprecated '\e' escape sequence in configuration files. 36 | * Fixed incorrect username in log message when spoofing fails. 37 | * Implemented XDG Base Directory specification 38 | * ~/.config/oidentd.conf takes precedence over ~/.oidentd.conf 39 | * Rewrote all manual pages, now licensed under GFDL v1.3+. 40 | * Prevent overflow when too many replies are specified in the 41 | system-wide configuration file. 42 | * Rewrote INSTALL and README files. 43 | * Improved PRNG interface. 44 | * Changed project description. 45 | * Deprecated support for MASQFILE and IPCONNTRACK on Linux. 46 | * Users of recent kernels are unaffected by this change. 47 | * Minor bugfixes, cleanups, and improvements. 48 | * Deprecated support for Darwin. 49 | * Deprecated support for FreeBSD 1-3. 50 | * Deprecated support for FreeBSD 4. 51 | * Deprecated support for NetBSD 1-4. 52 | * Deprecated support for OpenBSD 2.0-2.3. 53 | * Deprecated support for OpenBSD 2.4-2.8. 54 | * Deprecated support for OpenBSD 2.9. 55 | * Deprecated support for Solaris 2.4. 56 | * Deprecated support for Solaris 2.5. 57 | * Deprecated support for Solaris 2.6-2.7. 58 | * Deprecated support for Solaris 2.8. 59 | 60 | Changes in version 2.3.2 61 | 62 | * Option `--forward` now implies `--masquerade`. 63 | * Added a warning when the connection limit is exceeded. 64 | * Added systemd services and a socket file. 65 | * Added compile-time configuration to `--version` output. 66 | * Linux: fixed incorrect buffer lengths when compiled with `--disable-ipv6`. 67 | * Deprecated libudb (user database library) support. 68 | * Linux: fixed incorrect byte order in libnetfilter_conntrack queries. 69 | * Linux: fixed a null dereference with libnetfilter_conntrack on kernels 70 | without a connection tracking file. 71 | * Build as a position-independent executable and with stack protection. 72 | * Fixed an invalid comment style in the default oidentd_masq.conf file. 73 | 74 | Changes in version 2.3.1 75 | 76 | * Fixed build with libnetfilter_conntrack on Linux. 77 | 78 | Changes in version 2.3.0 79 | 80 | * Added a forwarding capability. 81 | * Added Linux IPv6 masquerading support. 82 | * Added build information to `--version` output. 83 | * Always use libnetfilter_conntrack when available. 84 | * Fixed signed/unsigned bit shifting on Linux. 85 | * Minor bugfixes. 86 | 87 | Changes in version 2.2.3 88 | 89 | * Fixed an out-of-buffer read/write issue. 90 | * Fixed several compiler warnings. 91 | * Fixed incorrect order of lport and fport in manual pages. 92 | * Fixed lookup of connections to IPv6-mapped IPv4 addresses. 93 | * Allow to, fport, from and lport to be specified in any order. 94 | * Warn when privileges cannot be dropped automatically. 95 | 96 | Changes in version 2.2.2 97 | 98 | * Implicitly drop privileges only when running as root. 99 | * Try to run as oidentd:oidentd before falling back to nobody etc. 100 | * Search for configuration files in sysconfdir instead of `/etc`. 101 | * Deprecated option --forward-last in favor of --masquerade-first. 102 | 103 | Changes in version 2.2.1 104 | 105 | * Fixed LIBNFCT_SUPPORT being defined incorrectly on some systems. 106 | 107 | Changes in version 2.2.0 108 | 109 | * Security: privileges were not being dropped without the `--user` 110 | and `--group` options. 111 | * Security: fixed a null pointer dereference with libudb support and 112 | IP masquerading enabled. 113 | * Added a system-wide default configuration file. 114 | * Added a HACKING file with instructions for modifying oidentd. 115 | * Added a kernel support table (KERNEL_SUPPORT.md). 116 | * Added support for modern FreeBSD kernels. 117 | * Added support for modern OpenBSD kernels. 118 | * Added support for NetBSD 5+ (no IP masquerading support yet). 119 | * Added support for DragonFly BSD. 120 | * Added support for listening on multiple addresses. 121 | * Added flag `--forward-last`. 122 | * Bind to IPv6 by default. 123 | * Warn when `--debug` is used in a build without debugging support. 124 | * Warn when IP masquerading support is requested but unavailable. 125 | * Improved logging to make sure important errors are shown. 126 | * Bind socket before forking so that any errors are shown. 127 | * Follow RFC 1413 recommendations regarding white space in replies. 128 | * Modernized build system and replaced deprecated macros. 129 | * Updated all documentation and manual pages. 130 | * Fixed function inlined using a method incompatible with C99. 131 | * Fixed `--limit` option also enabling `--other`. 132 | * Fixed `--forward` option with a different destination port. 133 | * Fixed exit code when `--help` or `--version` was used. 134 | * Fixed configuration option `--disable-masq` having no effect. 135 | * Fixed various minor issues leading to compiler warnings. 136 | * Linux: handle local NAT properly instead of trying to forward. 137 | * Linux: fixed NAT when a different destination port was used. 138 | * Linux: fixed an issue with IPv4-mapped IPv6 addresses. 139 | * Linux: add masquerading support using `/proc/net/nf_conntrack`. 140 | * Linux: add masquerading support using `libnetfilter_conntrack`. 141 | * Linux: open connection tracking file only when necessary. 142 | * Removed Solaris 5.1+ support (build is broken due to kernel changes). 143 | 144 | Changes in version 2.1.0 145 | 146 | * Fixed memory corruption on FreeBSD. 147 | * Changed maintainer to Janik Rabe . 148 | * Migrated project from CVS to git. 149 | 150 | Changes in version 2.0.9 151 | 152 | * Internal changes. 153 | 154 | Changes in version 2.0.8 155 | 156 | * So, I guess some things have changed in the past 3 years. 157 | * Fixed bugs. 158 | 159 | Changes in version 2.0.7 160 | 161 | * Bug fixes. 162 | * Build fixes. 163 | 164 | Changes in version 2.0.6 165 | 166 | * Bug fixes. 167 | * Build fixes for Darwin and FreeBSD. 168 | * Support for inetd/xinetd/daemontools. 169 | 170 | Changes in version 2.0.5 171 | 172 | * Bugfixes for connection forwarding on BSD. 173 | * DNAT support on linux. 174 | * Configuration Parser/scanner cleanups. 175 | * IPv6 fixes. 176 | * FreeBSD 5 support. 177 | * Compile fixes. 178 | * Made connection forwarding work on recent versions of OpenBSD and on FreeBSD 179 | when NAT is disabled. 180 | 181 | Changes in version 2.0.4 182 | 183 | * Support for lookups using the netlink socket diagnostics interface on Linux. 184 | * Support for Solaris 9. 185 | * Support for NetBSD. 186 | * Support for Darwin. 187 | * Bugfixes for NAT on *BSD. 188 | 189 | Changes in version 2.0.3 190 | 191 | * Fixed a bug in the configure script that caused a compile error on OpenBSD 192 | 3.0. 193 | 194 | Changes in version 2.0.2 195 | 196 | * Added support for OpenBSD (>= 3.0) Packet Filter. 197 | * Allow multiple strings to be specified after a "reply" statement from which 198 | one string will be selected at random. 199 | * A --limit command-line argument used to limit the number of connections that 200 | can be open at any one time. 201 | * Fixed a bug that caused oidentd to chew up lots of CPU time on some 202 | operating systems. 203 | * Note that oidentd only suports ipf NAT in FreeBSD (i.e. ipfw is not 204 | supported). 205 | - See the TODO file for slightly more info. 206 | 207 | Changes in version 2.0.1 208 | 209 | * NAT support on OpenBSD 2.9 and greater has been enabled again. 210 | * Allow comments and whitespace in /etc/oidentd_masq.conf. 211 | * Fix a crash that occurred when oidentd reloaded its configuration file. 212 | 213 | Changes in version 2.0.0 214 | 215 | * A new command-line flag, --config, can be used to specify the config file. 216 | * Support for OpenBSD 2.9 217 | * IP masquerading/NAT support for FreeBSD. 218 | * The bug that caused IP masquerading to fail was fixed. 219 | * More bug fixes. 220 | 221 | Changes in version 1.9.9.1 222 | 223 | * Lots of bugfixes. 224 | * Support for Solaris 5.4 - 5.8 225 | 226 | Changes in version 1.9.9 227 | 228 | * Complete rewrite. 229 | * Addition of system-wide and per-user configuration files. 230 | * IPv6 support. 231 | 232 | Changes in version 1.7.1 233 | 234 | * Fixed a bug that prevented oidentd from running in standalone mode. 235 | 236 | Changes in version 1.7.0 237 | 238 | * IP masquerading support for OpenBSD. 239 | * Support for FreeBSD 4.* 240 | * Support for libudb. 241 | 242 | Changes in version 1.6.4 243 | 244 | * Add -F and -O flags. See the manual page for a description. 245 | * Add the capability to set an identd reply for a specific user in 246 | /etc/identd.spoof. For example, the line "user:reply" will cause oidentd 247 | to return "reply" for every successful query for a connection of the user 248 | "user" 249 | 250 | Changes in version 1.6.3 251 | 252 | * Fix a few small bugs. 253 | * Add -q (quiet) flag, which suppresses normal system logging. 254 | 255 | Changes in version 1.6.2 256 | 257 | * New flag: -x (see the man page or ChangeLog) 258 | * Service names as well as port numbers are accepted where a port is supplied. 259 | /etc/oidentd.users 260 | * If our attempt to forward a connection to a host times out, fall back to 261 | masquerading lookup results 262 | 263 | Changes in version 1.6.1 264 | 265 | * -r works correctly in standalone mode. 266 | * You can now specify masks for networks in /etc/oidentd.users (See man page) 267 | (It used to only accept quad-dot IP notation) 268 | * You can now specify a hostname in /etc/oidentd.users 269 | 270 | Changes in version 1.6.0 271 | 272 | * The man page gets installed now 273 | * Rewrote "INSTALL" 274 | * Fixed (hopefully) the forwarding stuff. 275 | 276 | Changes in version 1.5.1 277 | 278 | * Code and documentation cleanups. 279 | * Regenerate autoconf scripts using version 2.13. 280 | 281 | Changes in version 1.5 282 | 283 | * Various small fixes and improvements. 284 | * Added support for OpenBSD, FreeBSD. 285 | * autoconf'd the package. 286 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | oidentd 2 | ======= 3 | 4 | Version 3.1.0 5 | 6 | Flexible, RFC 1413 compliant Ident daemon with NAT support. 7 | 8 | oidentd is a flexible Ident daemon for Linux, FreeBSD, OpenBSD, NetBSD, and 9 | DragonFly BSD. It is highly configurable, allowing the system administator to 10 | define custom responses based on host and port pairs. The administrator can 11 | also grant capabilities to individual users to allow them to change their Ident 12 | replies, generate random replies, or hide their connections. oidentd supports 13 | lookups for NAT connections and is able to forward queries to other servers. 14 | Detailed descriptions of all features are available in the manual pages. 15 | 16 | The INSTALL file contains instructions for installing oidentd. The HACKING 17 | file describes how to work with the source code. Please consult the 18 | KERNEL_SUPPORT.md file for information about the supported kernels. 19 | 20 | oidentd is maintained and developed by Janik Rabe , with 21 | contributions from many people who are listed in the AUTHORS file. oidentd was 22 | originally written by Ryan McCabe . 23 | 24 | The most recent version of oidentd is available from 25 | . 26 | 27 | Please report any bugs or submit pull requests on GitHub: 28 | . 29 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # autogen.sh - oidentd Ident (RFC 1413) implementation. 4 | # Copyright (c) 2019 Janik Rabe 5 | # 6 | # This program is free software; you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License, version 2, 8 | # as published by the Free Software Foundation. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program; if not, write to the Free Software 17 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | 19 | AUTOCONF=autoconf 20 | AUTOMAKE=automake 21 | AUTOHEADER=autoheader 22 | ACLOCAL=aclocal 23 | 24 | require_binary() { 25 | "$1" --version < /dev/null > /dev/null || { 26 | printf "Error: No usable installation of '%s' was found in your \$PATH.\n" "$1" 27 | printf " Please install it to compile oidentd.\n" 28 | 29 | test -z "$2" || printf "\nNote: %s\n" "$2" 30 | 31 | exit 1 32 | } 33 | } 34 | 35 | require_binary "$AUTOCONF" 36 | require_binary "$AUTOMAKE" 37 | require_binary "$AUTOHEADER" \ 38 | "Your version of 'automake' may not be recent enough." 39 | require_binary "$ACLOCAL" \ 40 | "Your version of 'automake' may not be recent enough." 41 | 42 | $ACLOCAL && $AUTOHEADER && $AUTOMAKE --gnu --add-missing --copy && $AUTOCONF || { 43 | printf "Error: Automatic generation of the configuration scripts has failed.\n" 44 | printf " Please try to generate them manually. If you believe this\n" 45 | printf " failure is the result of a bug in oidentd, please email\n" 46 | printf " with any relevant details.\n" 47 | exit 1 48 | } 49 | -------------------------------------------------------------------------------- /contrib/systemd/oidentd.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=RFC 1413 compliant Ident daemon 3 | Documentation=man:oidentd(8) man:oidentd.conf(5) man:oidentd_masq.conf(5) 4 | After=network.target 5 | 6 | [Service] 7 | ExecStart=/usr/sbin/oidentd 8 | ExecReload=/bin/kill -HUP $MAINPID 9 | PrivateDevices=true 10 | Restart=on-failure 11 | Type=forking 12 | 13 | [Install] 14 | WantedBy=multi-user.target 15 | -------------------------------------------------------------------------------- /contrib/systemd/oidentd.socket: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Conflicts=oidentd.service 3 | Description=RFC 1413 compliant Ident socket 4 | Documentation=man:oidentd(8) man:oidentd.conf(5) man:oidentd_masq.conf(5) 5 | 6 | [Socket] 7 | Accept=true 8 | ListenStream=113 9 | PrivateDevices=true 10 | 11 | [Install] 12 | WantedBy=sockets.target 13 | -------------------------------------------------------------------------------- /contrib/systemd/oidentd@.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=RFC 1413 compliant per-connection Ident server 3 | Documentation=man:oidentd(8) man:oidentd.conf(5) man:oidentd_masq.conf(5) 4 | 5 | [Service] 6 | ExecStart=/usr/sbin/oidentd -I 7 | PrivateDevices=true 8 | StandardInput=socket 9 | StandardError=syslog 10 | -------------------------------------------------------------------------------- /doc/Makefile.am: -------------------------------------------------------------------------------- 1 | man_MANS = \ 2 | oidentd.8 \ 3 | oidentd.conf.5 \ 4 | oidentd_masq.conf.5 5 | 6 | DISTCLEANFILES = \ 7 | $(man_MANS) 8 | 9 | EXTRA_DIST = \ 10 | book \ 11 | $(man_MANS) \ 12 | oidentd.8.adoc \ 13 | oidentd.conf.5.adoc \ 14 | oidentd_masq.conf.5.adoc 15 | 16 | SUFFIXES = .adoc 17 | 18 | oidentd.8: oidentd.8.adoc 19 | oidentd.conf.5: oidentd.conf.5.adoc 20 | oidentd_masq.conf.5: oidentd_masq.conf.5.adoc 21 | 22 | .adoc: 23 | asciidoctor \ 24 | --backend manpage \ 25 | --doctype manpage \ 26 | -a "sysconfdir=@sysconfdir@" \ 27 | -a "mansource=@PACKAGE_STRING@" \ 28 | $< 29 | -------------------------------------------------------------------------------- /doc/book/.gitignore: -------------------------------------------------------------------------------- 1 | /book/ 2 | -------------------------------------------------------------------------------- /doc/book/book.toml: -------------------------------------------------------------------------------- 1 | [book] 2 | authors = ["Janik Rabe"] 3 | language = "en" 4 | multilingual = false 5 | src = "src" 6 | title = "oidentd 3.1.0" 7 | -------------------------------------------------------------------------------- /doc/book/src/SUMMARY.md: -------------------------------------------------------------------------------- 1 | 10 | 11 | [About oidentd](index.md) 12 | [Download](download.md) 13 | 14 | - [Getting Started](getting-started/index.md) 15 | - [Installation](getting-started/installation.md) 16 | - [Capabilities](getting-started/capabilities.md) 17 | - [Configuration](getting-started/configuration/index.md) 18 | - [Examples](getting-started/configuration/examples.md) 19 | - [Starting the Server](getting-started/starting-the-server.md) 20 | - [Support](getting-started/support.md) 21 | 22 | - [Guides](guides/index.md) 23 | - [Using oidentd with Quassel](guides/using-oidentd-with-quassel.md) 24 | - [Using oidentd with ZNC](guides/using-oidentd-with-znc.md) 25 | 26 | - [NAT](nat/index.md) 27 | - [Introduction](nat/introduction.md) 28 | - [Static Replies](nat/static-replies.md) 29 | - [Forwarding](nat/forwarding.md) 30 | 31 | - [Security](security/index.md) 32 | - [Dropping Privileges](security/dropping-privileges.md) 33 | - [Hiding Connections](security/hiding-connections.md) 34 | - [Identification vs. Authentication](security/identification-vs-authentication.md) 35 | -------------------------------------------------------------------------------- /doc/book/src/download.md: -------------------------------------------------------------------------------- 1 | 10 | 11 | # Download 12 | 13 | ## Package Managers 14 | 15 | Many popular Linux and BSD distributions provide an `oidentd` package that can 16 | be installed with the package manager. 17 | On distributions that package the latest version of oidentd, this is normally 18 | the recommended approach. 19 | Beware that some distributions ship severely outdated versions. 20 | 21 | ## Releases 22 | 23 | [Releases can be downloaded from files.janikrabe.com][releases]. 24 | For oidentd, these are source releases (not compiled executables). 25 | See the `INSTALL` file for instructions on how to compile and install oidentd. 26 | 27 | [releases]: https://files.janikrabe.com/pub/oidentd/releases/ 28 | 29 | ## Source Code 30 | 31 | [The source code can be found on GitHub][github]. This is useful if you want to 32 | contribute to the project, or if you want to run the latest (unreleased) code. 33 | See the `HACKING` file for information on how to work with the source code. 34 | 35 | [github]: https://github.com/janikrabe/oidentd 36 | -------------------------------------------------------------------------------- /doc/book/src/getting-started/capabilities.md: -------------------------------------------------------------------------------- 1 | 10 | 11 | # Capabilities 12 | 13 | Capabilities allow the system administrator to control the set of features 14 | users have access to. 15 | They can be granted or revoked using [capability directives][capdirs]. 16 | No capabilities are granted to users by default. 17 | 18 | ## `forward` 19 | 20 | The `forward` capability allows users to forward Ident queries to another 21 | server. 22 | The `host` and `port` arguments specify the host and port of the receiving 23 | Ident server. 24 | This server must support forwarding (e.g., oidentd with the `--proxy` option). 25 | 26 | Forwarding does not allow users to send replies they otherwise would not be 27 | able to send. 28 | For example, if the receiving Ident server replies with the name of another 29 | user, the reply will be sent back to the client only if the user that owns the 30 | connection was granted the `spoof` and `spoof_all` capabilities. 31 | This restriction does not apply to `force forward` statements in the 32 | system-wide configuration file. 33 | 34 | Imperative syntax: `forward ` 35 | 36 | ## `hide` 37 | 38 | The `hide` capability allows users to hide their connections. 39 | When used, oidentd reports a `HIDDEN-USER` error to clients. 40 | 41 | Imperative syntax: `hide` 42 | 43 | ## `numeric` 44 | 45 | The `numeric` capability allows users to reply with their user ID (UID) instead 46 | of their user name. 47 | 48 | Imperative syntax: `numeric` 49 | 50 | ## `random` 51 | 52 | The `random` capability allows users to send random alphanumeric Ident replies. 53 | Replies are logged so that the system administrator can identify the user 54 | responsible for a particular connection. 55 | 56 | Imperative syntax: `random` 57 | 58 | ## `random_numeric` 59 | 60 | The `random_numeric` capability allows users to send random numeric Ident 61 | replies of the form `userNNNNN`, where `N` represents a digit from 0 to 9. 62 | Replies are logged so that the system administrator can identify the user 63 | responsible for a particular connection. 64 | 65 | Imperative syntax: `random_numeric` 66 | 67 | ## `reply` 68 | 69 | The `reply` capability cannot be granted or revoked. 70 | However, using it may require one or more of `spoof`, `spoof_all`, and 71 | `spoof_privport`, depending on the replies and type of connection. 72 | 73 | If more than one reply is given, a random reply is chosen from the list for 74 | each incoming query. 75 | At least one reply must be specified. 76 | 77 | Imperative syntax: `reply ` 78 | 79 | ## `spoof` 80 | 81 | The `spoof` capability allows users to send custom Ident replies, except in 82 | cases that require the `spoof_all` or `spoof_privport` capabilities. 83 | 84 | This capability does not have an imperative syntax. 85 | 86 | ## `spoof_all` 87 | 88 | The `spoof_all` capability allows users to reply with the names of other users 89 | on the system. 90 | It only works in conjunction with the `spoof` capability. 91 | 92 | This capability does not have an imperative syntax. 93 | 94 | ## `spoof_privport` 95 | 96 | The `spoof_privport` capability allows users to spoof replies for connections 97 | to privileged foreign ports (port numbers below 1024). 98 | It only works in conjunction with the `spoof` capability. 99 | 100 | This capability does not have an imperative syntax. 101 | 102 | [capdirs]: configuration/index.md#capability-directives 103 | -------------------------------------------------------------------------------- /doc/book/src/getting-started/configuration/examples.md: -------------------------------------------------------------------------------- 1 | 10 | 11 | # Examples 12 | 13 | The following examples illustrate how capabilities and conditional directives 14 | can be used in system-wide and user configuration files. 15 | 16 | Lines stating with `#` are comments. 17 | They are ignored by oidentd. 18 | 19 | ## System-wide Configuration File 20 | 21 | This configuration allows `ryan` to send spoofed and random Ident replies, 22 | except in response to lookups for connections to `example.net`. 23 | Other users' connections are hidden so that no user information is disclosed. 24 | 25 | ``` 26 | default { # User defaults 27 | default { # Connection defaults 28 | # Hide all connections from users not 29 | # explicitly listed in this file. 30 | force hide 31 | } 32 | } 33 | 34 | user ryan { # Settings for user "ryan" 35 | 36 | default { # Connection defaults 37 | # Allow ryan to send custom Ident replies, 38 | # except for the names of other users. 39 | allow spoof 40 | 41 | # Allow ryan to send random Ident replies. 42 | allow random 43 | } 44 | 45 | to example.net { # Connections to example.net 46 | # Do not allow ryan to spoof Ident replies. 47 | force reply "ryan" 48 | } 49 | } 50 | ``` 51 | 52 | ## User Configuration File 53 | 54 | This user configuration file instructs oidentd to reply to Ident queries for 55 | connections to foreign ports `6667` through `6697` with the name of a random 56 | Greek letter. 57 | This requires the `spoof` capability. 58 | It also requires the `spoof_all` capability if there is a local user named 59 | "alpha", "beta", or "gamma". 60 | 61 | A random alphanumeric Ident reply is sent in response to all other queries. 62 | This requires the `random` capability. 63 | 64 | ``` 65 | global { # Connection defaults 66 | # Send random Ident replies by default. 67 | random 68 | } 69 | 70 | fport 6667:6697 { # Foreign ports from 6667 to 6697 71 | # Choose one of three Greek letters at random. 72 | reply "alpha" "beta" "gamma" 73 | } 74 | ``` 75 | -------------------------------------------------------------------------------- /doc/book/src/getting-started/configuration/index.md: -------------------------------------------------------------------------------- 1 | 10 | 11 | # Configuration 12 | 13 | When an Ident query is received, oidentd normally replies with the user name of 14 | the user that owns the corresponding connection. 15 | Users can override this behavior only if they have been granted permission to 16 | do so through the system-wide configuration file. 17 | 18 | ## System-wide Configuration File 19 | 20 | The system-wide configuration file is usually found at `/etc/oidentd.conf` or 21 | `/usr/local/etc/oidentd.conf`, depending on how oidentd was installed. 22 | It is not necessary for this file to exist. 23 | 24 | This file may contain any number of [user directives][user-directives]. 25 | 26 | ## User Configuration File 27 | 28 | Each user may also create a user configuration file at `~/.config/oidentd.conf` 29 | or `~/.oidentd.conf`. 30 | If both files exist, only the former is used. 31 | The user configuration file is ignored if oidentd does not have permission to 32 | read it. 33 | 34 | This file may contain one directive of the following form: 35 | 36 | ``` 37 | global { 38 | 39 | } 40 | ``` 41 | 42 | This `global` directive matches all connections. 43 | If used, it should be the first directive in the file. 44 | 45 | The user configuration file may also contain any number of directives of the 46 | following form: 47 | 48 | ``` 49 | { 50 | 51 | } 52 | ``` 53 | 54 | In this form the directive only applies to connections that match the given 55 | range specification. 56 | 57 | ## User Directives 58 | 59 | A user directive takes one of the following forms: 60 | 61 | ``` 62 | default { 63 | 64 | } 65 | ``` 66 | 67 | This form can be used to specify defaults for users. 68 | There should be no more than one directive of this form. 69 | If used, it should be the first user directive. 70 | 71 | ``` 72 | user "" { 73 | 74 | } 75 | ``` 76 | 77 | In this form the directive applies only to the specified user. 78 | 79 | ## Range Directives 80 | 81 | A range directive takes one of the following forms: 82 | 83 | ``` 84 | default { 85 | 86 | } 87 | ``` 88 | 89 | In this form the directive matches when no other range directive in its scope 90 | does. 91 | There should be no more than one directive of this form. 92 | If used, it should be the first range directive. 93 | 94 | ``` 95 | { 96 | 97 | } 98 | ``` 99 | 100 | In this form the directive only applies to connections that match the given 101 | range specification. 102 | 103 | ## Range Specification 104 | 105 | A range specification takes the following form: 106 | 107 | ``` 108 | [to ] [fport ] [from ] [lport ] 109 | ``` 110 | 111 | * `to` is the foreign address associated with the connection. 112 | * `fport` is the foreign port associated with the connection. 113 | * `from` is the local address associated with the connection. 114 | * `lport` is the local port associated with the connection. 115 | 116 | At least one of the four filters must be specified. 117 | 118 | Hosts may be specified by hostname or by 119 | IP address. 120 | Ports may optionally be specified as a port range of the form `min:max`, 121 | `min:`, or `:max`. 122 | 123 | A range specification matches a connection if all specified filters match. 124 | 125 | ## Capability Directives 126 | 127 | A capability directive takes one of the following forms: 128 | 129 | ``` 130 | allow 131 | ``` 132 | 133 | In this form the directive grants the specified capability. 134 | 135 | ``` 136 | deny 137 | ``` 138 | 139 | In this form the directive revokes the specified capability. 140 | 141 | ``` 142 | force 143 | ``` 144 | 145 | In this form the directive enforces use of the specified capability. 146 | 147 | ## Capabilities 148 | 149 | The following are valid capabilities: 150 | 151 | * [`forward`][cap-forward] 152 | * [`hide`][cap-hide] 153 | * [`numeric`][cap-numeric] 154 | * [`random`][cap-random] 155 | * [`random_numeric`][cap-random_numeric] 156 | * [`spoof`][cap-spoof] 157 | * [`spoof_all`][cap-spoof_all] 158 | * [`spoof_privport`][cap-spoof_privport] 159 | 160 | ## Capability Statements 161 | 162 | The following are valid capability statements: 163 | 164 | * [`forward `][cap-forward] 165 | * [`hide`][cap-hide] 166 | * [`numeric`][cap-numeric] 167 | * [`random`][cap-random] 168 | * [`random_numeric`][cap-random_numeric] 169 | * [`reply `][cap-reply] 170 | 171 | ## Further Reading 172 | 173 | The `oidentd.conf(5)` manual page contains further information on how to 174 | configure oidentd, as well as detailed descriptions of all capabilities. 175 | 176 | [user-directives]: #user-directives 177 | [cap-forward]: ../capabilities.md#forward 178 | [cap-hide]: ../capabilities.md#hide 179 | [cap-numeric]: ../capabilities.md#numeric 180 | [cap-random]: ../capabilities.md#random 181 | [cap-random_numeric]: ../capabilities.md#random_numeric 182 | [cap-reply]: ../capabilities.md#reply 183 | [cap-spoof]: ../capabilities.md#spoof 184 | [cap-spoof_all]: ../capabilities.md#spoof_all 185 | [cap-spoof_privport]: ../capabilities.md#spoof_privport 186 | -------------------------------------------------------------------------------- /doc/book/src/getting-started/index.md: -------------------------------------------------------------------------------- 1 | 10 | 11 | # Getting Started 12 | 13 | This chapter describes how to install and configure oidentd. 14 | -------------------------------------------------------------------------------- /doc/book/src/getting-started/installation.md: -------------------------------------------------------------------------------- 1 | 10 | 11 | # Installation 12 | 13 | Most popular operating system distributions include a recent version of oidentd 14 | in their package repositories. 15 | Installing oidentd using a package manager is recommended in most cases. 16 | 17 | In some cases, however, it may be desirable to install oidentd from source. 18 | This may be useful if your distribution does not package a recent version of 19 | oidentd, or if there are any compile-time features you would like to enable. 20 | 21 | More detailed instructions for compiling and installing oidentd can be found in 22 | the `INSTALL` file included in all releases. 23 | 24 | ### Configuring the Build 25 | 26 | After downloading, verifying and extracting oidentd, enter the directory you 27 | extracted and run `./configure` to configure the build. 28 | 29 | On many modern Linux systems, you may have to install libnetfilter\_conntrack 30 | before running `./configure`. 31 | More information can be found in the `INSTALL` file in the source tree. 32 | 33 | The `./configure` script supports a number of optional flags: 34 | 35 | * `--disable-ipv6` disables support for 36 | IPv6. 37 | * `--disable-libnfct` disables support for libnetfilter\_conntrack. 38 | * `--disable-nat` disables support for 39 | NAT. 40 | * `--disable-debug` compiles oidentd without the `--debug` option to reduce the 41 | size of the executable. 42 | * `--enable-warn` is intended for developers and enables additional warning 43 | messages during compilation. 44 | 45 | ### Compile oidentd 46 | 47 | Run `make` to compile oidentd. 48 | 49 | You can run `src/oidentd --version` to verify that the compilation succeeded. 50 | 51 | ### Install oidentd 52 | 53 | Run `make install` as root to install oidentd. 54 | 55 | To uninstall oidentd later on, run `make uninstall` as root in the same 56 | directory. 57 | -------------------------------------------------------------------------------- /doc/book/src/getting-started/starting-the-server.md: -------------------------------------------------------------------------------- 1 | 10 | 11 | # Starting the Server 12 | 13 | oidentd can be run as a standalone server or started by a service manager. 14 | By default, oidentd forks to the background after starting up. 15 | 16 | If you installed oidentd from your distribution's package repositories, an 17 | initialization script or [systemd service][systemd] may already have been 18 | included in the package. 19 | Consult your distribution's documentation for more information. 20 | 21 | oidentd needs to be started as root on most systems, but normally drops its 22 | privileges automatically after starting up. 23 | See [Dropping Privileges][drop-privs] for details. 24 | 25 | Run `oidentd` to start the server. 26 | 27 | oidentd accepts a large number of command-line options. 28 | Some commonly used options are: 29 | 30 | * `-a`, `--address`: bind to the specified address (may be specified multiple 31 | times) 32 | * `-d`, `--debug`: show messages that may be useful for debugging 33 | * `-i`, `--foreground`: do not run as a background process 34 | * `-p`, `--port`: listen on the specified port instead of port 113 35 | 36 | The `oidentd(8)` manual page contains a complete list of options with detailed 37 | explanations. 38 | `oidentd --help` prints a list with more concise descriptions. 39 | 40 | ## systemd Service 41 | 42 | Many systemd-based distributions include service files for oidentd. 43 | On these distributions, oidentd can be started and enabled with the following 44 | command: 45 | 46 | ``` 47 | systemctl enable --now oidentd 48 | ``` 49 | 50 | [drop-privs]: ../security/dropping-privileges.md 51 | [systemd]: #systemd-service 52 | -------------------------------------------------------------------------------- /doc/book/src/getting-started/support.md: -------------------------------------------------------------------------------- 1 | 10 | 11 | # Support 12 | 13 | If you need help or have any questions about oidentd, feel free to use any of 14 | the following resources. 15 | 16 | ## Documentation 17 | 18 | Documentation for oidentd can be found in the `oidentd(8)`, `oidentd.conf(5)`, 19 | and `oidentd_masq.conf(5)` manual pages. 20 | 21 | Additional documentation for developers and package maintainers is available in 22 | the `INSTALL` and `HACKING` files in the oidentd source tree. 23 | 24 | ## IRC Channel 25 | 26 | You can find us in `#oidentd` on `ircs://irc.libera.chat`. 27 | Please be patient; it may take a while for someone to see your message. 28 | 29 | ## Contact the Maintainer 30 | 31 | Feel free to [contact the project maintainer][contact-maint] if you have any 32 | questions or need help with oidentd. 33 | 34 | This is also the best way to share any feedback you may have. 35 | We're always looking for ways to make oidentd better, and we'd appreciate your 36 | help. 37 | 38 | [contact-maint]: https://janikrabe.com/ 39 | -------------------------------------------------------------------------------- /doc/book/src/guides/index.md: -------------------------------------------------------------------------------- 1 | 10 | 11 | # Guides 12 | 13 | The guides in this chapter are intended to serve as a starting point when 14 | configuring oidentd to work with other software. 15 | -------------------------------------------------------------------------------- /doc/book/src/guides/using-oidentd-with-quassel.md: -------------------------------------------------------------------------------- 1 | 10 | 11 | # Using oidentd with Quassel 12 | 13 | You can use oidentd to spoof Ident replies so that they match Idents configured 14 | within Quassel. 15 | 16 | ## Forwarding to Quassel 17 | 18 | oidentd can forward incoming queries for connections owned by the Quassel user 19 | directly to Quassel's built-in Ident server. 20 | This is the recommended method. 21 | 22 | Append the following to your [system-wide configuration file][sys-conf]: 23 | 24 | ``` 25 | user "" { 26 | default { 27 | allow spoof 28 | 29 | # Add the next line if Quassel needs to 30 | # reply with the name of a local user. 31 | allow spoof_all 32 | 33 | force forward 34 | } 35 | } 36 | ``` 37 | 38 | Replace `` with the user name of the Quassel user (e.g., 39 | `quasselcore`). 40 | 41 | Replace `` with the IP address or 42 | hostname Quassel's built-in Ident server is configured to listen on (e.g., 43 | `::1`). 44 | 45 | Replace `` with the port Quassel's built-in Ident server is configured to 46 | listen on (e.g., `10113`). 47 | 48 | ## Using Quassel's oidentd Configuration Generator 49 | 50 | Quassel can automatically write to an oidentd user configuration file when 51 | establishing a new connection. 52 | 53 | Use of this feature is discouraged as of oidentd 2.3.0. 54 | Some IRC servers send Ident queries 55 | before the connection's local port is known to Quassel, which may cause lookups 56 | to fail. 57 | 58 | Append the following to your [system-wide configuration file][sys-conf]: 59 | 60 | ``` 61 | user "" { 62 | default { 63 | allow spoof 64 | 65 | # Use this only if Quassel needs to spoof local user names 66 | allow spoof_all 67 | } 68 | } 69 | ``` 70 | 71 | Replace `` with the user name of the Quassel user (e.g., 72 | `quasselcore`). 73 | 74 | Ensure that the Quassel home directory (typically `~quasselcore`) is 75 | world-executable (mode `0711`) so that oidentd can read the user configuration 76 | file: 77 | 78 | ``` 79 | chmod 0711 ~quasselcore 80 | ``` 81 | 82 | Finally, make sure Quassel is run with the `--oidentd` flag. 83 | 84 | Your changes will take effect after you reload oidentd and restart Quassel. 85 | 86 | [sys-conf]: ../getting-started/configuration/index.md#system-wide-configuration-file 87 | -------------------------------------------------------------------------------- /doc/book/src/guides/using-oidentd-with-znc.md: -------------------------------------------------------------------------------- 1 | 10 | 11 | # Using oidentd with ZNC 12 | 13 | You can use oidentd to spoof Ident replies so that they match Idents configured 14 | within ZNC. 15 | 16 | Append the following to your [system-wide configuration file][sys-conf]: 17 | 18 | ``` 19 | user "" { 20 | default { 21 | allow spoof 22 | 23 | # Add the next line if ZNC needs to 24 | # reply with the name of a local user. 25 | allow spoof_all 26 | } 27 | } 28 | ``` 29 | 30 | Replace `` with the user name of the ZNC user (e.g., `znc`). 31 | 32 | Change to the user running ZNC (e.g., using `su znc -ls "$SHELL"`), and use the 33 | following commands to create an empty [user configuration file][usr-conf]: 34 | 35 | ``` 36 | touch ~/.oidentd.conf 37 | chmod 0644 ~/.oidentd.conf 38 | ``` 39 | 40 | Ensure that the ZNC home directory (typically `~znc`) is world-executable (mode 41 | `0711`) so that oidentd can read the user configuration file: 42 | 43 | ``` 44 | chmod 0711 ~ 45 | ``` 46 | 47 | Ensure that ZNC's *identfile* module is loaded and configured correctly: 48 | 49 | ``` 50 | /MSG *status LoadMod identfile 51 | /MSG *identfile SetFile ~/.oidentd.conf 52 | /MSG *identfile SetFormat global { reply "%user%" } 53 | /MSG *status SaveConfig 54 | ``` 55 | 56 | Note that `%user%` expands to the name of the ZNC user that initiated the 57 | connection. 58 | Another popular choice is `%ident%`, which allows users to specify any Ident. 59 | 60 | Your changes will take effect after you reload oidentd and reconnect to 61 | IRC. 62 | 63 | [sys-conf]: ../getting-started/configuration/index.md#system-wide-configuration-file 64 | [usr-conf]: ../getting-started/configuration/index.md#user-configuration-file 65 | -------------------------------------------------------------------------------- /doc/book/src/index.md: -------------------------------------------------------------------------------- 1 | 10 | 11 | # About oidentd 12 | 13 | _Flexible, RFC 1413 compliant Ident daemon with NAT support._ 14 | 15 | oidentd is a flexible, RFC 1413 16 | compliant Ident server. 17 | It runs on Linux, FreeBSD, OpenBSD, NetBSD, and DragonFly BSD. 18 | It is highly configurable, allowing the system administrator to define custom 19 | responses based on host and port pairs. 20 | The administrator can also grant capabilities to individual users to allow them 21 | to change their Ident replies, generate random replies, or hide their 22 | connections. 23 | oidentd supports lookups for NAT connections and is able to forward queries to 24 | other servers. 25 | 26 | oidentd was originally written by Ryan McCabe in 1998. Since January 2018, it 27 | is maintained by Janik Rabe, with contributions from several other volunteers. 28 | 29 | The Ident Protocol is used primarily on 30 | IRC to detect and prevent abuse and to 31 | identify users connecting through shared networks. 32 | 33 | ## Features 34 | 35 | * oidentd is highly [configurable][configuration], but configuration is 36 | optional and sensible defaults are provided. 37 | * oidentd provides system administrators with a granular, capability-based 38 | [access control][acl] system. 39 | * [Conditional replies][conditionals] enable users to send replies based on 40 | connection information, such as ports and IP addresses. 41 | * oidentd is capable of sending [hidden][cap-hide], [randomized][cap-random], 42 | and [spoofed][cap-spoof] replies. 43 | * oidentd can optionally handle requests for 44 | [NAT connections][nat] 45 | and is capable of forwarding requests to other Ident servers. 46 | * Both IPv4 and 47 | IPv6 are supported. 48 | * oidentd is free software licensed under the 49 | GNU 50 | GPLv2. 51 | 52 | [acl]: getting-started/configuration/index.md#capability-directives 53 | [cap-hide]: getting-started/capabilities.md#hide 54 | [cap-random]: getting-started/capabilities.md#random 55 | [cap-spoof]: getting-started/capabilities.md#spoof 56 | [conditionals]: getting-started/configuration/index.md#range-specification 57 | [configuration]: getting-started/configuration/index.md 58 | [nat]: nat/introduction.md 59 | -------------------------------------------------------------------------------- /doc/book/src/nat/forwarding.md: -------------------------------------------------------------------------------- 1 | 10 | 11 | # Forwarding 12 | 13 | oidentd can forward Ident queries to the host they were intended for, provided 14 | that this host is connecting through the machine oidentd is running on. 15 | 16 | When forwarding is enabled, the default behavior is to forward immediately and 17 | only fall back to using the configured [static replies][static-replies] if 18 | forwarding fails. 19 | This can be changed by using the `--masquerade-first` (`-M`) flag, in which 20 | case oidentd only forwards requests if no matching static reply was found. 21 | 22 | ## Configuring the Gateway 23 | 24 | Forwarding can be enabled on the device performing network address translation 25 | by running oidentd with the `--forward` (`-f`) option. 26 | Optionally, a target port may be specified using `--forward=port`. 27 | If no port is specified, port `113` is used. 28 | 29 | ## Configuring the Servers 30 | 31 | All machines that need to receive forwarded queries must be running an Ident 32 | server capable of handling these queries, such as oidentd with the `--proxy` 33 | (`-P`) option. 34 | For example, oidentd can be run on a machine behind 35 | NAT with the following 36 | command: 37 | 38 | ``` 39 | oidentd -P 10.0.0.1 40 | ``` 41 | 42 | This allows `10.0.0.1` to forward queries to the current oidentd instance. 43 | 44 | If you specified a custom target port for forwarding, make sure the target 45 | server is configured to listen on that port: 46 | 47 | ``` 48 | oidentd -P 10.0.0.1 -p 113 49 | ``` 50 | 51 | Port `113` is the default and does not need to be specified explicitly. 52 | 53 | [static-replies]: static-replies.md 54 | -------------------------------------------------------------------------------- /doc/book/src/nat/index.md: -------------------------------------------------------------------------------- 1 | 10 | 11 | # NAT 12 | 13 | This chapter explains how to use oidentd for 14 | NAT connections. 15 | -------------------------------------------------------------------------------- /doc/book/src/nat/introduction.md: -------------------------------------------------------------------------------- 1 | 10 | 11 | # Introduction 12 | 13 | oidentd can handle Ident queries for other machines connecting through the 14 | server it is running on. 15 | This is especially useful when the server running oidentd performs Network 16 | Address Translation (NAT). 17 | 18 | Before configuring oidentd to use 19 | NAT, please take a look at the 20 | `KERNEL_SUPPORT.md` file in the source tree to find out whether 21 | NAT is supported on your 22 | system. 23 | 24 | oidentd supports two features that may be useful in combination with 25 | NAT: 26 | 27 | - [Static replies][static] instruct oidentd to send a certain reply in response 28 | to every Ident query intended for a particular host or subnetwork. 29 | - [Forwarding][forwarding] allows Ident queries to be forwarded through 30 | NAT to the host that 31 | established a connection. 32 | 33 | [static]: static-replies.md 34 | [forwarding]: forwarding.md 35 | -------------------------------------------------------------------------------- /doc/book/src/nat/static-replies.md: -------------------------------------------------------------------------------- 1 | 10 | 11 | # Static Replies 12 | 13 | oidentd can send different Ident replies for each host connecting through the 14 | machine it is running on. 15 | 16 | To enable this functionality, oidentd must be run with the `--masquerade` 17 | (`-m`) flag. 18 | 19 | ## Configuring Replies 20 | 21 | Replies can be configured in the masquerading configuration file, which is 22 | usually found in `/etc/oidentd_masq.conf` or in 23 | `/usr/local/etc/oidentd_masq.conf`, depending on how oidentd was installed. 24 | 25 | This file should consist of lines of the following form: 26 | 27 | ``` 28 | [/subnet] ident_reply system_type 29 | ``` 30 | 31 | The masquerading configuration file is read from top to bottom, so more 32 | specific rules should be placed before more general ones. 33 | For example: 34 | 35 | ``` 36 | 10.0.0.1 user1 UNIX 37 | 10.0.0.2 user2 FREEBSD 38 | 10.0.0.0/24 user3 OTHER 39 | ``` 40 | 41 | In this example, a `user1` reply is sent in response to all requests for 42 | `10.0.0.1`. 43 | A `user2` reply is sent for all requests for `10.0.0.2`. 44 | Finally, `user3` is sent in response to requests for other machines in the 45 | `10.0.0.0/24` subnetwork. 46 | 47 | Detailed information can be found in the `oidentd_masq.conf(5)` manual page. 48 | -------------------------------------------------------------------------------- /doc/book/src/security/dropping-privileges.md: -------------------------------------------------------------------------------- 1 | 10 | 11 | # Dropping Privileges 12 | 13 | It is highly recommended not to run internet-facing services as root. 14 | For this reason, oidentd attempts to switch to an unprivileged user 15 | automatically after starting up. 16 | 17 | Please note that oidentd needs to run as root on a small number of systems. 18 | On these systems, a warning is printed at startup and privileges are not 19 | dropped automatically. 20 | Your system is affected by this limitation if `oidentd --version` prints "Needs 21 | root access: Yes". 22 | 23 | ## Default User 24 | 25 | By default, oidentd attempts to run as one of the following users, in order of 26 | preference. 27 | If a user does not exist, oidentd tries to use the next one. 28 | 29 | * oidentd 30 | * nobody 31 | 32 | If neither of the above users exists, oidentd switches to user ID 65534. 33 | 34 | ## Default Group 35 | 36 | By default, oidentd attempts to run as one of the following groups, in order of 37 | preference. 38 | If a group does not exist, oidentd tries to use the next one. 39 | 40 | * oidentd 41 | * nobody 42 | * nogroup 43 | 44 | If none of the above groups exist, oidentd switches to group ID 65534. 45 | 46 | ## Changing This Behavior 47 | 48 | The `--user` and `--group` options can be used to run oidentd as another user 49 | or group. 50 | oidentd refuses to start up if the user or group specified by either of these 51 | options does not exist, or if privileges cannot be dropped for some other 52 | reason. 53 | -------------------------------------------------------------------------------- /doc/book/src/security/hiding-connections.md: -------------------------------------------------------------------------------- 1 | 10 | 11 | # Hiding Connections 12 | 13 | It is recommended to hide connections to any servers running on your machine to 14 | avoid disclosing unnecessary information. 15 | 16 | The recommended way to accomplish this is to hide all connections and only 17 | respond to queries for certain user accounts: 18 | 19 | ``` 20 | default { 21 | default { 22 | force hide 23 | } 24 | } 25 | 26 | user "ryan" { 27 | default { 28 | force reply "ryan" 29 | } 30 | } 31 | ``` 32 | 33 | It is also possible to hide individual users' connections: 34 | 35 | ``` 36 | user "root" { 37 | default { 38 | force hide 39 | } 40 | } 41 | 42 | user "http" { 43 | default { 44 | force hide 45 | } 46 | } 47 | ``` 48 | 49 | Alternatively, the [`random`][cap_random] and 50 | [`random_numeric`][cap_random_numeric] capabilities may be used to conceal 51 | users' real login names while still allowing the system administrator to 52 | identify who was responsible for a particular connection. 53 | See the [list of capabilities][caps] for more information. 54 | 55 | [caps]: ../getting-started/capabilities.md 56 | [cap_random]: ../getting-started/capabilities.md#random 57 | [cap_random_numeric]: ../getting-started/capabilities.md#random_numeric 58 | -------------------------------------------------------------------------------- /doc/book/src/security/identification-vs-authentication.md: -------------------------------------------------------------------------------- 1 | 10 | 11 | # Identification vs. Authentication 12 | 13 | The Ident protocol was designed for identification, not authentication. 14 | Please don't use it for access control. 15 | 16 | The primary purpose of the Ident protocol is to serve as an auditing and abuse 17 | prevention mechanism. 18 | For example, many IRC servers act as 19 | Ident clients, querying and publicly displaying users' Ident replies. 20 | This allows providers of IRC bouncers, 21 | shell accounts and other services to identify users abusing their systems and 22 | enables channel operators and network operators to remove individual users 23 | without excluding their entire host or network. 24 | 25 | Ident queries and replies are sent as plain text, with no encryption or 26 | authentication, and can be intercepted or modified by an attacker. 27 | In addition, it is not possible to prevent compromised or malicious hosts from 28 | [sending arbitrary Ident replies][cap-spoof]. 29 | For these reasons, the Ident protocol is not suitable for authentication or 30 | access control. 31 | 32 | [cap-spoof]: ../getting-started/capabilities.md#spoof 33 | -------------------------------------------------------------------------------- /doc/book/src/security/index.md: -------------------------------------------------------------------------------- 1 | 10 | 11 | # Security 12 | 13 | This chapter covers security concerns related to Ident servers and provides 14 | advice for mitigating possible risks. 15 | -------------------------------------------------------------------------------- /doc/oidentd.8.adoc: -------------------------------------------------------------------------------- 1 | //// 2 | Copyright (c) 2019 Janik Rabe 3 | 4 | Permission is granted to copy, distribute and/or modify this document 5 | under the terms of the GNU Free Documentation License, Version 1.3 6 | or any later version published by the Free Software Foundation; 7 | with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. 8 | A copy of the license is included in the file 'COPYING.DOC' 9 | //// 10 | 11 | oidentd(8) 12 | ========== 13 | :doctype: manpage 14 | :man manual: oidentd User Manual 15 | :man source: oidentd 16 | :reproducible: yes 17 | :revdate: 2023-03-11 18 | :sysconfdir: /etc 19 | 20 | 21 | NAME 22 | ---- 23 | 24 | oidentd - flexible, RFC 1413 compliant Ident daemon with NAT support 25 | 26 | 27 | SYNOPSIS 28 | -------- 29 | 30 | *oidentd* ['OPTIONS'] 31 | 32 | 33 | DESCRIPTION 34 | ----------- 35 | 36 | *oidentd* implements the Identification Protocol as described in RFC 1413. By 37 | default, *oidentd* replies with the username of the owner of connections. This 38 | behavior can be altered in *oidentd.conf*(5) and by using the options specified 39 | in this document. 40 | 41 | 42 | OPTIONS 43 | ------- 44 | 45 | *-a, --address*='ADDRESS':: 46 | Bind to the specified address. This option causes *oidentd* to listen for 47 | incoming connections only on the specified address or addresses instead of on 48 | all interfaces. This option may be specified more than once to configure 49 | multiple addresses. 50 | 51 | *-c, --charset*='CHARSET':: 52 | Inform clients that Ident replies use the specified character set as defined 53 | in RFC 1340 or its successors. The default is not to send a character set to 54 | clients. 55 | 56 | *-C, --config*='FILE':: 57 | Use the specified system-wide configuration file. If this option is not 58 | given, *oidentd* defaults to *{sysconfdir}/oidentd.conf*. The format of the 59 | system-wide configuration file is described in *oidentd.conf*(5). 60 | 61 | *-d, --debug*:: 62 | Show debug messages, including detailed lookup information that may be useful 63 | for diagnosing issues with failed lookups. This option is only available if 64 | *oidentd* was compiled with debugging support. 65 | 66 | *-e, --error*:: 67 | Hide error messages, returning *UNKNOWN-ERROR* for all errors. This includes 68 | the *NO-USER*, *HIDDEN-USER* and *INVALID-PORT* errors. This option may be 69 | used to conceal the fact that *oidentd* is hiding Ident responses for a user. 70 | 71 | *-f, --forward*=['PORT']:: 72 | Forward requests for hosts masquerading through the server *oidentd* is 73 | running on to the host that established the corresponding connection. The 74 | target host must be running *oidentd* with the *--proxy* option, or some 75 | Ident server returning static responses regardless of the query. If no port 76 | is specified, the default Ident port (113) is used. If forwarding fails, 77 | *oidentd* falls back to the response specified in *oidentd_masq.conf*(5). 78 | This option implies *--masquerade*. The *--masquerade-first* option can be 79 | used to forward queries only if no response was specified in 80 | *oidentd_masq.conf*(5). 81 | 82 | *-g, --group*='GROUP|GID':: 83 | Run as the specified group or GID. If this option is not given, *oidentd* 84 | falls back to running as "oidentd", "nobody", "nogroup" or GID 65534, in this 85 | order. On systems that require *oidentd* to run as the superuser, a warning 86 | is shown and the group is not changed automatically. 87 | 88 | *-h, --help*:: 89 | Print a summary of options and exit. 90 | 91 | *-i, --foreground*:: 92 | Do not fork to background. This option may be useful for debugging, or for 93 | running *oidentd* from a service manager like *systemd*(1) with 94 | *Type=simple*. 95 | 96 | *-I, --stdio*:: 97 | Read a single Ident query from standard input, write the response to standard 98 | output, then exit. This option may be useful for debugging, or when running 99 | *oidentd* from a listener daemon such as *xinetd*(8). 100 | 101 | *-l, --limit*='MAX':: 102 | Limit the maximum number of concurrent connections to the specified value. 103 | Further connections beyond this limit will be closed immediately without 104 | spawning a new process. If this option is not specified, no limit is 105 | enforced. 106 | 107 | *-m, --masquerade*:: 108 | Enable support for NAT connections, allowing Ident lookups intended for hosts 109 | masquerading through the server running *oidentd*. Ident responses for NAT 110 | connections can be configured in the *oidentd_masq.conf*(5) configuration 111 | file. 112 | 113 | *-M, --masquerade-first*:: 114 | If an entry matching the target host exists in the *oidentd_masq.conf*(5) 115 | configuration file, return the configured Ident response instead of 116 | forwarding the query. With this option, queries are forwarded only if no 117 | static response has been configured. If this option is not specified, the 118 | default behavior of *--forward* is to forward queries before checking the 119 | *oidentd_masq.conf*(5) file. This option implies *--forward* and 120 | *--masquerade*. 121 | 122 | *-o, --other*=['OS']:: 123 | Set an alternative operating system string to send alongside Ident responses. 124 | Note that some clients may interpret queries as having failed when an unknown 125 | operating system is returned. If this option is not specified, the value 126 | *UNIX* is used. If this option is specified without an argument, *OTHER* is 127 | returned. 128 | 129 | *-p, --port*='PORT':: 130 | Listen on the specified port instead of port 113. 131 | 132 | *-P, --proxy*='ORIGIN':: 133 | Allow the specified host to forward queries to this instance using the 134 | *--forward* option. If *--reply* is not specified, this option must be 135 | enabled for *oidentd* to correctly handle forwarded connections. 136 | 137 | *-q, --quiet*:: 138 | Suppress normal logging, showing only critical messages. 139 | 140 | *-r, --reply*='REPLY':: 141 | When a lookup fails, send the specified Ident response as if it had 142 | succeeded. 143 | 144 | *-R, --reply-all*='REPLY':: 145 | Send the specified reply in response to all well-formed queries. When this 146 | option is used, the configuration files are not read and connection lookups 147 | are never performed. Privileged initialization is not performed on systems 148 | that would otherwise require it, so unprivileged users can run oidentd with 149 | this option as long as they have permission to bind the requested port. 150 | 151 | *-S, --nosyslog*:: 152 | Log messages to the standard error stream, even if it is not a terminal. If 153 | standard error is a terminal, messages are written to it by default. 154 | 155 | *-t, --timeout*='SECONDS':: 156 | Close connections if no Ident query is received within the specified number 157 | of seconds. By default, connections are closed after 30 seconds. 158 | 159 | *-u, --user*='USER|UID':: 160 | Run as the specified user or UID. If this option is not given, *oidentd* 161 | falls back to running as "oidentd", "nobody" or UID 65534, in this order. On 162 | systems that require *oidentd* to run as the superuser, a warning is shown 163 | and the user is not changed automatically. 164 | 165 | *-v, --version*:: 166 | Print version and build information and exit. 167 | 168 | 169 | FILES 170 | ----- 171 | 172 | *{sysconfdir}/oidentd.conf*:: 173 | System-wide configuration file; see *oidentd.conf*(5). 174 | 175 | *~/.config/oidentd.conf*, *~/.oidentd.conf*:: 176 | User configuration files; see *oidentd.conf*(5). 177 | 178 | *{sysconfdir}/oidentd_masq.conf*:: 179 | Masquerading configuration file; see *oidentd_masq.conf*(5). 180 | 181 | 182 | AUTHOR 183 | ------ 184 | 185 | mailto:info@janikrabe.com[Janik Rabe]:: 186 | https://janikrabe.com 187 | 188 | Originally written by Ryan McCabe. 189 | 190 | 191 | BUGS 192 | ---- 193 | 194 | Please report any bugs at . 195 | 196 | 197 | SEE ALSO 198 | -------- 199 | 200 | *oidentd.conf*(5) 201 | *oidentd_masq.conf*(5) 202 | -------------------------------------------------------------------------------- /doc/oidentd_masq.conf.5.adoc: -------------------------------------------------------------------------------- 1 | //// 2 | Copyright (c) 2019 Janik Rabe 3 | 4 | Permission is granted to copy, distribute and/or modify this document 5 | under the terms of the GNU Free Documentation License, Version 1.3 6 | or any later version published by the Free Software Foundation; 7 | with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. 8 | A copy of the license is included in the file 'COPYING.DOC' 9 | //// 10 | 11 | oidentd_masq.conf(5) 12 | ==================== 13 | :doctype: manpage 14 | :man manual: oidentd User Manual 15 | :man source: oidentd 16 | :reproducible: yes 17 | :revdate: 2023-03-11 18 | :sysconfdir: /etc 19 | 20 | 21 | NAME 22 | ---- 23 | 24 | oidentd_masq.conf - oidentd NAT configuration file 25 | 26 | 27 | DESCRIPTION 28 | ----------- 29 | 30 | If NAT support is enabled with the *--masquerade* option, *oidentd* reads the 31 | *{sysconfdir}/oidentd_masq.conf* file to determine Ident responses to queries 32 | intended for other machines. It is also possible to forward queries to Ident 33 | servers on the hosts connecting through the machine *oidentd* runs on. For more 34 | information on forwarding, please see the *--forward* option in *oidentd*(8). 35 | 36 | The NAT configuration file contains one rule per line. Lines are read from top 37 | to bottom, and only the first matching rule is used. Lines starting with a 38 | number sign ("#") are ignored. 39 | 40 | 41 | RULE FORMAT 42 | ----------- 43 | 44 | Rules must have the following form: 45 | 46 | [subs="quotes"] 47 | .... 48 | _host_[/_mask_] _response_ _system-type_ 49 | .... 50 | 51 | The _host_ field specifies the hostname or IP address of the host that owns the 52 | connection for which an Ident query was received. This host must be connecting 53 | through the machine *oidentd* runs on. The host may be specified as either an 54 | IP address or a hostname. 55 | 56 | If a network mask is specified using the _mask_ field, the rule applies to all 57 | hosts in the given subnetwork. Network masks may be specified in dot notation 58 | (e.g., "255.255.192.0") or in CIDR notation (e.g., "18"). 59 | 60 | The _response_ field specifies the response to be sent when receiving a query 61 | for the specified host or subnetwork. 62 | 63 | The _system-type_ field specifies the operating system to send alongside the 64 | Ident response. See the *--other* option in *oidentd*(8) for more information. 65 | 66 | 67 | EXAMPLES 68 | -------- 69 | 70 | [subs="quotes"] 71 | .... 72 | # host[/mask] response system-type 73 | 10.0.0.1 user1 UNIX 74 | server.internal user2 UNIX-BSD 75 | 10.0.0.0/24 user3 UNIX 76 | 10.0.0.0/255.255.0.0 user4 UNKNOWN 77 | .... 78 | 79 | Note that the order of the rules is significant in this example. Due to lines 80 | being read from top to bottom, more specific rules must precede more general 81 | ones. For example, the rule for "10.0.0.1" would not match any connections if 82 | it were preceded by the more general "10.0.0.0/24". 83 | 84 | 85 | AUTHOR 86 | ------ 87 | 88 | mailto:info@janikrabe.com[Janik Rabe]:: 89 | https://janikrabe.com 90 | 91 | Originally written by Ryan McCabe. 92 | 93 | 94 | BUGS 95 | ---- 96 | 97 | Please report any bugs at . 98 | 99 | 100 | SEE ALSO 101 | -------- 102 | 103 | *oidentd*(8) 104 | *oidentd.conf*(5) 105 | -------------------------------------------------------------------------------- /oidentd.conf: -------------------------------------------------------------------------------- 1 | # This is the system-wide configuration file for oidentd. This 2 | # file provides defaults for users. The settings in this file 3 | # can be overridden by user configuration files of users who 4 | # have been granted sufficient privileges through this file. 5 | # 6 | # See oidentd.conf(5) for more information. 7 | 8 | default { 9 | default { 10 | # Capabilities are disabled by default 11 | deny spoof 12 | deny spoof_all 13 | deny spoof_privport 14 | deny random 15 | deny random_numeric 16 | deny numeric 17 | deny hide 18 | deny forward 19 | } 20 | } 21 | 22 | user root { 23 | default { 24 | # Hide connections belonging to the superuser. 25 | force hide 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /oidentd_masq.conf: -------------------------------------------------------------------------------- 1 | # This is the NAT configuration file for oidentd. 2 | # If you enable NAT support with the '-m' option, 3 | # this file is read to determine the appropriate 4 | # Ident responses to queries intended for hosts 5 | # masquerading through this server. 6 | # 7 | # See oidentd_masq.conf(5) for more information. 8 | 9 | # host[/mask] response system-type 10 | # 10.0.0.1 user1 UNIX 11 | # server.internal user2 UNIX-BSD 12 | # 10.0.0.0/24 user3 UNIX 13 | # 10.0.0.0/255.255.0.0 user4 UNKNOWN 14 | -------------------------------------------------------------------------------- /src/Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = missing 2 | sbin_PROGRAMS = oidentd 3 | 4 | oidentd_LDADD = -Lmissing -lmissing $(ADD_LIB) 5 | 6 | AM_CFLAGS = $(DEBUG_CFLAGS) $(WARN_CFLAGS) 7 | AM_CPPFLAGS = -I "$(srcdir)/missing" \ 8 | -D "SYSCONFDIR=\"$(sysconfdir)\"" 9 | AM_YFLAGS = -d 10 | 11 | EXTRA_DIST = kernel 12 | 13 | DISTCLEANFILES = \ 14 | os.c 15 | 16 | oidentd_SOURCES = \ 17 | oidentd.c \ 18 | util.c \ 19 | inet_util.c \ 20 | forward.c \ 21 | user_db.c \ 22 | options.c \ 23 | masq.c \ 24 | cfg_scan.l \ 25 | cfg_parse.y \ 26 | os.c 27 | 28 | noinst_HEADERS = \ 29 | oidentd.h \ 30 | cfg_parse.h \ 31 | inet_util.h \ 32 | forward.h \ 33 | masq.h \ 34 | netlink.h \ 35 | options.h \ 36 | user_db.h \ 37 | util.h 38 | 39 | BUILT_SOURCES = \ 40 | cfg_parse.h \ 41 | cfg_parse.c \ 42 | cfg_scan.c 43 | 44 | CLEANFILES = \ 45 | $(BUILT_SOURCES) 46 | -------------------------------------------------------------------------------- /src/cfg_scan.l: -------------------------------------------------------------------------------- 1 | %{ 2 | /* 3 | ** cfg_scan.l - oidentd configuration scanner. 4 | ** Copyright (c) 2001-2006 Ryan McCabe 5 | ** Copyright (c) 2018-2019 Janik Rabe 6 | ** 7 | ** This program is free software; you can redistribute it and/or modify 8 | ** it under the terms of the GNU General Public License, version 2, 9 | ** as published by the Free Software Foundation. 10 | ** 11 | ** This program is distributed in the hope that it will be useful, 12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | ** GNU General Public License for more details. 15 | ** 16 | ** You should have received a copy of the GNU General Public License 17 | ** along with this program; if not, write to the Free Software 18 | ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 | */ 20 | 21 | #include 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | #include "oidentd.h" 38 | #include "util.h" 39 | #include "missing.h" 40 | #include "user_db.h" 41 | #include "options.h" 42 | #include "cfg_parse.h" 43 | 44 | #define STRING_CHUNK_LEN 256 45 | 46 | extern int parser_mode; 47 | 48 | static char *string_buf; 49 | static size_t str_idx; 50 | static size_t max_slen; 51 | 52 | static char get_esc_char(char c); 53 | 54 | u_int32_t current_line; 55 | 56 | %} 57 | 58 | %option case-insensitive 59 | %option never-interactive 60 | %option noyywrap 61 | %option nounput 62 | 63 | %x state_comment 64 | %x state_string 65 | 66 | TO to 67 | FROM from 68 | USER user 69 | DEFAULT default 70 | GLOBAL global 71 | FPORT fport 72 | LPORT lport 73 | ALLOW allow 74 | DENY deny 75 | FORCE force 76 | HIDE hide 77 | REPLY reply 78 | RANDOM random 79 | NUMERIC numeric 80 | RANDOM_NUMERIC random_numeric 81 | SPOOF spoof 82 | SPOOF_ALL spoof_all 83 | SPOOF_PRIVPORT spoof_privport 84 | FORWARD forward 85 | 86 | %% 87 | 88 | "{"|"}" { 89 | return yytext[0]; 90 | } 91 | 92 | [ \t]+ { 93 | /* ignore */ 94 | } 95 | 96 | #[^\n]* { 97 | /* ignore */ 98 | } 99 | 100 | {USER} { 101 | return TOK_USER; 102 | } 103 | 104 | {DEFAULT} { 105 | return TOK_DEFAULT; 106 | } 107 | 108 | {GLOBAL} { 109 | return TOK_GLOBAL; 110 | } 111 | 112 | {TO} { 113 | return TOK_TO; 114 | } 115 | 116 | {FROM} { 117 | return TOK_FROM; 118 | } 119 | 120 | {FPORT} { 121 | return TOK_FPORT; 122 | } 123 | 124 | {LPORT} { 125 | return TOK_LPORT; 126 | } 127 | 128 | {ALLOW} { 129 | yylval.value = ACTION_ALLOW; 130 | return TOK_ALLOWDENY; 131 | } 132 | 133 | {DENY} { 134 | yylval.value = ACTION_DENY; 135 | return TOK_ALLOWDENY; 136 | } 137 | 138 | {FORCE} { 139 | return TOK_FORCE; 140 | } 141 | 142 | {HIDE} { 143 | yylval.value = CAP_HIDE; 144 | return TOK_CAP; 145 | } 146 | 147 | {RANDOM} { 148 | yylval.value = CAP_RANDOM; 149 | return TOK_CAP; 150 | } 151 | 152 | {NUMERIC} { 153 | yylval.value = CAP_NUMERIC; 154 | return TOK_CAP; 155 | } 156 | 157 | {RANDOM_NUMERIC} { 158 | yylval.value = CAP_RANDOM_NUMERIC; 159 | return TOK_CAP; 160 | } 161 | 162 | {SPOOF} { 163 | yylval.value = CAP_SPOOF; 164 | return TOK_CAP; 165 | } 166 | 167 | {SPOOF_ALL} { 168 | yylval.value = CAP_SPOOF_ALL; 169 | return TOK_CAP; 170 | } 171 | 172 | {SPOOF_PRIVPORT} { 173 | yylval.value = CAP_SPOOF_PRIVPORT; 174 | return TOK_CAP; 175 | } 176 | 177 | {REPLY} { 178 | return TOK_REPLY; 179 | } 180 | 181 | {FORWARD} { 182 | return TOK_FORWARD; 183 | } 184 | 185 | \" { 186 | string_buf = xmalloc(STRING_CHUNK_LEN); 187 | str_idx = 0; 188 | max_slen = STRING_CHUNK_LEN; 189 | 190 | BEGIN(state_string); 191 | } 192 | 193 | "/*" BEGIN(state_comment); 194 | 195 | [^*\n]* { 196 | /* ignore */; 197 | } 198 | 199 | "*"+[^*/\n]* { 200 | /* ignore */; 201 | } 202 | 203 | "*"+"/" { 204 | BEGIN(INITIAL); 205 | } 206 | 207 | \" { 208 | string_buf[str_idx++] = '\0'; 209 | string_buf = xrealloc(string_buf, str_idx); 210 | yylval.string = string_buf; 211 | 212 | BEGIN(INITIAL); 213 | return TOK_STRING; 214 | } 215 | 216 | \n { 217 | if (parser_mode == PARSE_SYSTEM) { 218 | o_log(LOG_CRIT, "[line %u] Error: Unterminated string constant", 219 | current_line); 220 | } 221 | 222 | free(string_buf); 223 | return -1; 224 | } 225 | 226 | <*>\n { 227 | current_line++; 228 | } 229 | 230 | \\[0-7]{1,3} { 231 | u_int32_t result; 232 | 233 | result = strtoul(yytext + 1, NULL, 8); 234 | 235 | if (result > 0xff) { 236 | if (parser_mode == PARSE_SYSTEM) { 237 | o_log(LOG_CRIT, "[line %u] Bad escape sequence: \"%s\"", 238 | current_line, yytext); 239 | } 240 | 241 | free(string_buf); 242 | return -1; 243 | } 244 | 245 | if (str_idx >= max_slen - 1) { 246 | max_slen += STRING_CHUNK_LEN; 247 | string_buf = xrealloc(string_buf, max_slen); 248 | } 249 | 250 | string_buf[str_idx++] = result; 251 | } 252 | 253 | \\[xX][0-9A-Fa-f]{1,2} { 254 | u_int32_t result; 255 | 256 | result = strtoul(yytext + 2, NULL, 16); 257 | 258 | if (str_idx >= max_slen - 2) { 259 | max_slen += STRING_CHUNK_LEN; 260 | string_buf = xrealloc(string_buf, max_slen); 261 | } 262 | 263 | string_buf[str_idx++] = result; 264 | } 265 | 266 | \\[0-9] { 267 | if (parser_mode == PARSE_SYSTEM) { 268 | o_log(LOG_CRIT, "[line %u] Error: Bad escape sequence: \"%s\"", 269 | current_line, yytext); 270 | } 271 | 272 | free(string_buf); 273 | return -1; 274 | } 275 | 276 | \\. { 277 | if (str_idx >= max_slen - 2) { 278 | max_slen += STRING_CHUNK_LEN; 279 | string_buf = xrealloc(string_buf, max_slen); 280 | } 281 | 282 | string_buf[str_idx++] = get_esc_char(yytext[1]); 283 | } 284 | 285 | [^\\\n\"]+ { 286 | size_t len = yyleng; 287 | char *p = yytext; 288 | 289 | if (str_idx + len >= max_slen - 1) { 290 | max_slen += len + 1; 291 | string_buf = xrealloc(string_buf, max_slen); 292 | } 293 | 294 | while (*p) 295 | string_buf[str_idx++] = *p++; 296 | } 297 | 298 | ([^\n\t "/{}]([^\n\t {}]*))|(\/([^*\n\t {}]+)([^\n\t {}]*)) { 299 | yylval.string = xstrdup(yytext); 300 | return TOK_STRING; 301 | } 302 | 303 | . { 304 | return yytext[0]; 305 | } 306 | 307 | %% 308 | 309 | /* 310 | ** Return the specified escaped character. 311 | */ 312 | 313 | static char get_esc_char(char c) { 314 | switch (c) { 315 | case 'n': 316 | return '\n'; 317 | 318 | case 't': 319 | return '\t'; 320 | 321 | case 'r': 322 | return '\r'; 323 | 324 | case 'f': 325 | return '\f'; 326 | 327 | case 'b': 328 | return '\b'; 329 | 330 | case 'v': 331 | return '\v'; 332 | 333 | case 'a': 334 | return '\a'; 335 | 336 | default: 337 | break; 338 | } 339 | 340 | return c; 341 | } 342 | -------------------------------------------------------------------------------- /src/forward.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** forward.c - oidentd request forwarding. 3 | ** Copyright (c) 1998-2006 Ryan McCabe 4 | ** Copyright (c) 2018 Jan Steffens 5 | ** Copyright (c) 2018-2019 Janik Rabe 6 | ** 7 | ** This program is free software; you can redistribute it and/or modify 8 | ** it under the terms of the GNU General Public License, version 2, 9 | ** as published by the Free Software Foundation. 10 | ** 11 | ** This program is distributed in the hope that it will be useful, 12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | ** GNU General Public License for more details. 15 | ** 16 | ** You should have received a copy of the GNU General Public License 17 | ** along with this program; if not, write to the Free Software 18 | ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 | */ 20 | 21 | #include 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | #include "oidentd.h" 39 | #include "util.h" 40 | #include "missing.h" 41 | #include "inet_util.h" 42 | #include "options.h" 43 | #include "forward.h" 44 | 45 | static sigjmp_buf timebuf; 46 | static int fsock; 47 | static void fwd_alarm(int sig) __noreturn; 48 | 49 | /* 50 | ** Make an Ident request to another machine and return its response, 51 | ** if the request was successful. 52 | */ 53 | 54 | int forward_request(const struct sockaddr_storage *host, 55 | in_port_t port, 56 | in_port_t lport, 57 | in_port_t fport, 58 | char *reply, 59 | size_t len) 60 | { 61 | struct sockaddr_storage addr; 62 | char ipbuf[MAX_IPLEN]; 63 | char user[512]; 64 | char buf[1024]; 65 | 66 | sin_copy(&addr, host); 67 | sin_set_port(htons(port), &addr); 68 | 69 | fsock = socket(addr.ss_family, SOCK_STREAM, 0); 70 | if (fsock == -1) { 71 | debug("socket: %s", strerror(errno)); 72 | return -1; 73 | } 74 | 75 | if (sigsetjmp(timebuf, 1) != 0) { 76 | debug("sigsetjmp: %s", strerror(errno)); 77 | return -1; 78 | } 79 | 80 | signal(SIGALRM, fwd_alarm); 81 | 82 | /* 83 | ** Five seconds should be plenty, seeing as we're forwarding to a machine 84 | ** on a local network. 85 | */ 86 | 87 | alarm(5); 88 | 89 | if (connect(fsock, (struct sockaddr *) &addr, (socklen_t) sin_len(&addr)) != 0) { 90 | get_ip(&addr, ipbuf, sizeof(ipbuf)); 91 | debug("connect to %s:%d: %s", 92 | ipbuf, ntohs(sin_port(&addr)), strerror(errno)); 93 | goto out_fail; 94 | } 95 | 96 | if (sockprintf(fsock, "%d,%d\r\n", lport, fport) < 1) { 97 | debug("write: %s", strerror(errno)); 98 | goto out_fail; 99 | } 100 | 101 | if (!sock_read(fsock, buf, sizeof(buf))) { 102 | debug("read(%d): %s", fsock, strerror(errno)); 103 | goto out_fail; 104 | } 105 | 106 | /* 107 | ** Don't time out once we've finished processing the request. 108 | */ 109 | 110 | alarm(0); 111 | close(fsock); 112 | 113 | if (sscanf(buf, "%*d , %*d : USERID :%*[^:]:%511s", user) != 1) { 114 | char *p = strchr(buf, '\r'); 115 | 116 | if (p) 117 | *p = '\0'; 118 | 119 | get_ip(&addr, ipbuf, sizeof(ipbuf)); 120 | debug("[%s] Remote response: \"%s\"", ipbuf, buf); 121 | return -1; 122 | } 123 | 124 | xstrncpy(reply, user, len); 125 | return 0; 126 | 127 | out_fail: 128 | alarm(0); 129 | close(fsock); 130 | return -1; 131 | } 132 | 133 | /* 134 | ** Handle the timeout of a forward request. 135 | */ 136 | 137 | static void fwd_alarm(int sig) { 138 | o_log(LOG_INFO, "Forward timed out"); 139 | close(fsock); 140 | siglongjmp(timebuf, sig); 141 | } 142 | 143 | -------------------------------------------------------------------------------- /src/forward.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** forward.h - oidentd request forwarding. 3 | ** Copyright (c) 1998-2006 Ryan McCabe 4 | ** Copyright (c) 2018 Janik Rabe 5 | ** Copyright (c) 2018 Jan Steffens 6 | ** 7 | ** This program is free software; you can redistribute it and/or modify 8 | ** it under the terms of the GNU General Public License, version 2, 9 | ** as published by the Free Software Foundation. 10 | ** 11 | ** This program is distributed in the hope that it will be useful, 12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | ** GNU General Public License for more details. 15 | ** 16 | ** You should have received a copy of the GNU General Public License 17 | ** along with this program; if not, write to the Free Software 18 | ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 | */ 20 | 21 | #ifndef __OIDENTD_FORWARD_H 22 | #define __OIDENTD_FORWARD_H 23 | 24 | int forward_request(const struct sockaddr_storage *host, 25 | in_port_t port, 26 | in_port_t lport, 27 | in_port_t fport, 28 | char *reply, 29 | size_t len); 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /src/inet_util.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** inet_util.c - oidentd network utility functions. 3 | ** Copyright (c) 2001-2006 Ryan McCabe 4 | ** Copyright (c) 2018-2019 Janik Rabe 5 | ** 6 | ** This program is free software; you can redistribute it and/or modify 7 | ** it under the terms of the GNU General Public License, version 2, 8 | ** as published by the Free Software Foundation. 9 | ** 10 | ** This program is distributed in the hope that it will be useful, 11 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ** GNU General Public License for more details. 14 | ** 15 | ** You should have received a copy of the GNU General Public License 16 | ** along with this program; if not, write to the Free Software 17 | ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #define _GNU_SOURCE 21 | #include 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | #include "oidentd.h" 41 | #include "util.h" 42 | #include "missing.h" 43 | #include "inet_util.h" 44 | #include "options.h" 45 | 46 | static int setup_bind(const struct addrinfo *ai, in_port_t listen_port); 47 | 48 | static int setup_bind(const struct addrinfo *ai, in_port_t listen_port) { 49 | int ret; 50 | const int one = 1; 51 | int listenfd; 52 | 53 | listenfd = socket(ai->ai_family, SOCK_STREAM, 0); 54 | if (listenfd == -1) { 55 | debug("socket: %s", strerror(errno)); 56 | return -1; 57 | } 58 | 59 | switch (ai->ai_family) { 60 | #if WANT_IPV6 61 | case AF_INET6: 62 | SIN6(ai->ai_addr)->sin6_port = listen_port; 63 | if (setsockopt(listenfd, IPPROTO_IPV6, IPV6_V6ONLY, &one, 64 | sizeof(one)) != 0) { 65 | debug("setsockopt IPV6_V6ONLY: %s", strerror(errno)); 66 | return -1; 67 | } 68 | break; 69 | #endif 70 | 71 | case AF_INET: 72 | SIN4(ai->ai_addr)->sin_port = listen_port; 73 | break; 74 | default: 75 | debug("address family %d not supported", ai->ai_family); 76 | return -1; 77 | } 78 | 79 | ret = setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); 80 | if (ret != 0) { 81 | debug("setsockopt: %s", strerror(errno)); 82 | return -1; 83 | } 84 | 85 | ret = bind(listenfd, ai->ai_addr, ai->ai_addrlen); 86 | if (ret != 0) { 87 | debug("bind: %s", strerror(errno)); 88 | return -1; 89 | } 90 | 91 | if (listen(listenfd, SOMAXCONN) != 0) { 92 | debug("listen: %s", strerror(errno)); 93 | return -1; 94 | } 95 | 96 | return listenfd; 97 | } 98 | 99 | /* 100 | ** Setup the listening socket(s). 101 | */ 102 | 103 | int *setup_listen(struct sockaddr_storage **listen_addr, in_port_t listen_port) { 104 | int ret; 105 | int *bound_fds = NULL; 106 | char listen_port_str[64]; 107 | struct addrinfo hints, *res, *cur; 108 | unsigned int naddr = 0; 109 | 110 | if (listen_addr) { 111 | do { 112 | cur = xcalloc(1, sizeof(struct addrinfo)); 113 | 114 | cur->ai_family = listen_addr[naddr]->ss_family; 115 | 116 | switch (cur->ai_family) { 117 | #if WANT_IPV6 118 | case AF_INET6: 119 | cur->ai_addrlen = sizeof(struct sockaddr_in6); 120 | break; 121 | #endif 122 | case AF_INET: 123 | cur->ai_addrlen = sizeof(struct sockaddr_in); 124 | break; 125 | default: 126 | debug("address family %d not supported", cur->ai_family); 127 | free(cur); 128 | free(listen_addr[naddr]); 129 | return NULL; 130 | } 131 | 132 | cur->ai_addr = xmalloc(cur->ai_addrlen); 133 | memcpy(cur->ai_addr, listen_addr[naddr], cur->ai_addrlen); 134 | 135 | ret = setup_bind(cur, listen_port); 136 | free(cur->ai_addr); 137 | free(cur); 138 | free(listen_addr[naddr]); 139 | 140 | if (ret == -1) 141 | return NULL; 142 | 143 | bound_fds = xrealloc(bound_fds, (naddr + 2) * sizeof(int)); 144 | bound_fds[naddr] = ret; 145 | bound_fds[++naddr] = -1; 146 | } while (listen_addr[naddr]); 147 | 148 | return bound_fds; 149 | } 150 | 151 | memset(&hints, 0, sizeof(hints)); 152 | hints.ai_family = PF_UNSPEC; 153 | hints.ai_flags = AI_PASSIVE; 154 | hints.ai_socktype = SOCK_STREAM; 155 | 156 | snprintf(listen_port_str, sizeof(listen_port_str), "%d", listen_port); 157 | 158 | ret = getaddrinfo(NULL, listen_port_str, &hints, &res); 159 | if (ret != 0) { 160 | debug("getaddrinfo: %s", gai_strerror(ret)); 161 | return NULL; 162 | } 163 | 164 | cur = res; 165 | if (cur) { 166 | size_t bound_addr = 0; 167 | size_t fdlen = 4; 168 | 169 | bound_fds = xmalloc(fdlen * sizeof(int)); 170 | 171 | do { 172 | ret = setup_bind(cur, listen_port); 173 | if (ret == -1) 174 | goto bind_next; 175 | 176 | if (bound_addr >= fdlen - 1) { 177 | fdlen += 4; 178 | bound_fds = xrealloc(bound_fds, fdlen * sizeof(int)); 179 | } 180 | 181 | bound_fds[bound_addr++] = ret; 182 | 183 | bind_next: 184 | cur = cur->ai_next; 185 | } while (cur); 186 | 187 | bound_fds[bound_addr++] = -1; 188 | bound_fds = xrealloc(bound_fds, bound_addr * sizeof(int)); 189 | freeaddrinfo(res); 190 | } else 191 | return NULL; 192 | 193 | return bound_fds; 194 | } 195 | 196 | /* 197 | ** Read at most "len" bytes from socket "sock" into "buf". 198 | */ 199 | 200 | ssize_t sock_read(int sock, char *buf, ssize_t len) { 201 | char c; 202 | ssize_t i; 203 | ssize_t ret; 204 | 205 | if (!buf) 206 | return 0; 207 | 208 | for (i = 1; i < len; ++i) { 209 | top: 210 | ret = read(sock, &c, 1); 211 | if (ret == 1) { 212 | *buf++ = c; 213 | 214 | if (c == '\n') 215 | break; 216 | } else if (ret == 0) { 217 | if (i == 1) 218 | return 0; 219 | 220 | break; 221 | } else if (errno == EINTR) { 222 | goto top; 223 | } else { 224 | return 0; 225 | } 226 | } 227 | 228 | *buf = '\0'; 229 | return i; 230 | } 231 | 232 | /* 233 | ** Write to a socket, deal with interrupted and incomplete writes. Returns 234 | ** the number of characters written to the socket on success, -1 on failure. 235 | */ 236 | 237 | ssize_t sock_write(int sock, void *buf, ssize_t len) { 238 | ssize_t written = 0; 239 | 240 | while (len > 0) { 241 | ssize_t n; 242 | 243 | n = write(sock, buf, (size_t) len); 244 | if (n == -1) { 245 | if (errno == EINTR) 246 | continue; 247 | return -1; 248 | } 249 | 250 | written += n; 251 | len -= n; 252 | buf = (char *) buf + n; 253 | } 254 | 255 | return written; 256 | } 257 | 258 | /* 259 | ** printf-like function that writes to sockets. 260 | */ 261 | 262 | ssize_t sockprintf(int fd, const char *fmt, ...) { 263 | va_list ap; 264 | char *buf; 265 | ssize_t ret; 266 | 267 | va_start(ap, fmt); 268 | ret = vasprintf(&buf, fmt, ap); 269 | va_end(ap); 270 | 271 | if (ret == -1) 272 | return -1; 273 | 274 | ret = sock_write(fd, buf, ret); 275 | free(buf); 276 | 277 | return ret; 278 | } 279 | 280 | /* 281 | ** Return the canonical hostname of the given address. 282 | */ 283 | 284 | inline int get_hostname(struct sockaddr_storage *addr, 285 | char *hostbuf, 286 | socklen_t len) 287 | { 288 | int ret; 289 | 290 | ret = getnameinfo((struct sockaddr *) addr, sizeof(struct sockaddr_storage), 291 | hostbuf, len, NULL, 0, NI_NAMEREQD); 292 | 293 | return ret; 294 | } 295 | 296 | /* 297 | ** Get the port associated with a TCP service name. 298 | */ 299 | 300 | int get_port(const char *name, in_port_t *port) { 301 | struct servent *servent; 302 | 303 | servent = getservbyname(name, "tcp"); 304 | if (servent) { 305 | *port = ntohs(servent->s_port); 306 | } else { 307 | char *end; 308 | long temp_port; 309 | 310 | temp_port = strtol(name, &end, 10); 311 | 312 | if (*end != '\0') 313 | return -1; 314 | 315 | if (!VALID_PORT(temp_port)) 316 | return -1; 317 | 318 | *port = (in_port_t) temp_port; 319 | } 320 | 321 | return 0; 322 | } 323 | 324 | /* 325 | ** Return a network byte ordered IPv4 or IPv6 address. 326 | */ 327 | 328 | int get_addr(const char *hostname, struct sockaddr_storage *addr) { 329 | struct addrinfo *res; 330 | size_t len; 331 | 332 | if (getaddrinfo(hostname, NULL, NULL, &res) != 0) 333 | return -1; 334 | 335 | switch (res->ai_addr->sa_family) { 336 | case AF_INET: 337 | len = sizeof(struct sockaddr_in); 338 | break; 339 | #if WANT_IPV6 340 | case AF_INET6: 341 | len = sizeof(struct sockaddr_in6); 342 | break; 343 | #endif 344 | default: 345 | goto out_fail; 346 | } 347 | 348 | if (len < (size_t) res->ai_addrlen) 349 | goto out_fail; 350 | 351 | memcpy(addr, res->ai_addr, res->ai_addrlen); 352 | freeaddrinfo(res); 353 | 354 | return 0; 355 | 356 | out_fail: 357 | freeaddrinfo(res); 358 | return -1; 359 | } 360 | 361 | /* 362 | ** Returns the address set in the appropriate 363 | ** sockaddr struct. 364 | */ 365 | 366 | inline void *sin_addr(struct sockaddr_storage *ss) { 367 | #if WANT_IPV6 368 | if (ss->ss_family == AF_INET6) 369 | return &SIN6(ss)->sin6_addr; 370 | #endif 371 | 372 | return &SIN4(ss)->sin_addr; 373 | } 374 | 375 | /* 376 | ** Return string IPv4 or IPv6 address. 377 | */ 378 | 379 | inline void get_ip( struct sockaddr_storage *ss, 380 | char *buf, 381 | socklen_t len) 382 | { 383 | inet_ntop(ss->ss_family, sin_addr(ss), buf, len); 384 | } 385 | 386 | /* 387 | ** Returns true if the two in4 addresses are equal, false 388 | ** if they aren't. 389 | */ 390 | 391 | inline bool sin4_equal( struct sockaddr_storage *ss1, 392 | struct sockaddr_storage *ss2) 393 | { 394 | return (SIN4(ss1)->sin_addr.s_addr == SIN4(ss2)->sin_addr.s_addr); 395 | } 396 | 397 | /* 398 | ** Setup "ss" as an IPv4 sockaddr struct with the address specified by 399 | ** "addr" 400 | */ 401 | 402 | void sin_setv4(in_addr_t addr, struct sockaddr_storage *ss) { 403 | memset(ss, 0, sizeof(struct sockaddr_storage)); 404 | ss->ss_family = AF_INET; 405 | memcpy(&SIN4(ss)->sin_addr, &addr, sizeof(addr)); 406 | } 407 | 408 | #if WANT_IPV6 409 | 410 | inline bool sin6_equal( struct sockaddr_storage *ss1, 411 | struct sockaddr_storage *ss2) 412 | { 413 | return IN6_ARE_ADDR_EQUAL(&SIN6(ss1)->sin6_addr, &SIN6(ss2)->sin6_addr); 414 | } 415 | 416 | /* 417 | ** Setup "ss" as an IPv6 sockaddr struct with the address specified by 418 | ** "sin6" 419 | */ 420 | 421 | void sin_setv6(struct in6_addr *sin6, struct sockaddr_storage *ss) { 422 | memset(ss, 0, sizeof(struct sockaddr_storage)); 423 | ss->ss_family = AF_INET6; 424 | memcpy(&SIN6(ss)->sin6_addr, sin6, sizeof(struct in6_addr)); 425 | } 426 | 427 | #endif 428 | 429 | /* 430 | ** Returns the length of the sockaddr struct. 431 | */ 432 | 433 | inline size_t sin_len(const struct sockaddr_storage *ss __notused) { 434 | #if WANT_IPV6 435 | if (ss->ss_family == AF_INET6) 436 | return sizeof(struct sockaddr_in6); 437 | #endif 438 | 439 | return sizeof(struct sockaddr_in); 440 | } 441 | 442 | /* 443 | ** Returns the length of the address portion of the sockaddr 444 | ** structure. 445 | */ 446 | 447 | inline size_t sin_addr_len(const struct sockaddr_storage *ss __notused) { 448 | #if WANT_IPV6 449 | if (ss->ss_family == AF_INET6) 450 | return sizeof(struct in6_addr); 451 | #endif 452 | 453 | return sizeof(struct in_addr); 454 | } 455 | 456 | /* 457 | ** Copies a sockaddr struct. 458 | */ 459 | 460 | inline void sin_copy( struct sockaddr_storage *ss1, 461 | const struct sockaddr_storage *ss2) 462 | { 463 | memset(ss1, 0, sizeof(struct sockaddr_storage)); 464 | memcpy(ss1, ss2, sin_len(ss2)); 465 | } 466 | 467 | /* 468 | ** Returns the port set in the sockaddr struct. 469 | */ 470 | 471 | inline in_port_t sin_port(const struct sockaddr_storage *ss) { 472 | #if WANT_IPV6 473 | if (ss->ss_family == AF_INET6) 474 | return SIN6(ss)->sin6_port; 475 | #endif 476 | 477 | return SIN4(ss)->sin_port; 478 | } 479 | 480 | /* 481 | ** Sets the port for the approprite socket family. 482 | */ 483 | 484 | inline void sin_set_port(in_port_t port, struct sockaddr_storage *ss) { 485 | #if WANT_IPV6 486 | if (ss->ss_family == AF_INET6) 487 | SIN6(ss)->sin6_port = port; 488 | #endif 489 | 490 | SIN4(ss)->sin_port = port; 491 | } 492 | 493 | /* 494 | ** Checks whether two addresses are equal. 495 | */ 496 | 497 | inline bool sin_equal( struct sockaddr_storage *ss1, 498 | struct sockaddr_storage *ss2) 499 | { 500 | #if WANT_IPV6 501 | if (ss1->ss_family == AF_INET6) 502 | return sin6_equal(ss1, ss2); 503 | #endif 504 | 505 | return sin4_equal(ss1, ss2); 506 | } 507 | 508 | /* 509 | ** Converts an IPv6-mapped IPv4 address to an IPv4 address. 510 | */ 511 | 512 | inline void sin_extractv4(void *in6, struct in_addr *in4) { 513 | /* XXX - Is there a cleaner portable way to do this? */ 514 | memcpy(in4, ((char *) in6) + 12, sizeof(struct in_addr)); 515 | } 516 | 517 | /* 518 | ** Converts an IPv4 address to an IPv6-mapped IPv4 address. 519 | */ 520 | 521 | inline void sin_mapv4to6(void *in4, struct in6_addr *in6) { 522 | /* XXX - Is there a cleaner portable way to do this? */ 523 | char *in6_ptr = (char *) in6; 524 | memset(in6_ptr, 0, 10); 525 | memset(in6_ptr + 10, 0xFF, 2); 526 | memcpy(in6_ptr + 12, in4, sizeof(struct in_addr)); 527 | } 528 | -------------------------------------------------------------------------------- /src/inet_util.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** inet_util.h - oidentd network utility functions. 3 | ** Copyright (c) 2001-2006 Ryan McCabe 4 | ** Copyright (c) 2018 Janik Rabe 5 | ** 6 | ** This program is free software; you can redistribute it and/or modify 7 | ** it under the terms of the GNU General Public License, version 2, 8 | ** as published by the Free Software Foundation. 9 | ** 10 | ** This program is distributed in the hope that it will be useful, 11 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ** GNU General Public License for more details. 14 | ** 15 | ** You should have received a copy of the GNU General Public License 16 | ** along with this program; if not, write to the Free Software 17 | ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #ifndef __OIDENTD_INET_UTIL_H 21 | #define __OIDENTD_INET_UTIL_H 22 | 23 | #define SIN4(x) ((struct sockaddr_in *) (x)) 24 | #define SIN6(x) ((struct sockaddr_in6 *) (x)) 25 | 26 | int *setup_listen(struct sockaddr_storage **listen_addr, in_port_t listen_port); 27 | 28 | int get_port(const char *name, in_port_t *port); 29 | int get_addr(const char *const hostname, struct sockaddr_storage *g_addr); 30 | void get_ip(struct sockaddr_storage *ss, char *buf, socklen_t len); 31 | int get_hostname(struct sockaddr_storage *addr, char *hostname, socklen_t len); 32 | 33 | ssize_t sockprintf(int fd, const char *fmt, ...) __format((printf, 2, 3)); 34 | ssize_t sock_read(int fd, char *srbuf, ssize_t len); 35 | ssize_t sock_write(int sock, void *buf, ssize_t len); 36 | 37 | #ifndef HAVE_INET_ATON 38 | int inet_aton(const char *cp, struct in_addr *addr); 39 | #endif 40 | 41 | #ifndef HAVE_INET_NTOP 42 | const char *inet_ntop(int af, const void *src, char *dst, size_t len); 43 | #endif 44 | 45 | #if WANT_IPV6 46 | void sin_setv6(struct in6_addr *sin6, struct sockaddr_storage *ss); 47 | #endif 48 | 49 | void sin_setv4(in_addr_t addr, struct sockaddr_storage *ss); 50 | void sin_extractv4(void *sin6, struct in_addr *sin4); 51 | void sin_mapv4to6(void *in4, struct in6_addr *in6); 52 | size_t sin_len(const struct sockaddr_storage *ss); 53 | size_t sin_addr_len(const struct sockaddr_storage *ss); 54 | void sin_copy(struct sockaddr_storage *ss1, const struct sockaddr_storage *ss2); 55 | void *sin_addr(struct sockaddr_storage *ss); 56 | in_port_t sin_port(const struct sockaddr_storage *ss); 57 | void sin_set_port(in_port_t port, struct sockaddr_storage *ss); 58 | bool sin4_equal(struct sockaddr_storage *ss1, struct sockaddr_storage *ss2); 59 | bool sin6_equal(struct sockaddr_storage *ss1, struct sockaddr_storage *ss2); 60 | bool sin_equal(struct sockaddr_storage *ss1, struct sockaddr_storage *ss2); 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /src/kernel/dflybsd1.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** dflybsd1.c - Ident lookup routines for DragonFly BSD >= 1 3 | ** Copyright (c) 2000-2006 Ryan McCabe 4 | ** Copyright (c) 2018-2019 Janik Rabe 5 | ** 6 | ** This program is free software; you can redistribute it and/or modify 7 | ** it under the terms of the GNU General Public License, version 2, 8 | ** as published by the Free Software Foundation. 9 | ** 10 | ** This program is distributed in the hope that it will be useful, 11 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ** GNU General Public License for more details. 14 | ** 15 | ** You should have received a copy of the GNU General Public License 16 | ** along with this program; if not, write to the Free Software 17 | ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #define _GNU_SOURCE 21 | #define _WANT_UCRED 22 | 23 | #include 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | 47 | #include "oidentd.h" 48 | #include "util.h" 49 | #include "inet_util.h" 50 | #include "missing.h" 51 | #include "options.h" 52 | 53 | /* 54 | ** System-dependent initialization; called only once. 55 | ** Called before privileges are dropped. 56 | ** Returns non-zero on failure. 57 | */ 58 | 59 | int core_init(void) { 60 | return 0; 61 | } 62 | 63 | extern struct sockaddr_storage proxy; 64 | 65 | /* 66 | ** Returns the UID of the owner of an IPv4 connection, 67 | ** or MISSING_UID on failure. 68 | */ 69 | 70 | uid_t get_user4( in_port_t lport, 71 | in_port_t fport, 72 | struct sockaddr_storage *laddr, 73 | struct sockaddr_storage *faddr) 74 | { 75 | struct ucred ucred; 76 | struct sockaddr_in sin4[2]; 77 | size_t len; 78 | int ret; 79 | 80 | len = sizeof(struct ucred); 81 | 82 | memset(sin4, 0, sizeof(sin4)); 83 | 84 | sin4[0].sin_len = sizeof(struct sockaddr_in); 85 | sin4[0].sin_family = AF_INET; 86 | sin4[0].sin_port = lport; 87 | sin4[0].sin_addr.s_addr = SIN4(laddr)->sin_addr.s_addr; 88 | 89 | sin4[1].sin_len = sizeof(struct sockaddr_in); 90 | sin4[1].sin_family = AF_INET; 91 | sin4[1].sin_port = fport; 92 | 93 | if (!opt_enabled(PROXY) || !sin_equal(faddr, &proxy)) 94 | sin4[1].sin_addr.s_addr = SIN4(faddr)->sin_addr.s_addr; 95 | 96 | ret = sysctlbyname("net.inet.tcp.getcred", 97 | &ucred, &len, sin4, sizeof(sin4)); 98 | 99 | if (ret == -1) { 100 | debug("sysctlbyname: %s", strerror(errno)); 101 | return MISSING_UID; 102 | } 103 | 104 | return ucred.cr_uid; 105 | } 106 | 107 | #if WANT_IPV6 108 | 109 | /* 110 | ** Returns the UID of the owner of an IPv6 connection, 111 | ** or MISSING_UID on failure. 112 | */ 113 | 114 | uid_t get_user6( in_port_t lport, 115 | in_port_t fport, 116 | struct sockaddr_storage *laddr, 117 | struct sockaddr_storage *faddr) 118 | { 119 | struct ucred ucred; 120 | struct sockaddr_in6 sin6[2]; 121 | size_t len; 122 | int ret; 123 | 124 | len = sizeof(struct ucred); 125 | 126 | memset(sin6, 0, sizeof(sin6)); 127 | 128 | sin6[0].sin6_len = sizeof(struct sockaddr_in6); 129 | sin6[0].sin6_family = AF_INET6; 130 | sin6[0].sin6_port = lport; 131 | memcpy(&sin6[0].sin6_addr, &SIN6(laddr)->sin6_addr, 132 | sizeof(sin6[0].sin6_addr)); 133 | 134 | sin6[1].sin6_len = sizeof(struct sockaddr_in6); 135 | sin6[1].sin6_family = AF_INET6; 136 | sin6[1].sin6_port = fport; 137 | memcpy(&sin6[1].sin6_addr, &SIN6(faddr)->sin6_addr, 138 | sizeof(sin6[1].sin6_addr)); 139 | 140 | ret = sysctlbyname("net.inet6.tcp6.getcred", 141 | &ucred, &len, sin6, sizeof(sin6)); 142 | 143 | if (ret == -1) { 144 | debug("sysctlbyname: %s", strerror(errno)); 145 | return MISSING_UID; 146 | } 147 | 148 | return ucred.cr_uid; 149 | } 150 | 151 | #endif 152 | 153 | /* 154 | ** Open the kernel memory device. 155 | ** Return 0 on success, or -1 with errno set. 156 | ** 157 | ** No kmem access required; nothing to do. 158 | */ 159 | 160 | int k_open(void) { 161 | return 0; 162 | } 163 | -------------------------------------------------------------------------------- /src/kernel/freebsd5.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** freebsd5.c - Ident lookup routines for FreeBSD >= 5 3 | ** Copyright (c) 2000-2006 Ryan McCabe 4 | ** Copyright (c) 2018-2019 Janik Rabe 5 | ** 6 | ** This program is free software; you can redistribute it and/or modify 7 | ** it under the terms of the GNU General Public License, version 2, 8 | ** as published by the Free Software Foundation. 9 | ** 10 | ** This program is distributed in the hope that it will be useful, 11 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ** GNU General Public License for more details. 14 | ** 15 | ** You should have received a copy of the GNU General Public License 16 | ** along with this program; if not, write to the Free Software 17 | ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #include 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | 44 | #include "oidentd.h" 45 | #include "util.h" 46 | #include "inet_util.h" 47 | #include "missing.h" 48 | #include "options.h" 49 | 50 | /* 51 | ** System-dependent initialization; called only once. 52 | ** Called before privileges are dropped. 53 | ** Returns non-zero on failure. 54 | */ 55 | 56 | int core_init(void) { 57 | return 0; 58 | } 59 | 60 | extern struct sockaddr_storage proxy; 61 | 62 | /* 63 | ** Returns the UID of the owner of an IPv4 connection, 64 | ** or MISSING_UID on failure. 65 | */ 66 | 67 | uid_t get_user4( in_port_t lport, 68 | in_port_t fport, 69 | struct sockaddr_storage *laddr, 70 | struct sockaddr_storage *faddr) 71 | { 72 | struct xucred xuc; 73 | struct sockaddr_in sin4[2]; 74 | size_t len; 75 | int ret; 76 | 77 | len = sizeof(xuc); 78 | 79 | memset(sin4, 0, sizeof(sin4)); 80 | 81 | sin4[0].sin_len = sizeof(struct sockaddr_in); 82 | sin4[0].sin_family = AF_INET; 83 | sin4[0].sin_port = lport; 84 | sin4[0].sin_addr.s_addr = SIN4(laddr)->sin_addr.s_addr; 85 | 86 | sin4[1].sin_len = sizeof(struct sockaddr_in); 87 | sin4[1].sin_family = AF_INET; 88 | sin4[1].sin_port = fport; 89 | 90 | if (!opt_enabled(PROXY) || !sin_equal(faddr, &proxy)) 91 | sin4[1].sin_addr.s_addr = SIN4(faddr)->sin_addr.s_addr; 92 | 93 | ret = sysctlbyname("net.inet.tcp.getcred", 94 | &xuc, &len, sin4, sizeof(sin4)); 95 | 96 | if (ret == -1) { 97 | debug("sysctlbyname: %s", strerror(errno)); 98 | return MISSING_UID; 99 | } 100 | 101 | if (xuc.cr_version != XUCRED_VERSION) { 102 | debug("kernel is using xucred version %u, expected %u", 103 | xuc.cr_version, XUCRED_VERSION); 104 | return MISSING_UID; 105 | } 106 | 107 | return xuc.cr_uid; 108 | } 109 | 110 | #if WANT_IPV6 111 | 112 | /* 113 | ** Returns the UID of the owner of an IPv6 connection, 114 | ** or MISSING_UID on failure. 115 | */ 116 | 117 | uid_t get_user6( in_port_t lport, 118 | in_port_t fport, 119 | struct sockaddr_storage *laddr, 120 | struct sockaddr_storage *faddr) 121 | { 122 | struct xucred xuc; 123 | struct sockaddr_in6 sin6[2]; 124 | size_t len; 125 | int ret; 126 | 127 | len = sizeof(xuc); 128 | 129 | memset(sin6, 0, sizeof(sin6)); 130 | 131 | sin6[0].sin6_len = sizeof(struct sockaddr_in6); 132 | sin6[0].sin6_family = AF_INET6; 133 | sin6[0].sin6_port = lport; 134 | memcpy(&sin6[0].sin6_addr, &SIN6(laddr)->sin6_addr, 135 | sizeof(sin6[0].sin6_addr)); 136 | 137 | sin6[1].sin6_len = sizeof(struct sockaddr_in6); 138 | sin6[1].sin6_family = AF_INET6; 139 | sin6[1].sin6_port = fport; 140 | memcpy(&sin6[1].sin6_addr, &SIN6(faddr)->sin6_addr, 141 | sizeof(sin6[1].sin6_addr)); 142 | 143 | ret = sysctlbyname("net.inet6.tcp6.getcred", 144 | &xuc, &len, sin6, sizeof(sin6)); 145 | 146 | if (ret == -1) { 147 | debug("sysctlbyname: %s", strerror(errno)); 148 | return MISSING_UID; 149 | } 150 | 151 | if (xuc.cr_version != XUCRED_VERSION) { 152 | debug("kernel is using xucred version %u, expected %u", 153 | xuc.cr_version, XUCRED_VERSION); 154 | return MISSING_UID; 155 | } 156 | 157 | return xuc.cr_uid; 158 | } 159 | 160 | #endif 161 | 162 | /* 163 | ** Open the kernel memory device. 164 | ** Return 0 on success, or -1 with errno set. 165 | ** 166 | ** No kmem access required; nothing to do. 167 | */ 168 | 169 | int k_open(void) { 170 | return 0; 171 | } 172 | -------------------------------------------------------------------------------- /src/kernel/netbsd5.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** netbsd5.c - Ident lookup routines for >= NetBSD 5 3 | ** Copyright (c) 2018-2019 Janik Rabe 4 | ** 5 | ** This program is free software; you can redistribute it and/or modify 6 | ** it under the terms of the GNU General Public License, version 2, 7 | ** as published by the Free Software Foundation. 8 | ** 9 | ** This program is distributed in the hope that it will be useful, 10 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | ** GNU General Public License for more details. 13 | ** 14 | ** You should have received a copy of the GNU General Public License 15 | ** along with this program; if not, write to the Free Software 16 | ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 | */ 18 | 19 | #include 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | #if WANT_IPV6 41 | # include 42 | #endif 43 | 44 | #if MASQ_SUPPORT 45 | # include 46 | # include 47 | #endif 48 | 49 | #include "oidentd.h" 50 | #include "util.h" 51 | #include "inet_util.h" 52 | #include "missing.h" 53 | #include "masq.h" 54 | #include "options.h" 55 | 56 | /* 57 | ** System-dependent initialization; called only once. 58 | ** Called before privileges are dropped. 59 | ** Returns non-zero on failure. 60 | */ 61 | 62 | int core_init(void) { 63 | return 0; 64 | } 65 | 66 | /* 67 | ** Open the kernel memory device. 68 | ** Return 0 on success, or -1 with errno set. 69 | ** 70 | ** No kmem access required; nothing to do. 71 | */ 72 | 73 | int k_open(void) { 74 | return 0; 75 | } 76 | 77 | /* 78 | ** Returns the UID of the owner of an IPv4 connection, 79 | ** or MISSING_UID on failure. 80 | */ 81 | 82 | uid_t get_user4( in_port_t lport, 83 | in_port_t fport, 84 | struct sockaddr_storage *laddr, 85 | struct sockaddr_storage *faddr) 86 | { 87 | int mib[] = { CTL_NET, PF_INET, IPPROTO_TCP, TCPCTL_IDENT }; 88 | struct sockaddr_storage ss[2]; 89 | uid_t uid = MISSING_UID; 90 | size_t uidlen; 91 | size_t sslen; 92 | int error; 93 | 94 | memcpy(&ss[0], faddr, sizeof(ss[0])); 95 | memcpy(&ss[1], laddr, sizeof(ss[1])); 96 | SIN4(&ss[0])->sin_port = fport; 97 | SIN4(&ss[1])->sin_port = lport; 98 | uidlen = sizeof(uid); 99 | sslen = sizeof(ss); 100 | error = sysctl(mib, sizeof(mib) / sizeof(int), &uid, &uidlen, ss, sslen); 101 | 102 | if (error == 0 && uid != MISSING_UID) 103 | return uid; 104 | 105 | if (error == -1) 106 | debug("sysctl: %s", strerror(errno)); 107 | 108 | return MISSING_UID; 109 | } 110 | 111 | #if WANT_IPV6 112 | 113 | /* 114 | ** Returns the UID of the owner of an IPv6 connection, 115 | ** or MISSING_UID on failure. 116 | */ 117 | 118 | uid_t get_user6( in_port_t lport, 119 | in_port_t fport, 120 | struct sockaddr_storage *laddr, 121 | struct sockaddr_storage *faddr) 122 | { 123 | int mib[] = { CTL_NET, PF_INET6, IPPROTO_TCP, TCPCTL_IDENT }; 124 | struct sockaddr_storage ss[2]; 125 | uid_t uid = MISSING_UID; 126 | size_t uidlen; 127 | size_t sslen; 128 | int error; 129 | 130 | memcpy(&ss[0], faddr, sizeof(ss[0])); 131 | memcpy(&ss[1], laddr, sizeof(ss[1])); 132 | SIN6(&ss[0])->sin6_port = fport; 133 | SIN6(&ss[1])->sin6_port = lport; 134 | uidlen = sizeof(uid); 135 | sslen = sizeof(ss); 136 | error = sysctl(mib, sizeof(mib) / sizeof(int), &uid, &uidlen, ss, sslen); 137 | 138 | if (error == 0 && uid != MISSING_UID) 139 | return uid; 140 | 141 | if (error == -1) 142 | debug("sysctl: %s", strerror(errno)); 143 | 144 | return MISSING_UID; 145 | } 146 | 147 | #endif 148 | -------------------------------------------------------------------------------- /src/kernel/openbsd30.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** openbsd30.c - Low level kernel access functions for OpenBSD 3.0 and greater 3 | ** Copyright (c) 2001-2006 Ryan McCabe 4 | ** Copyright (c) 2018-2019 Janik Rabe 5 | ** 6 | ** This program is free software; you can redistribute it and/or modify 7 | ** it under the terms of the GNU General Public License, version 2, 8 | ** as published by the Free Software Foundation. 9 | ** 10 | ** This program is distributed in the hope that it will be useful, 11 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ** GNU General Public License for more details. 14 | ** 15 | ** You should have received a copy of the GNU General Public License 16 | ** along with this program; if not, write to the Free Software 17 | ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | ** 19 | ** PF support by Kamil Andrusz 20 | */ 21 | 22 | #include 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | 45 | #if MASQ_SUPPORT 46 | # include 47 | # include 48 | # include 49 | # include 50 | #endif 51 | 52 | #include "oidentd.h" 53 | #include "util.h" 54 | #include "inet_util.h" 55 | #include "missing.h" 56 | #include "masq.h" 57 | #include "options.h" 58 | 59 | #define PF_DEVICE "/dev/pf" 60 | 61 | extern struct sockaddr_storage proxy; 62 | 63 | /* 64 | ** System-dependent initialization; called only once. 65 | ** Called before privileges are dropped. 66 | ** Returns non-zero on failure. 67 | */ 68 | 69 | int core_init(void) { 70 | return 0; 71 | } 72 | 73 | /* 74 | ** Returns the UID of the owner of an IPv4 connection, 75 | ** or MISSING_UID on failure. 76 | */ 77 | 78 | uid_t get_user4( in_port_t lport, 79 | in_port_t fport, 80 | struct sockaddr_storage *laddr, 81 | struct sockaddr_storage *faddr) 82 | { 83 | struct tcp_ident_mapping tir; 84 | struct sockaddr_in *fin, *lin; 85 | int mib[] = { CTL_NET, PF_INET, IPPROTO_TCP, TCPCTL_IDENT }; 86 | int error; 87 | size_t i; 88 | 89 | memset(&tir, 0, sizeof(tir)); 90 | 91 | tir.faddr.ss_family = AF_INET; 92 | tir.faddr.ss_len = sizeof(struct sockaddr); 93 | fin = (struct sockaddr_in *) &tir.faddr; 94 | fin->sin_port = fport; 95 | 96 | if (!opt_enabled(PROXY) || !sin_equal(faddr, &proxy)) 97 | memcpy(&fin->sin_addr, &SIN4(faddr)->sin_addr, sizeof(struct in_addr)); 98 | 99 | tir.laddr.ss_family = AF_INET; 100 | tir.laddr.ss_len = sizeof(struct sockaddr); 101 | lin = (struct sockaddr_in *) &tir.laddr; 102 | lin->sin_port = lport; 103 | memcpy(&lin->sin_addr, &SIN4(laddr)->sin_addr, sizeof(struct in_addr)); 104 | 105 | i = sizeof(tir); 106 | 107 | error = sysctl(mib, sizeof(mib) / sizeof(int), &tir, &i, NULL, 0); 108 | 109 | if (error == 0 && tir.ruid != -1) 110 | return tir.ruid; 111 | 112 | if (error == -1) 113 | debug("sysctl: %s", strerror(errno)); 114 | 115 | return MISSING_UID; 116 | } 117 | 118 | #if MASQ_SUPPORT 119 | 120 | /* 121 | ** Handle a request to a host that's IP masquerading through us. 122 | ** Returns non-zero on failure. 123 | */ 124 | 125 | int masq( int sock, 126 | in_port_t lport, 127 | in_port_t fport, 128 | struct sockaddr_storage *laddr, 129 | struct sockaddr_storage *faddr) 130 | { 131 | struct pfioc_natlook natlook; 132 | int pfdev; 133 | int retm; 134 | char os[24]; 135 | char user[MAX_ULEN]; 136 | struct sockaddr_storage ss; 137 | in_port_t masq_lport; 138 | in_port_t masq_fport; 139 | 140 | /* 141 | ** Only IPv4 is supported right now.. 142 | */ 143 | 144 | if (faddr->ss_family != AF_INET || laddr->ss_family != AF_INET) 145 | return -1; 146 | 147 | pfdev = open(PF_DEVICE, O_RDWR); 148 | if (pfdev == -1) { 149 | debug("open: %s: %s", PF_DEVICE, strerror(errno)); 150 | return -1; 151 | } 152 | 153 | memset(&natlook, 0, sizeof(struct pfioc_natlook)); 154 | 155 | memcpy(&natlook.saddr.v4.s_addr, &SIN4(laddr)->sin_addr.s_addr, 156 | sizeof(struct in_addr)); 157 | natlook.sport = lport; 158 | 159 | memcpy(&natlook.daddr.v4.s_addr, &SIN4(faddr)->sin_addr.s_addr, 160 | sizeof(struct in_addr)); 161 | natlook.dport = fport; 162 | 163 | natlook.direction = PF_IN; 164 | natlook.af = AF_INET; 165 | natlook.proto = IPPROTO_TCP; 166 | 167 | if (ioctl(pfdev, DIOCNATLOOK, &natlook) != 0) { 168 | debug("ioctl: %s", strerror(errno)); 169 | return -1; 170 | } 171 | 172 | fport = ntohs(fport); 173 | lport = ntohs(lport); 174 | masq_lport = ntohs(natlook.rsport); 175 | masq_fport = ntohs(natlook.rdport); 176 | 177 | sin_setv4(natlook.rsaddr.v4.s_addr, &ss); 178 | 179 | retm = find_masq_entry(&ss, user, sizeof(user), os, sizeof(os)); 180 | 181 | if (opt_enabled(FORWARD) && (retm != 0 || !opt_enabled(MASQ_OVERRIDE))) { 182 | int retf; 183 | 184 | retf = fwd_request(sock, lport, masq_lport, fport, masq_fport, &ss); 185 | 186 | if (retf == 0) { 187 | if (retm != 0) 188 | return 0; 189 | } else { 190 | char ipbuf[MAX_IPLEN]; 191 | 192 | get_ip(&ss, ipbuf, sizeof(ipbuf)); 193 | debug("Forward to %s (%d %d) (%d) failed", 194 | ipbuf, lport, natlook.rsport, fport); 195 | } 196 | } 197 | 198 | if (retm == 0) { 199 | char ipbuf[MAX_IPLEN]; 200 | 201 | sockprintf(sock, "%d,%d:USERID:%s:%s\r\n", 202 | lport, fport, os, user); 203 | 204 | get_ip(faddr, ipbuf, sizeof(ipbuf)); 205 | 206 | o_log(LOG_INFO, 207 | "[%s] (NAT) Successful lookup: %d , %d : %s", 208 | ipbuf, lport, fport, user); 209 | 210 | return 0; 211 | } 212 | 213 | return -1; 214 | } 215 | 216 | #endif 217 | 218 | #if WANT_IPV6 219 | 220 | /* 221 | ** Returns the UID of the owner of an IPv6 connection, 222 | ** or MISSING_UID on failure. 223 | */ 224 | 225 | uid_t get_user6( in_port_t lport, 226 | in_port_t fport, 227 | struct sockaddr_storage *laddr, 228 | struct sockaddr_storage *faddr) 229 | { 230 | struct tcp_ident_mapping tir; 231 | struct sockaddr_in6 *fin; 232 | struct sockaddr_in6 *lin; 233 | int mib[] = { CTL_NET, PF_INET, IPPROTO_TCP, TCPCTL_IDENT }; 234 | int error; 235 | size_t i; 236 | 237 | memset(&tir, 0, sizeof(tir)); 238 | 239 | fin = (struct sockaddr_in6 *) &tir.faddr; 240 | fin->sin6_family = AF_INET6; 241 | fin->sin6_len = sizeof(struct sockaddr_in6); 242 | 243 | if (faddr->ss_len > sizeof(tir.faddr)) 244 | return MISSING_UID; 245 | 246 | memcpy(&fin->sin6_addr, &SIN6(faddr)->sin6_addr, sizeof(tir.faddr)); 247 | fin->sin6_port = fport; 248 | 249 | lin = (struct sockaddr_in6 *) &tir.laddr; 250 | lin->sin6_family = AF_INET6; 251 | lin->sin6_len = sizeof(struct sockaddr_in6); 252 | 253 | if (laddr->ss_len > sizeof(tir.laddr)) 254 | return MISSING_UID; 255 | 256 | memcpy(&lin->sin6_addr, &SIN6(laddr)->sin6_addr, sizeof(tir.laddr)); 257 | lin->sin6_port = lport; 258 | 259 | i = sizeof(tir); 260 | error = sysctl(mib, sizeof(mib) / sizeof(int), &tir, &i, NULL, 0); 261 | 262 | if (error == 0 && tir.ruid != -1) 263 | return tir.ruid; 264 | 265 | if (error == -1) 266 | debug("sysctl: %s", strerror(errno)); 267 | 268 | return MISSING_UID; 269 | } 270 | 271 | #endif 272 | 273 | /* 274 | ** Open the kernel memory device. 275 | ** Return 0 on success, or -1 with errno set. 276 | ** 277 | ** No kmem access required; nothing to do. 278 | */ 279 | 280 | int k_open(void) { 281 | #ifdef HAVE_UNVEIL 282 | if (unveil("/", "r")) { 283 | debug("unveil: %s", strerror(errno)); 284 | return -1; 285 | } 286 | #endif 287 | 288 | return 0; 289 | } 290 | -------------------------------------------------------------------------------- /src/masq.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** masq.c - oidentd IP masquerading handler. 3 | ** Copyright (c) 1998-2006 Ryan McCabe 4 | ** Copyright (c) 2018-2019 Janik Rabe 5 | ** 6 | ** This program is free software; you can redistribute it and/or modify 7 | ** it under the terms of the GNU General Public License, version 2, 8 | ** as published by the Free Software Foundation. 9 | ** 10 | ** This program is distributed in the hope that it will be useful, 11 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ** GNU General Public License for more details. 14 | ** 15 | ** You should have received a copy of the GNU General Public License 16 | ** along with this program; if not, write to the Free Software 17 | ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #include 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #include "oidentd.h" 36 | #include "util.h" 37 | #include "missing.h" 38 | #include "inet_util.h" 39 | #include "masq.h" 40 | #include "options.h" 41 | #include "forward.h" 42 | 43 | struct sockaddr_storage proxy; 44 | 45 | #if MASQ_SUPPORT 46 | 47 | in_port_t fwdport; 48 | 49 | extern char *ret_os; 50 | 51 | static bool blank_line(const char *buf); 52 | 53 | /* 54 | ** Returns true if the buffer contains only 55 | ** blank characters (spaces and/or tabs). Returns 56 | ** false otherwise. 57 | */ 58 | 59 | static bool blank_line(const char *buf) { 60 | const char *p; 61 | 62 | for (p = buf; *p; ++p) { 63 | if (*p != ' ' && *p != '\t') 64 | return false; 65 | } 66 | 67 | return true; 68 | } 69 | 70 | /* 71 | ** Parse the masquerading map file. 72 | ** Returns 0 on success, -1 on failure. 73 | */ 74 | 75 | int find_masq_entry(struct sockaddr_storage *host, 76 | char *user, 77 | size_t user_len, 78 | char *os, 79 | size_t os_len) 80 | { 81 | FILE *fp; 82 | struct sockaddr_storage addr; 83 | u_int32_t line_num; 84 | char buf[4096]; 85 | 86 | fp = fopen(MASQ_MAP, "r"); 87 | if (!fp) { 88 | if (errno != EEXIST) 89 | debug("fopen: %s: %s", MASQ_MAP, strerror(errno)); 90 | return -1; 91 | } 92 | 93 | line_num = 0; 94 | 95 | while (fgets(buf, sizeof(buf), fp)) { 96 | struct sockaddr_storage stemp; 97 | char *p, *temp; 98 | 99 | ++line_num; 100 | p = strchr(buf, '\n'); 101 | if (!p) { 102 | debug("[%s:%d] Line too long", MASQ_MAP, line_num); 103 | goto failure; 104 | } 105 | *p = '\0'; 106 | 107 | if (buf[0] == '#') 108 | continue; 109 | 110 | if (blank_line(buf)) 111 | continue; 112 | 113 | p = strchr(buf, '\r'); 114 | if (p) 115 | *p = '\0'; 116 | 117 | p = strtok(buf, " \t"); 118 | if (!p) { 119 | debug("[%s:%d] Missing address parameter", MASQ_MAP, line_num); 120 | goto failure; 121 | } 122 | 123 | temp = strchr(p, '/'); 124 | if (temp) 125 | *temp++ = '\0'; 126 | 127 | if (get_addr(p, &stemp) == -1) { 128 | debug("[%s:%d] Invalid address: %s", MASQ_MAP, line_num, p); 129 | goto failure; 130 | } 131 | 132 | sin_copy(&addr, &stemp); 133 | 134 | if (stemp.ss_family == AF_INET && temp) { 135 | in_addr_t mask, mask2; 136 | char *end; 137 | 138 | mask = strtoul(temp, &end, 10); 139 | 140 | if (*end != '\0') { 141 | if (get_addr(temp, &stemp) == -1) { 142 | debug("[%s:%d] Invalid address: %s", 143 | MASQ_MAP, line_num, temp); 144 | 145 | goto failure; 146 | } 147 | 148 | mask2 = SIN4(&stemp)->sin_addr.s_addr; 149 | } else { 150 | if (mask < 1 || mask > 31) { 151 | debug("[%s:%d] Invalid mask: %s", 152 | MASQ_MAP, line_num, temp); 153 | 154 | goto failure; 155 | } 156 | 157 | mask2 = htonl(~(((uint32_t) 1 << (32 - mask)) - 1)); 158 | } 159 | 160 | SIN4(&addr)->sin_addr.s_addr &= mask2; 161 | SIN4(host)->sin_addr.s_addr &= mask2; 162 | } 163 | 164 | if (!sin_equal(&addr, host)) 165 | continue; 166 | 167 | p = strtok(NULL, " \t"); 168 | if (!p) { 169 | debug("[%s:%d] Missing user parameter", MASQ_MAP, line_num); 170 | goto failure; 171 | } 172 | 173 | if (strlen(p) >= user_len) { 174 | debug("[%s:%d] Username too long (limit is %ld)", 175 | MASQ_MAP, line_num, user_len); 176 | 177 | goto failure; 178 | } 179 | 180 | xstrncpy(user, p, user_len); 181 | 182 | p = strtok(NULL, " \t"); 183 | if (!p) { 184 | debug("[%s:%d] Missing OS parameter", MASQ_MAP, line_num); 185 | 186 | goto failure; 187 | } 188 | 189 | if (strlen(p) >= os_len) { 190 | debug("[%s:%d] OS name too long (limit is %ld)", 191 | MASQ_MAP, line_num, os_len); 192 | 193 | goto failure; 194 | } 195 | 196 | xstrncpy(os, p, os_len); 197 | 198 | fclose(fp); 199 | return 0; 200 | } 201 | 202 | failure: 203 | fclose(fp); 204 | return -1; 205 | } 206 | 207 | /* 208 | ** Forward an Ident request to another machine, return the response to the 209 | ** client that has connected to us and requested it. 210 | */ 211 | 212 | int fwd_request( int sock, 213 | in_port_t real_lport, 214 | in_port_t masq_lport, 215 | in_port_t real_fport, 216 | in_port_t masq_fport, 217 | struct sockaddr_storage *mrelay) 218 | { 219 | char ipbuf[MAX_IPLEN]; 220 | char user[512]; 221 | int ret; 222 | 223 | ret = forward_request(mrelay, fwdport, masq_lport, masq_fport, 224 | user, sizeof user); 225 | if (ret == -1) 226 | return -1; 227 | 228 | sockprintf(sock, "%d,%d:USERID:%s:%s\r\n", 229 | real_lport, real_fport, ret_os, user); 230 | 231 | get_ip(mrelay, ipbuf, sizeof(ipbuf)); 232 | o_log(LOG_INFO, 233 | "[%s] Successful lookup (by forward): %d (%d) , %d (%d) : %s", 234 | ipbuf, real_lport, masq_lport, real_fport, masq_fport, user); 235 | 236 | return 0; 237 | } 238 | 239 | #else 240 | 241 | /* 242 | ** Handle a request to a host that's IP masquerading through us. 243 | ** Returns non-zero on failure. 244 | */ 245 | 246 | int masq( int sock __notused, 247 | in_port_t lport __notused, 248 | in_port_t fport __notused, 249 | struct sockaddr_storage *local __notused, 250 | struct sockaddr_storage *remote __notused) 251 | { 252 | return -1; 253 | } 254 | 255 | #endif 256 | -------------------------------------------------------------------------------- /src/masq.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** masq.h - oidentd IP masquerading handler. 3 | ** Copyright (c) 1998-2006 Ryan McCabe 4 | ** Copyright (c) 2018 Janik Rabe 5 | ** 6 | ** This program is free software; you can redistribute it and/or modify 7 | ** it under the terms of the GNU General Public License, version 2, 8 | ** as published by the Free Software Foundation. 9 | ** 10 | ** This program is distributed in the hope that it will be useful, 11 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ** GNU General Public License for more details. 14 | ** 15 | ** You should have received a copy of the GNU General Public License 16 | ** along with this program; if not, write to the Free Software 17 | ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #ifndef __OIDENTD_MASQ_H 21 | #define __OIDENTD_MASQ_H 22 | 23 | #if MASQ_SUPPORT 24 | 25 | int find_masq_entry(struct sockaddr_storage *host, 26 | char *user, 27 | size_t user_len, 28 | char *os, 29 | size_t os_len); 30 | 31 | int fwd_request(int sock, 32 | in_port_t real_lport, 33 | in_port_t masq_lport, 34 | in_port_t real_fport, 35 | in_port_t masq_fport, 36 | struct sockaddr_storage *mrelay); 37 | 38 | #endif 39 | 40 | int masq( int sock, 41 | in_port_t lport, 42 | in_port_t fport, 43 | struct sockaddr_storage *laddr, 44 | struct sockaddr_storage *faddr); 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /src/missing/Makefile.am: -------------------------------------------------------------------------------- 1 | AM_CFLAGS = "-I$(srcdir)" $(DEBUG_CFLAGS) $(WARN_CFLAGS) 2 | 3 | noinst_LIBRARIES = libmissing.a 4 | 5 | libmissing_a_SOURCES = \ 6 | inet_aton.c \ 7 | inet_ntop.c \ 8 | ipv6_missing.c \ 9 | getopt.c \ 10 | vasprintf.c 11 | 12 | noinst_HEADERS = \ 13 | getopt_missing.h \ 14 | missing.h 15 | -------------------------------------------------------------------------------- /src/missing/getopt.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (c) 1987,88,89,90,91,92,93,94,95,96,98,99,2000,2001 3 | ** Free Software Foundation, Inc. 4 | ** This file is part of the GNU C Library. 5 | ** 6 | ** The GNU C Library is free software; you can redistribute it and/or 7 | ** modify it under the terms of the GNU Lesser General Public 8 | ** License as published by the Free Software Foundation; either 9 | ** version 2.1 of the License, or (at your option) any later version. 10 | ** 11 | ** The GNU C Library is distributed in the hope that it will be useful, 12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | ** Lesser General Public License for more details. 15 | ** 16 | ** You should have received a copy of the GNU Lesser General Public 17 | ** License along with the GNU C Library; if not, write to the Free 18 | ** Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19 | ** 02110-1301 USA. 20 | ** 21 | ** Code cleanup Copyright (c) 2001-2006 Ryan McCabe 22 | */ 23 | 24 | #include 25 | 26 | #ifndef HAVE_GETOPT_LONG 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | char *optarg; 34 | int optind = 1; 35 | int __getopt_initialized; 36 | static char *nextchar; 37 | int opterr = 1; 38 | int optopt = '?'; 39 | 40 | static enum { 41 | REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER 42 | } ordering; 43 | 44 | static char *posixly_correct; 45 | 46 | static char *my_index(const char *str, int chr) { 47 | while (*str) { 48 | if (*str == chr) 49 | return ((char *) str); 50 | str++; 51 | } 52 | 53 | return (0); 54 | } 55 | 56 | static int first_nonopt; 57 | static int last_nonopt; 58 | 59 | #define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0') 60 | 61 | static void exchange(char **argv) { 62 | int bottom = first_nonopt; 63 | int middle = last_nonopt; 64 | int top = optind; 65 | char *tem; 66 | 67 | while (top > middle && middle > bottom) { 68 | if (top - middle > middle - bottom) { 69 | int len = middle - bottom; 70 | int i; 71 | 72 | for (i = 0; i < len; i++) { 73 | tem = argv[bottom + i]; 74 | argv[bottom + i] = argv[top - (middle - bottom) + i]; 75 | argv[top - (middle - bottom) + i] = tem; 76 | } 77 | 78 | top -= len; 79 | } else { 80 | int len = top - middle; 81 | int i; 82 | 83 | for (i = 0; i < len; i++) { 84 | tem = argv[bottom + i]; 85 | argv[bottom + i] = argv[middle + i]; 86 | argv[middle + i] = tem; 87 | } 88 | 89 | bottom += len; 90 | } 91 | } 92 | 93 | first_nonopt += (optind - last_nonopt); 94 | last_nonopt = optind; 95 | } 96 | 97 | static const char *_getopt_initialize( int argc, 98 | char *const *argv, 99 | const char *optstring) 100 | { 101 | (void) argc; 102 | (void) argv; 103 | 104 | first_nonopt = last_nonopt = optind; 105 | nextchar = NULL; 106 | posixly_correct = getenv("POSIXLY_CORRECT"); 107 | 108 | if (optstring[0] == '-') { 109 | ordering = RETURN_IN_ORDER; 110 | ++optstring; 111 | } else if (optstring[0] == '+') { 112 | ordering = REQUIRE_ORDER; 113 | ++optstring; 114 | } else if (posixly_correct != NULL) 115 | ordering = REQUIRE_ORDER; 116 | else 117 | ordering = PERMUTE; 118 | 119 | return (optstring); 120 | } 121 | 122 | int _getopt_internal( int argc, 123 | char *const *argv, 124 | const char *optstring, 125 | const struct option *longopts, 126 | int *longind, 127 | int long_only) 128 | { 129 | int print_errors = opterr; 130 | 131 | if (optstring[0] == ':') 132 | print_errors = 0; 133 | 134 | if (argc < 1) 135 | return (-1); 136 | 137 | optarg = NULL; 138 | 139 | if (optind == 0 || !__getopt_initialized) { 140 | if (optind == 0) 141 | optind = 1; 142 | 143 | optstring = _getopt_initialize(argc, argv, optstring); 144 | __getopt_initialized = 1; 145 | } 146 | 147 | if (nextchar == NULL || *nextchar == '\0') { 148 | if (last_nonopt > optind) 149 | last_nonopt = optind; 150 | 151 | if (first_nonopt > optind) 152 | first_nonopt = optind; 153 | 154 | if (ordering == PERMUTE) { 155 | if (first_nonopt != last_nonopt && last_nonopt != optind) 156 | exchange((char **) argv); 157 | else if (last_nonopt != optind) 158 | first_nonopt = optind; 159 | 160 | while (optind < argc && NONOPTION_P) 161 | optind++; 162 | 163 | last_nonopt = optind; 164 | } 165 | 166 | if (optind != argc && !strcmp(argv[optind], "--")) { 167 | optind++; 168 | 169 | if (first_nonopt != last_nonopt && last_nonopt != optind) 170 | exchange((char **) argv); 171 | else if (first_nonopt == last_nonopt) 172 | first_nonopt = optind; 173 | 174 | last_nonopt = argc; 175 | optind = argc; 176 | } 177 | 178 | if (optind == argc) { 179 | if (first_nonopt != last_nonopt) 180 | optind = first_nonopt; 181 | 182 | return (-1); 183 | } 184 | 185 | if (NONOPTION_P) { 186 | if (ordering == REQUIRE_ORDER) 187 | return (-1); 188 | 189 | optarg = argv[optind++]; 190 | return (1); 191 | } 192 | 193 | nextchar = 194 | (argv[optind] + 1 + (longopts != NULL && argv[optind][1] == '-')); 195 | } 196 | 197 | if (longopts != NULL 198 | && (argv[optind][1] == '-' 199 | || (long_only && (argv[optind][2] 200 | || !my_index (optstring, argv[optind][1]))))) 201 | { 202 | char *nameend; 203 | const struct option *p; 204 | const struct option *pfound = NULL; 205 | int exact = 0; 206 | int ambig = 0; 207 | int indfound = -1; 208 | int option_index; 209 | 210 | for (nameend = nextchar; *nameend && *nameend != '='; nameend++) 211 | ; 212 | 213 | for (p = longopts, option_index = 0; p->name; p++, option_index++) { 214 | if (!strncmp(p->name, nextchar, nameend - nextchar)) { 215 | if ((unsigned int) (nameend - nextchar) == 216 | (unsigned int) strlen(p->name)) 217 | { 218 | pfound = p; 219 | indfound = option_index; 220 | exact = 1; 221 | break; 222 | } else if (pfound == NULL) { 223 | pfound = p; 224 | indfound = option_index; 225 | } else if (long_only || pfound->has_arg != p->has_arg 226 | || pfound->flag != p->flag 227 | || pfound->val != p->val) 228 | { 229 | ambig = 1; 230 | } 231 | } 232 | } 233 | 234 | if (ambig && !exact) { 235 | if (print_errors) { 236 | fprintf(stderr, "%s: option `%s' is ambiguous\n", 237 | argv[0], argv[optind]); 238 | } 239 | 240 | nextchar += strlen(nextchar); 241 | optind++; 242 | optopt = 0; 243 | 244 | return ('?'); 245 | } 246 | 247 | if (pfound != NULL) { 248 | option_index = indfound; 249 | optind++; 250 | 251 | if (*nameend) { 252 | if (pfound->has_arg) 253 | optarg = nameend + 1; 254 | else { 255 | if (print_errors) { 256 | if (argv[optind - 1][1] == '-') { 257 | fprintf(stderr, 258 | "%s: option `--%s' doesn't allow an argument\n", 259 | argv[0], pfound->name); 260 | } else { 261 | fprintf(stderr, 262 | "%s: option `%c%s' doesn't allow an argument\n", 263 | argv[0], argv[optind - 1][0], pfound->name); 264 | } 265 | } 266 | 267 | nextchar += strlen(nextchar); 268 | optopt = pfound->val; 269 | 270 | return ('?'); 271 | } 272 | } else if (pfound->has_arg == 1) { 273 | if (optind < argc) 274 | optarg = argv[optind++]; 275 | else { 276 | if (print_errors) { 277 | fprintf(stderr, 278 | "%s: option `%s' requires an argument\n", 279 | argv[0], argv[optind - 1]); 280 | } 281 | 282 | nextchar += strlen(nextchar); 283 | optopt = pfound->val; 284 | 285 | return (optstring[0] == ':' ? ':' : '?'); 286 | } 287 | } 288 | 289 | nextchar += strlen(nextchar); 290 | 291 | if (longind != NULL) 292 | *longind = option_index; 293 | 294 | if (pfound->flag) { 295 | *(pfound->flag) = pfound->val; 296 | return (0); 297 | } 298 | 299 | return (pfound->val); 300 | } 301 | 302 | if (!long_only || argv[optind][1] == '-' 303 | || my_index(optstring, *nextchar) == NULL) 304 | { 305 | if (print_errors) { 306 | if (argv[optind][1] == '-') { 307 | fprintf(stderr, "%s: unrecognized option `--%s'\n", 308 | argv[0], nextchar); 309 | } else { 310 | fprintf(stderr, "%s: unrecognized option `%c%s'\n", 311 | argv[0], argv[optind][0], nextchar); 312 | } 313 | } 314 | 315 | nextchar = (char *) ""; 316 | optind++; 317 | optopt = 0; 318 | 319 | return ('?'); 320 | } 321 | } 322 | 323 | { 324 | char c = *nextchar++; 325 | char *temp = my_index(optstring, c); 326 | 327 | if (*nextchar == '\0') 328 | ++optind; 329 | 330 | if (temp == NULL || c == ':') { 331 | if (print_errors) { 332 | if (posixly_correct) { 333 | fprintf(stderr, "%s: illegal option -- %c\n", argv[0], c); 334 | } else { 335 | fprintf(stderr, "%s: invalid option -- %c\n", argv[0], c); 336 | } 337 | } 338 | 339 | optopt = c; 340 | return ('?'); 341 | } 342 | 343 | if (temp[0] == 'W' && temp[1] == ';') { 344 | char *nameend; 345 | const struct option *p; 346 | const struct option *pfound = NULL; 347 | int exact = 0; 348 | int ambig = 0; 349 | int indfound = 0; 350 | int option_index; 351 | 352 | if (*nextchar != '\0') { 353 | optarg = nextchar; 354 | optind++; 355 | } else if (optind == argc) { 356 | if (print_errors) { 357 | fprintf(stderr, "%s: option requires an argument -- %c\n", 358 | argv[0], c); 359 | } 360 | 361 | optopt = c; 362 | if (optstring[0] == ':') 363 | c = ':'; 364 | else 365 | c = '?'; 366 | 367 | return (c); 368 | } else 369 | optarg = argv[optind++]; 370 | 371 | for (nextchar = nameend = optarg ; 372 | *nameend && *nameend != '=' ; nameend++) 373 | { 374 | ; 375 | } 376 | 377 | for (p = longopts, option_index = 0 ; 378 | p->name; p++, option_index++) 379 | { 380 | if (!strncmp(p->name, nextchar, nameend - nextchar)) { 381 | if ((unsigned int) (nameend - nextchar) 382 | == strlen(p->name)) 383 | { 384 | pfound = p; 385 | indfound = option_index; 386 | exact = 1; 387 | break; 388 | } else if (pfound == NULL) { 389 | pfound = p; 390 | indfound = option_index; 391 | } else 392 | ambig = 1; 393 | } 394 | } 395 | 396 | if (ambig && !exact) { 397 | if (print_errors) { 398 | fprintf(stderr, "%s: option `-W %s' is ambiguous\n", 399 | argv[0], argv[optind]); 400 | } 401 | 402 | nextchar += strlen(nextchar); 403 | optind++; 404 | 405 | return ('?'); 406 | } 407 | 408 | if (pfound != NULL) { 409 | option_index = indfound; 410 | 411 | if (*nameend) { 412 | if (pfound->has_arg) 413 | optarg = nameend + 1; 414 | else { 415 | if (print_errors) { 416 | fprintf(stderr, 417 | "%s option `-W %s' doesn't allow an argument\n", 418 | argv[0], pfound->name); 419 | } 420 | 421 | nextchar += strlen(nextchar); 422 | return ('?'); 423 | } 424 | } else if (pfound->has_arg == 1) { 425 | if (optind < argc) 426 | optarg = argv[optind++]; 427 | else { 428 | if (print_errors) { 429 | fprintf(stderr, 430 | "%s: option `%s' requires an argument\n", 431 | argv[0], argv[optind - 1]); 432 | } 433 | 434 | nextchar += strlen(nextchar); 435 | return (optstring[0] == ':' ? ':' : '?'); 436 | } 437 | } 438 | 439 | nextchar += strlen(nextchar); 440 | if (longind != NULL) 441 | *longind = option_index; 442 | 443 | if (pfound->flag) { 444 | *(pfound->flag) = pfound->val; 445 | return (0); 446 | } 447 | 448 | return (pfound->val); 449 | } 450 | 451 | nextchar = NULL; 452 | return ('W'); 453 | } 454 | 455 | if (temp[1] == ':') { 456 | if (temp[2] == ':') { 457 | if (*nextchar != '\0') { 458 | optarg = nextchar; 459 | optind++; 460 | } else 461 | optarg = NULL; 462 | 463 | nextchar = NULL; 464 | } else { 465 | if (*nextchar != '\0') { 466 | optarg = nextchar; 467 | optind++; 468 | } else if (optind == argc) { 469 | if (print_errors) { 470 | fprintf(stderr, 471 | "%s: option requires an argument -- %c\n", 472 | argv[0], c); 473 | } 474 | 475 | optopt = c; 476 | 477 | if (optstring[0] == ':') 478 | c = ':'; 479 | else 480 | c = '?'; 481 | } else 482 | optarg = argv[optind++]; 483 | 484 | nextchar = NULL; 485 | } 486 | } 487 | 488 | return (c); 489 | } 490 | } 491 | 492 | int getopt(int argc, char *const *argv, const char *optstring) { 493 | return (_getopt_internal(argc, argv, optstring, NULL, NULL, 0)); 494 | } 495 | 496 | int getopt_long(int argc, 497 | char *const *argv, 498 | const char *options, 499 | const struct option *long_options, 500 | int *opt_index) 501 | { 502 | return (_getopt_internal(argc, argv, options, long_options, opt_index, 0)); 503 | } 504 | 505 | int getopt_long_only( int argc, 506 | char *const *argv, 507 | const char *options, 508 | const struct option *long_options, 509 | int *opt_index) 510 | { 511 | return (_getopt_internal(argc, argv, options, long_options, opt_index, 1)); 512 | } 513 | 514 | #endif 515 | -------------------------------------------------------------------------------- /src/missing/getopt_missing.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** getopt_missing.h - Declarations for getopt. 3 | ** 4 | ** Copyright (c) 1989-1994, 1996-1999, 2001 Free Software Foundation, Inc. 5 | ** This file is part of the GNU C Library. 6 | ** 7 | ** The GNU C Library is free software; you can redistribute it and/or 8 | ** modify it under the terms of the GNU Lesser General Public 9 | ** License as published by the Free Software Foundation; either 10 | ** version 2.1 of the License, or (at your option) any later version. 11 | ** 12 | ** The GNU C Library is distributed in the hope that it will be useful, 13 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | ** Lesser General Public License for more details. 16 | ** 17 | ** You should have received a copy of the GNU Lesser General Public 18 | ** License along with the GNU C Library; if not, write to the Free 19 | ** Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 20 | ** 02110-1301 USA. 21 | ** 22 | ** Cleanup Copyright (c) 2001-2006 Ryan McCabe 23 | */ 24 | 25 | #ifndef _GETOPT_MISSING_H 26 | #define _GETOPT_MISSING_H 27 | 28 | # ifndef HAVE_GETOPT_LONG 29 | 30 | extern char *optarg; 31 | extern int optind; 32 | extern int opterr; 33 | extern int optopt; 34 | 35 | struct option { 36 | const char *name; 37 | int has_arg; 38 | int *flag; 39 | int val; 40 | }; 41 | 42 | /* Names for the values of the `has_arg' field of `struct option'. */ 43 | 44 | #define no_argument 0 45 | #define required_argument 1 46 | #define optional_argument 2 47 | 48 | int getopt(int ___argc, char *const *___argv, const char *__shortopts); 49 | 50 | int getopt_long(int ___argc, 51 | char *const *___argv, 52 | const char *__shortopts, 53 | const struct option *__longopts, 54 | int *__longind); 55 | 56 | int getopt_long_only( int ___argc, 57 | char *const *___argv, 58 | const char *__shortopts, 59 | const struct option *__longopts, 60 | int *__longind); 61 | 62 | int _getopt_internal( int ___argc, 63 | char *const *___argv, 64 | const char *__shortopts, 65 | const struct option *__longopts, 66 | int *__longind, 67 | int __long_only); 68 | # endif 69 | 70 | #else 71 | # warning "included multiple times" 72 | #endif 73 | -------------------------------------------------------------------------------- /src/missing/inet_aton.c: -------------------------------------------------------------------------------- 1 | /* 2 | * ++Copyright++ 1983, 1990, 1993 3 | * - 4 | * Copyright (c) 1983, 1990, 1993 5 | * The Regents of the University of California. All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions 9 | * are met: 10 | * 1. Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * 2. Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the distribution. 15 | * 3. All advertising materials mentioning features or use of this software 16 | * must display the following acknowledgement: 17 | * This product includes software developed by the University of 18 | * California, Berkeley and its contributors. 19 | * 4. Neither the name of the University nor the names of its contributors 20 | * may be used to endorse or promote products derived from this software 21 | * without specific prior written permission. 22 | * 23 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 | * SUCH DAMAGE. 34 | * - 35 | * Portions Copyright (c) 1993 by Digital Equipment Corporation. 36 | * 37 | * Permission to use, copy, modify, and distribute this software for any 38 | * purpose with or without fee is hereby granted, provided that the above 39 | * copyright notice and this permission notice appear in all copies, and that 40 | * the name of Digital Equipment Corporation not be used in advertising or 41 | * publicity pertaining to distribution of the document or software without 42 | * specific, written prior permission. 43 | * 44 | * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL 45 | * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES 46 | * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT 47 | * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 48 | * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 49 | * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 50 | * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 51 | * SOFTWARE. 52 | * - 53 | * --Copyright-- 54 | */ 55 | 56 | #include 57 | 58 | #if !defined(HAVE_INET_ATON) 59 | 60 | #include 61 | #include 62 | #include 63 | #include 64 | #include 65 | 66 | /* 67 | * Check whether "cp" is a valid ascii representation 68 | * of an Internet address and convert to a binary address. 69 | * Returns 1 if the address is valid, 0 if not. 70 | * This replaces inet_addr, the return value from which 71 | * cannot distinguish between failure and a local broadcast address. 72 | */ 73 | int 74 | inet_aton(const char *cp, struct in_addr *addr) 75 | { 76 | register u_int32_t val; 77 | register int base, n; 78 | register char c; 79 | unsigned int parts[4]; 80 | register unsigned int *pp = parts; 81 | 82 | c = *cp; 83 | for (;;) { 84 | /* 85 | * Collect number up to ``.''. 86 | * Values are specified as for C: 87 | * 0x=hex, 0=octal, isdigit=decimal. 88 | */ 89 | if (!isdigit(c)) 90 | return (0); 91 | val = 0; base = 10; 92 | if (c == '0') { 93 | c = *++cp; 94 | if (c == 'x' || c == 'X') 95 | base = 16, c = *++cp; 96 | else 97 | base = 8; 98 | } 99 | for (;;) { 100 | if (isascii(c) && isdigit(c)) { 101 | val = (val * base) + (c - '0'); 102 | c = *++cp; 103 | } else if (base == 16 && isascii(c) && isxdigit(c)) { 104 | val = (val << 4) | 105 | (c + 10 - (islower(c) ? 'a' : 'A')); 106 | c = *++cp; 107 | } else 108 | break; 109 | } 110 | if (c == '.') { 111 | /* 112 | * Internet format: 113 | * a.b.c.d 114 | * a.b.c (with c treated as 16 bits) 115 | * a.b (with b treated as 24 bits) 116 | */ 117 | if (pp >= parts + 3) 118 | return (0); 119 | *pp++ = val; 120 | c = *++cp; 121 | } else 122 | break; 123 | } 124 | /* 125 | * Check for trailing characters. 126 | */ 127 | if (c != '\0' && (!isascii(c) || !isspace(c))) 128 | return (0); 129 | /* 130 | * Concoct the address according to 131 | * the number of parts specified. 132 | */ 133 | n = pp - parts + 1; 134 | switch (n) { 135 | 136 | case 0: 137 | return (0); /* initial nondigit */ 138 | 139 | case 1: /* a -- 32 bits */ 140 | break; 141 | 142 | case 2: /* a.b -- 8.24 bits */ 143 | if ((val > 0xffffff) || (parts[0] > 0xff)) 144 | return (0); 145 | val |= parts[0] << 24; 146 | break; 147 | 148 | case 3: /* a.b.c -- 8.8.16 bits */ 149 | if ((val > 0xffff) || (parts[0] > 0xff) || (parts[1] > 0xff)) 150 | return (0); 151 | val |= (parts[0] << 24) | (parts[1] << 16); 152 | break; 153 | 154 | case 4: /* a.b.c.d -- 8.8.8.8 bits */ 155 | if ((val > 0xff) || (parts[0] > 0xff) || (parts[1] > 0xff) || (parts[2] > 0xff)) 156 | return (0); 157 | val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); 158 | break; 159 | } 160 | if (addr) 161 | addr->s_addr = htonl(val); 162 | return (1); 163 | } 164 | 165 | #endif /* !defined(HAVE_INET_ATON) */ 166 | -------------------------------------------------------------------------------- /src/missing/inet_ntop.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #ifndef HAVE_INET_NTOP 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #ifndef INET_ADDRSTRLEN 15 | # define INET_ADDRSTRLEN 16 16 | #endif 17 | 18 | /* 19 | ** This is an IPv4 only inet_ntop(3) replacement function. 20 | */ 21 | 22 | const char *inet_ntop(int af, const void *src, char *dst, size_t len) { 23 | const char *tmp = src; 24 | 25 | if (af != AF_INET) { 26 | errno = EAFNOSUPPORT; 27 | return (NULL); 28 | } 29 | 30 | if (len < INET_ADDRSTRLEN) { 31 | errno = ENOSPC; 32 | return (NULL); 33 | } 34 | 35 | snprintf(dst, len, "%u.%u.%u.%u", tmp[0], tmp[1], tmp[2], tmp[3]); 36 | 37 | return (dst); 38 | } 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /src/missing/ipv6_missing.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** ipv6.c - Compatibility functions. 3 | ** 4 | ** This file includes getaddrinfo(), freeaddrinfo() and gai_strerror(). 5 | ** These funtions are defined in rfc2133. 6 | ** 7 | ** But these functions are not implemented correctly. The minimum subset 8 | ** is implemented for ssh use only. For exapmle, this routine assumes 9 | ** that ai_family is AF_INET. Don't use it for another purpose. 10 | ** 11 | ** This code was taken from OpenSSH. It is distributed 12 | ** under a two-term BSD license. 13 | ** 14 | ** Modifications Copyright (c) 2001-2006 Ryan McCabe 15 | */ 16 | 17 | #ifndef _GNU_SOURCE 18 | # define _GNU_SOURCE 19 | #endif 20 | 21 | #include 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | #include "missing.h" 41 | 42 | #ifndef HAVE_GAI_STRERROR 43 | 44 | char *gai_strerror(int ecode) { 45 | switch (ecode) { 46 | case EAI_NODATA: 47 | return ("no address associated with hostname"); 48 | case EAI_MEMORY: 49 | return ("memory allocation failure"); 50 | default: 51 | return ("unknown error"); 52 | } 53 | } 54 | 55 | #endif 56 | 57 | #ifndef HAVE_FREEADDRINFO 58 | 59 | void freeaddrinfo(struct addrinfo *ai) { 60 | 61 | while (ai != NULL) { 62 | struct addrinfo *next = ai->ai_next; 63 | 64 | free(ai); 65 | ai = next; 66 | } 67 | } 68 | 69 | #endif 70 | 71 | #ifndef HAVE_GETADDRINFO 72 | 73 | static struct addrinfo *malloc_ai(int port, in_addr_t addr) { 74 | struct addrinfo *ai; 75 | 76 | ai = malloc(sizeof(struct addrinfo) + sizeof(struct sockaddr_in)); 77 | if (ai == NULL) 78 | return (NULL); 79 | 80 | memset(ai, 0, sizeof(struct addrinfo) + sizeof(struct sockaddr_in)); 81 | 82 | ai->ai_addr = (struct sockaddr *) (ai + 1); 83 | ai->ai_addrlen = sizeof(struct sockaddr_in); 84 | ai->ai_addr->sa_family = ai->ai_family = AF_INET; 85 | 86 | ((struct sockaddr_in *) (ai)->ai_addr)->sin_port = port; 87 | ((struct sockaddr_in *) (ai)->ai_addr)->sin_addr.s_addr = addr; 88 | 89 | return (ai); 90 | } 91 | 92 | int getaddrinfo(const char *hostname, const char *servname, 93 | const struct addrinfo *hints, struct addrinfo **res) 94 | { 95 | struct addrinfo *cur, *prev = NULL; 96 | struct hostent *hp; 97 | struct in_addr in; 98 | int i, port; 99 | 100 | if (servname) 101 | port = htons(atoi(servname)); 102 | else 103 | port = 0; 104 | 105 | if (hints != NULL && hints->ai_flags & AI_PASSIVE) { 106 | *res = malloc_ai(port, htonl(0x00000000)); 107 | if (*res != NULL) 108 | return (0); 109 | else 110 | return (EAI_MEMORY); 111 | } 112 | 113 | if (hostname == NULL) { 114 | *res = malloc_ai(port, htonl(0x7f000001)); 115 | if (*res != NULL) 116 | return (0); 117 | else 118 | return (EAI_MEMORY); 119 | } 120 | 121 | if (inet_aton(hostname, &in) != 0) { 122 | *res = malloc_ai(port, in.s_addr); 123 | if (*res != NULL) 124 | return (0); 125 | else 126 | return (EAI_MEMORY); 127 | } 128 | 129 | hp = gethostbyname(hostname); 130 | if (hp != NULL && hp->h_name != NULL && hp->h_name[0] != 0 && 131 | hp->h_addr_list[0] != NULL) 132 | { 133 | for (i = 0 ; hp->h_addr_list[i] ; i++) { 134 | cur = malloc_ai(port, 135 | ((struct in_addr *) hp->h_addr_list[i])->s_addr); 136 | 137 | if (cur == NULL) { 138 | if (*res != NULL) 139 | freeaddrinfo(*res); 140 | 141 | return (EAI_MEMORY); 142 | } 143 | 144 | if (prev != NULL) 145 | prev->ai_next = cur; 146 | else 147 | *res = cur; 148 | 149 | prev = cur; 150 | } 151 | 152 | return (0); 153 | } 154 | 155 | return (EAI_NODATA); 156 | } 157 | 158 | #endif 159 | 160 | #ifndef HAVE_GETNAMEINFO 161 | 162 | int getnameinfo(const struct sockaddr *sa, size_t salen, char *host, 163 | size_t hostlen, char *serv, size_t servlen, int flags) 164 | { 165 | struct sockaddr_in *sin4 = (struct sockaddr_in *) sa; 166 | struct hostent *hp; 167 | char tmpserv[16]; 168 | 169 | (void) salen; 170 | 171 | if (serv != NULL) { 172 | snprintf(tmpserv, sizeof(tmpserv), "%d", ntohs(sin4->sin_port)); 173 | if (strlen(tmpserv) >= servlen) 174 | return (EAI_MEMORY); 175 | else 176 | strcpy(serv, tmpserv); 177 | } 178 | 179 | if (host != NULL) { 180 | if (flags & NI_NUMERICHOST) { 181 | if (strlen(inet_ntoa(sin4->sin_addr)) >= hostlen) 182 | return (EAI_MEMORY); 183 | 184 | strcpy(host, inet_ntoa(sin4->sin_addr)); 185 | return (0); 186 | } else { 187 | hp = gethostbyaddr((char *) &sin4->sin_addr, 188 | sizeof(struct in_addr), AF_INET); 189 | if (hp == NULL) 190 | return (EAI_NODATA); 191 | 192 | if (strlen(hp->h_name) >= hostlen) 193 | return (EAI_MEMORY); 194 | 195 | strcpy(host, hp->h_name); 196 | return (0); 197 | } 198 | } 199 | 200 | return (0); 201 | } 202 | 203 | #endif 204 | -------------------------------------------------------------------------------- /src/missing/missing.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** missing.h 3 | ** Copyright (c) 2003-2006 Ryan McCabe 4 | ** Copyright (c) 2018-2019 Janik Rabe 5 | ** 6 | ** This program is free software; you can redistribute it and/or modify 7 | ** it under the terms of the GNU General Public License, version 2, 8 | ** as published by the Free Software Foundation. 9 | */ 10 | 11 | #ifndef __OIDENTD_MISSING_H 12 | #define __OIDENTD_MISSING_H 13 | 14 | #ifndef HAVE_INET_NTOP 15 | const char *inet_ntop(int af, const void *src, char *dst, size_t len); 16 | #endif 17 | 18 | #ifndef EAI_NODATA 19 | # define EAI_NODATA 1 20 | #endif 21 | 22 | #ifndef EAI_MEMORY 23 | # define EAI_MEMORY 2 24 | #endif 25 | 26 | #ifndef AI_PASSIVE 27 | # define AI_PASSIVE 1 28 | #endif 29 | 30 | #ifndef AI_CANONNAME 31 | # define AI_CANONNAME 2 32 | #endif 33 | 34 | #ifndef NI_NUMERICHOST 35 | # define NI_NUMERICHOST 2 36 | #endif 37 | 38 | #ifndef NI_NAMEREQD 39 | # define NI_NAMEREQD 4 40 | #endif 41 | 42 | #ifndef NI_NUMERICSERV 43 | # define NI_NUMERICSERV 8 44 | #endif 45 | 46 | #if !defined HAVE_STRUCT_ADDRINFO || !defined HAVE_GETNAMEINFO 47 | struct sockaddr; 48 | #endif 49 | 50 | #ifndef HAVE_STRUCT_ADDRINFO 51 | 52 | struct addrinfo { 53 | int ai_flags; 54 | int ai_family; 55 | int ai_socktype; 56 | int ai_protocol; 57 | size_t ai_addrlen; 58 | char *ai_canonname; 59 | struct sockaddr *ai_addr; 60 | struct addrinfo *ai_next; 61 | }; 62 | 63 | #endif 64 | 65 | #ifndef HAVE_GETADDRINFO 66 | int getaddrinfo(const char *hostname, const char *servname, 67 | const struct addrinfo *hints, struct addrinfo **res); 68 | #endif 69 | 70 | #ifndef HAVE_GAI_STRERROR 71 | char *gai_strerror(int ecode); 72 | #endif 73 | 74 | #ifndef HAVE_FREEADDRINFO 75 | void freeaddrinfo(struct addrinfo *ai); 76 | #endif 77 | 78 | #ifndef HAVE_GETNAMEINFO 79 | int getnameinfo(const struct sockaddr *sa, size_t salen, char *host, 80 | size_t hostlen, char *serv, size_t servlen, int flags); 81 | #endif 82 | 83 | #ifndef HAVE_VASPRINTF 84 | int vasprintf(char **result, const char *format, va_list args); 85 | #endif 86 | 87 | #ifndef NI_MAXSERV 88 | # define NI_MAXSERV 32 89 | #endif 90 | 91 | #ifndef NI_MAXHOST 92 | # define NI_MAXHOST 1025 93 | #endif 94 | 95 | #else 96 | # warning "included multiple times" 97 | #endif 98 | -------------------------------------------------------------------------------- /src/missing/vasprintf.c: -------------------------------------------------------------------------------- 1 | /* Like vsprintf but provides a pointer to malloc'd storage, which must 2 | be freed by the caller. 3 | Copyright (c) 1994 Free Software Foundation, Inc. 4 | 5 | This file is part of the libiberty library. 6 | Libiberty is free software; you can redistribute it and/or 7 | modify it under the terms of the GNU Library General Public 8 | License as published by the Free Software Foundation; either 9 | version 2 of the License, or (at your option) any later version. 10 | 11 | Libiberty is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | Library General Public License for more details. 15 | 16 | You should have received a copy of the GNU Library General Public 17 | License along with libiberty; see the file COPYING.LIB. If not, 18 | write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 | Boston, MA 02110-1301 USA. */ 20 | 21 | #include 22 | 23 | #ifndef HAVE_VASPRINTF 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | static int int_vasprintf(char **result, char *format, va_list args) { 32 | char *p = format; 33 | /* 34 | ** Add one to make sure that it is never zero, which might cause malloc 35 | ** to return NULL. 36 | */ 37 | int total_width = strlen(format) + 1; 38 | va_list ap; 39 | 40 | memcpy(&ap, args, sizeof(va_list)); 41 | 42 | while (*p != '\0') { 43 | if (*p++ == '%') { 44 | while (strchr("-+ #0", *p)) 45 | ++p; 46 | if (*p == '*') { 47 | ++p; 48 | total_width += abs(va_arg(ap, int)); 49 | } else 50 | total_width += strtoul(p, &p, 10); 51 | 52 | if (*p == '.') { 53 | ++p; 54 | if (*p == '*') { 55 | ++p; 56 | total_width += abs(va_arg(ap, int)); 57 | } else 58 | total_width += strtoul(p, &p, 10); 59 | } 60 | 61 | while (strchr("hlL", *p)) 62 | ++p; 63 | /* 64 | ** Should be big enough for any format 65 | ** specifier except %s and floats. 66 | */ 67 | total_width += 30; 68 | 69 | switch (*p) { 70 | case 'd': 71 | case 'i': 72 | case 'o': 73 | case 'u': 74 | case 'x': 75 | case 'X': 76 | case 'c': 77 | (void) va_arg(ap, int); 78 | break; 79 | 80 | case 'f': 81 | case 'e': 82 | case 'E': 83 | case 'g': 84 | case 'G': 85 | (void) va_arg(ap, double); 86 | /* 87 | ** Since an ieee double can have an exponent of 307, 88 | ** we'll make the buffer wide enough to cover 89 | ** the gross case. 90 | */ 91 | total_width += 307; 92 | break; 93 | 94 | case 's': 95 | total_width += strlen(va_arg(ap, char *)); 96 | break; 97 | 98 | case 'p': 99 | case 'n': 100 | (void) va_arg(ap, char *); 101 | break; 102 | } 103 | } 104 | } 105 | 106 | *result = malloc(total_width); 107 | if (*result != NULL) 108 | return (vsprintf(*result, format, args)); 109 | else 110 | return (0); 111 | } 112 | 113 | int vasprintf(char **strp, const char *fmt, va_list ap) { 114 | return (int_vasprintf(strp, (char *) fmt, ap)); 115 | } 116 | 117 | #endif 118 | -------------------------------------------------------------------------------- /src/netlink.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** netlink.h - Linux netlink definitions. 3 | ** 4 | ** This header file extracts the needed structure definitions, #defines 5 | ** and macros from linux/netlink.h and linux/tcp_diag.h, and converts them 6 | ** to be usable from userland code. 7 | ** 8 | ** Cleanup and conversion Copyright (c) 2002-2006 Ryan McCabe 9 | ** 10 | ** This program is free software; you can redistribute it and/or modify 11 | ** it under the terms of the GNU General Public License, version 2, 12 | ** as published by the Free Software Foundation. 13 | */ 14 | 15 | #ifndef __OIDENTD_NETLINK_H 16 | #define __OIDENTD_NETLINK_H 17 | 18 | #define NETLINK_TCPDIAG 4 19 | #define TCPDIAG_GETSOCK 18 20 | 21 | /* Socket identity */ 22 | struct tcpdiag_sockid { 23 | u_int16_t tcpdiag_sport; 24 | u_int16_t tcpdiag_dport; 25 | u_int32_t tcpdiag_src[4]; 26 | u_int32_t tcpdiag_dst[4]; 27 | u_int32_t tcpdiag_if; 28 | u_int32_t tcpdiag_cookie[2]; 29 | #define TCPDIAG_NOCOOKIE (~0U) 30 | }; 31 | 32 | /* Request structure */ 33 | 34 | struct tcpdiagreq { 35 | u_int8_t tcpdiag_family; 36 | u_int8_t tcpdiag_src_len; 37 | u_int8_t tcpdiag_dst_len; 38 | u_int8_t tcpdiag_ext; 39 | struct tcpdiag_sockid id; 40 | u_int32_t tcpdiag_states; 41 | u_int32_t tcpdiag_dbs; 42 | }; 43 | 44 | struct tcpdiagmsg { 45 | u_int8_t tcpdiag_family; 46 | u_int8_t tcpdiag_state; 47 | u_int8_t tcpdiag_timer; 48 | u_int8_t tcpdiag_retrans; 49 | struct tcpdiag_sockid id; 50 | u_int32_t tcpdiag_expires; 51 | u_int32_t tcpdiag_rqueue; 52 | u_int32_t tcpdiag_wqueue; 53 | u_int32_t tcpdiag_uid; 54 | u_int32_t tcpdiag_inode; 55 | }; 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /src/oidentd.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** oidentd.c - oidentd Ident (RFC 1413) implementation. 3 | ** Copyright (c) 1998-2006 Ryan McCabe 4 | ** Copyright (c) 2018-2019 Janik Rabe 5 | ** 6 | ** This program is free software; you can redistribute it and/or modify 7 | ** it under the terms of the GNU General Public License, version 2, 8 | ** as published by the Free Software Foundation. 9 | ** 10 | ** This program is distributed in the hope that it will be useful, 11 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ** GNU General Public License for more details. 14 | ** 15 | ** You should have received a copy of the GNU General Public License 16 | ** along with this program; if not, write to the Free Software 17 | ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #define _GNU_SOURCE 21 | 22 | #include 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | 41 | #include "oidentd.h" 42 | #include "util.h" 43 | #include "missing.h" 44 | #include "inet_util.h" 45 | #include "user_db.h" 46 | #include "options.h" 47 | #include "masq.h" 48 | 49 | #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION 50 | static void sig_segv(int unused __notused) __noreturn; 51 | static void sig_child(int sig); 52 | static void sig_alarm(int unused __notused) __noreturn; 53 | static void sig_hup(int unused); 54 | #endif 55 | 56 | static void copy_pw(const struct passwd *pw, struct passwd *pwd); 57 | static void free_pw(struct passwd *pwd); 58 | 59 | static int service_request(int insock, int outsock); 60 | 61 | u_int32_t timeout = DEFAULT_TIMEOUT; 62 | u_int32_t connection_limit; 63 | u_int32_t current_connections = 0; 64 | 65 | uid_t target_uid; 66 | gid_t target_gid; 67 | 68 | char *ret_os; 69 | char *failuser; 70 | char *replyall; 71 | char *config_file; 72 | 73 | in_port_t listen_port; 74 | struct sockaddr_storage **addr; 75 | 76 | int main(int argc, char **argv) { 77 | int *listen_fds = NULL; 78 | 79 | if (get_options(argc, argv) != 0) 80 | exit(EXIT_FAILURE); 81 | 82 | openlog(PACKAGE_NAME, LOG_PID | LOG_CONS | LOG_NDELAY, LOG_DAEMON); 83 | 84 | if (!replyall && read_config(config_file) != 0) { 85 | o_log(LOG_CRIT, "Fatal: Error reading configuration file"); 86 | exit(EXIT_FAILURE); 87 | } 88 | 89 | if (!replyall && core_init() != 0) { 90 | if (opt_enabled(DEBUG_MSGS)) { 91 | o_log(LOG_CRIT, "Fatal: Error initializing core"); 92 | } else { 93 | o_log(LOG_CRIT, "Fatal: Error initializing core (try --debug)"); 94 | } 95 | exit(EXIT_FAILURE); 96 | } 97 | 98 | if (!opt_enabled(STDIO)) { 99 | listen_fds = setup_listen(addr, htons(listen_port)); 100 | if (!listen_fds || listen_fds[0] == -1) { 101 | o_log(LOG_CRIT, "Fatal: Unable to set up listening socket"); 102 | o_log(LOG_CRIT, " (try running " PACKAGE_NAME " as root)"); 103 | exit(EXIT_FAILURE); 104 | } 105 | } 106 | 107 | if (!opt_enabled(FOREGROUND)) { 108 | if (opt_enabled(NOSYSLOG)) { 109 | o_log(LOG_CRIT, "Warning: Running in background with --nosyslog set;" 110 | " logs will be discarded"); 111 | } 112 | 113 | if (go_background() == -1) { 114 | o_log(LOG_CRIT, "Fatal: Error creating daemon process"); 115 | exit(EXIT_FAILURE); 116 | } 117 | } 118 | 119 | if (!replyall && k_open() != 0) { 120 | o_log(LOG_CRIT, "Fatal: Unable to initialize kernel module: %s", strerror(errno)); 121 | exit(EXIT_FAILURE); 122 | } 123 | 124 | if (drop_privs(target_uid, target_gid) == -1) { 125 | o_log(LOG_CRIT, "Fatal: Failed to drop privileges (global)"); 126 | exit(EXIT_FAILURE); 127 | } 128 | 129 | #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION 130 | signal(SIGALRM, sig_alarm); 131 | signal(SIGCHLD, sig_child); 132 | signal(SIGHUP, sig_hup); 133 | signal(SIGSEGV, sig_segv); 134 | #endif 135 | 136 | if (opt_enabled(STDIO)) { 137 | service_request(fileno(stdin), fileno(stdout)); 138 | exit(EXIT_SUCCESS); 139 | } 140 | 141 | for (;;) { 142 | fd_set rfds; 143 | int ret; 144 | size_t fdlen = 0; 145 | 146 | FD_ZERO(&rfds); 147 | 148 | do { 149 | int fd = listen_fds[fdlen++]; 150 | FD_SET(fd, &rfds); 151 | } while (listen_fds[fdlen] != -1); 152 | 153 | ret = select(listen_fds[fdlen - 1] + 1, &rfds, NULL, NULL, NULL); 154 | if (ret > 0) { 155 | size_t i; 156 | 157 | for (i = 0; i < fdlen; ++i) { 158 | if (FD_ISSET(listen_fds[i], &rfds)) { 159 | int connectfd; 160 | pid_t child; 161 | 162 | connectfd = accept(listen_fds[i], NULL, NULL); 163 | if (connectfd == -1) { 164 | debug("accept: %s", strerror(errno)); 165 | continue; 166 | } 167 | 168 | if (current_connections >= connection_limit) { 169 | o_log(LOG_INFO, "Connection limit exceeded; " 170 | "closing incoming connection"); 171 | close(connectfd); 172 | continue; 173 | } 174 | 175 | ++current_connections; 176 | 177 | child = fork(); 178 | 179 | if (child == -1) { 180 | o_log(LOG_CRIT, "Failed to fork: %s", strerror(errno)); 181 | } else if (child == 0) { 182 | size_t idx; 183 | 184 | for (idx = 0; listen_fds[idx] != -1; ++idx) 185 | close(listen_fds[idx]); 186 | 187 | free(listen_fds); 188 | alarm(timeout); 189 | service_request(connectfd, connectfd); 190 | 191 | exit(EXIT_SUCCESS); 192 | } 193 | 194 | close(connectfd); 195 | } 196 | } 197 | } 198 | } 199 | } 200 | 201 | /* 202 | ** Handle the client's request: read the client data and send the Ident reply. 203 | */ 204 | 205 | static int service_request(int insock, int outsock) { 206 | int len; 207 | int ret; 208 | uid_t con_uid; 209 | int lport_temp; 210 | int fport_temp; 211 | in_port_t lport; 212 | in_port_t fport; 213 | char line[128]; 214 | char suser[MAX_ULEN]; 215 | char host_buf[MAX_HOSTLEN]; 216 | char ip_buf[MAX_IPLEN]; 217 | struct sockaddr_storage laddr, laddr6, faddr, faddr6; 218 | struct passwd *pw, pwd; 219 | 220 | #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION 221 | in_addr_t fuzz_faddr, fuzz_laddr; 222 | (void) inet_pton(AF_INET, "192.0.2.1", &fuzz_faddr); 223 | (void) inet_pton(AF_INET, "127.0.0.1", &fuzz_laddr); 224 | sin_setv4(fuzz_faddr, &faddr); 225 | sin_setv4(fuzz_laddr, &laddr); 226 | sin_set_port(49152, &faddr); 227 | sin_set_port(113, &faddr); 228 | #else 229 | static socklen_t socklen = sizeof(struct sockaddr_storage); 230 | 231 | if (getpeername(insock, (struct sockaddr *) &faddr, &socklen) != 0) { 232 | debug("getpeername: %s", strerror(errno)); 233 | return -1; 234 | } 235 | 236 | if (getsockname(insock, (struct sockaddr *) &laddr, &socklen) != 0) { 237 | debug("getsockname: %s", strerror(errno)); 238 | return -1; 239 | } 240 | #endif 241 | 242 | fport = htons(sin_port(&faddr)); 243 | 244 | #if WANT_IPV6 245 | laddr6 = laddr; 246 | faddr6 = faddr; 247 | 248 | if (laddr.ss_family == AF_INET6 && 249 | IN6_IS_ADDR_V4MAPPED(&SIN6(&laddr)->sin6_addr)) 250 | { 251 | struct in_addr in4; 252 | 253 | sin_extractv4(&SIN6(&laddr)->sin6_addr, &in4); 254 | sin_setv4(in4.s_addr, &laddr); 255 | 256 | sin_extractv4(&SIN6(&faddr)->sin6_addr, &in4); 257 | sin_setv4(in4.s_addr, &faddr); 258 | } 259 | #endif 260 | 261 | get_ip(&faddr, ip_buf, sizeof(ip_buf)); 262 | 263 | if (get_hostname(&faddr, host_buf, sizeof(host_buf)) != 0) { 264 | o_log(LOG_INFO, "Connection from %s:%d", ip_buf, fport); 265 | xstrncpy(host_buf, ip_buf, sizeof(host_buf)); 266 | } else 267 | o_log(LOG_INFO, "Connection from %s (%s):%d", host_buf, ip_buf, fport); 268 | 269 | if (!sock_read(insock, line, sizeof(line))) 270 | return -1; 271 | 272 | len = sscanf(line, "%d , %d", &lport_temp, &fport_temp); 273 | if (len < 2) { 274 | debug("[%s] Malformed request: \"%s\"", host_buf, line); 275 | return 0; 276 | } 277 | 278 | if (!VALID_PORT(lport_temp) || !VALID_PORT(fport_temp)) { 279 | sockprintf(outsock, "%d,%d:ERROR:%s\r\n", 280 | lport_temp, fport_temp, ERROR("INVALID-PORT")); 281 | 282 | debug("[%s] %d , %d : ERROR : INVALID-PORT", 283 | host_buf, lport_temp, fport_temp); 284 | 285 | return 0; 286 | } 287 | 288 | if (replyall) { 289 | sockprintf(outsock, "%d,%d:USERID:%s:%s\r\n", 290 | lport_temp, fport_temp, ret_os, replyall); 291 | 292 | o_log(LOG_INFO, "[%s] Static reply: %d , %d : (returned %s)", 293 | host_buf, lport_temp, fport_temp, replyall); 294 | 295 | return 0; 296 | } 297 | 298 | lport = (in_port_t) lport_temp; 299 | fport = (in_port_t) fport_temp; 300 | 301 | /* User ID is unknown. */ 302 | con_uid = MISSING_UID; 303 | 304 | if (con_uid == MISSING_UID && laddr.ss_family == AF_INET) 305 | con_uid = get_user4(htons(lport), htons(fport), &laddr, &faddr); 306 | 307 | #if WANT_IPV6 308 | /* 309 | * Check for IPv6-mapped IPv4 addresses. This ensures that the correct 310 | * Ident response is returned for connections to a mapped address. 311 | */ 312 | if (con_uid == MISSING_UID && laddr.ss_family == AF_INET) { 313 | struct sockaddr_storage laddr_m6, faddr_m6; 314 | struct in6_addr in6; 315 | 316 | sin_mapv4to6(&SIN4(&laddr)->sin_addr, &in6); 317 | sin_setv6(&in6, &laddr_m6); 318 | 319 | sin_mapv4to6(&SIN4(&faddr)->sin_addr, &in6); 320 | sin_setv6(&in6, &faddr_m6); 321 | 322 | con_uid = get_user6(htons(lport), htons(fport), &laddr_m6, &faddr_m6); 323 | } 324 | 325 | if (con_uid == MISSING_UID && laddr6.ss_family == AF_INET6) 326 | con_uid = get_user6(htons(lport), htons(fport), &laddr6, &faddr6); 327 | #endif 328 | 329 | if (opt_enabled(MASQ)) { 330 | if (con_uid == MISSING_UID && laddr.ss_family == AF_INET) 331 | if (masq(insock, htons(lport), htons(fport), &laddr, &faddr) == 0) 332 | return 0; 333 | } 334 | 335 | if (con_uid == MISSING_UID) { 336 | if (failuser) { 337 | sockprintf(outsock, "%d,%d:USERID:%s:%s\r\n", 338 | lport, fport, ret_os, failuser); 339 | 340 | o_log(LOG_INFO, "[%s] Failed lookup: %d , %d : (returned %s)", 341 | host_buf, lport, fport, failuser); 342 | } else { 343 | sockprintf(outsock, "%d,%d:ERROR:%s\r\n", 344 | lport, fport, ERROR("NO-USER")); 345 | 346 | o_log(LOG_INFO, "[%s] %d , %d : ERROR : NO-USER", 347 | host_buf, lport, fport); 348 | } 349 | 350 | return 0; 351 | } 352 | 353 | pw = getpwuid(con_uid); 354 | if (!pw) { 355 | sockprintf(outsock, "%d,%d:ERROR:%s\r\n", 356 | lport, fport, ERROR("NO-USER")); 357 | 358 | debug("getpwuid(%lu): %s", (unsigned long) con_uid, strerror(errno)); 359 | return 0; 360 | } else 361 | copy_pw(pw, &pwd); 362 | 363 | if (seed_prng() != 0) { 364 | o_log(LOG_CRIT, "Failed to seed PRNG"); 365 | goto out_fail; 366 | } 367 | 368 | ret = get_ident(&pwd, lport, fport, &laddr, &faddr, suser, sizeof(suser)); 369 | if (ret == -1) { 370 | sockprintf(outsock, "%d,%d:ERROR:%s\r\n", 371 | lport, fport, ERROR("HIDDEN-USER")); 372 | 373 | o_log(LOG_INFO, "[%s] %d , %d : HIDDEN-USER (%s)", 374 | host_buf, lport, fport, pwd.pw_name); 375 | 376 | goto out; 377 | } 378 | 379 | sockprintf(outsock, "%d,%d:USERID:%s:%s\r\n", 380 | lport, fport, ret_os, suser); 381 | 382 | o_log(LOG_INFO, "[%s] Successful lookup: %d , %d : %s (%s)", 383 | host_buf, lport, fport, pwd.pw_name, suser); 384 | 385 | out: 386 | free_pw(&pwd); 387 | return 0; 388 | 389 | out_fail: 390 | free_pw(&pwd); 391 | return -1; 392 | } 393 | 394 | /* 395 | ** Copy the needed fields from a passwd struct. 396 | */ 397 | 398 | static void copy_pw(const struct passwd *pw, struct passwd *pwd) { 399 | pwd->pw_name = xstrdup(pw->pw_name); 400 | pwd->pw_uid = pw->pw_uid; 401 | pwd->pw_gid = pw->pw_gid; 402 | pwd->pw_dir = xstrdup(pw->pw_dir); 403 | } 404 | 405 | /* 406 | ** Free a copied passwd struct. 407 | */ 408 | 409 | static void free_pw(struct passwd *pw) { 410 | free(pw->pw_name); 411 | free(pw->pw_dir); 412 | } 413 | 414 | #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION 415 | /* 416 | ** Handle SIGSEGV. 417 | */ 418 | 419 | static void sig_segv(int unused __notused) { 420 | o_log(LOG_CRIT, "Caught SIGSEGV; please report this to " PACKAGE_BUGREPORT); 421 | exit(EXIT_FAILURE); 422 | } 423 | 424 | /* 425 | ** Handle SIGCHLD. 426 | */ 427 | 428 | static void sig_child(int sig) { 429 | while (waitpid(-1, &sig, WNOHANG) > 0) 430 | --current_connections; 431 | 432 | signal(SIGCHLD, sig_child); 433 | } 434 | 435 | /* 436 | ** Handle SIGALRM. 437 | */ 438 | 439 | static void sig_alarm(int unused __notused) { 440 | o_log(LOG_INFO, "Request timed out; closing connection"); 441 | exit(EXIT_SUCCESS); 442 | } 443 | 444 | /* 445 | ** Handle SIGHUP - This causes oidentd to reload its configuration file. 446 | */ 447 | 448 | static void sig_hup(int unused __notused) { 449 | if (replyall) { 450 | /* 451 | * Configuration file was never loaded; don't try to reload it. 452 | */ 453 | return; 454 | } 455 | 456 | user_db_destroy(); 457 | 458 | if (read_config(CONFFILE) != 0) { 459 | o_log(LOG_CRIT, "Error parsing configuration file"); 460 | exit(EXIT_FAILURE); 461 | } 462 | } 463 | #endif 464 | -------------------------------------------------------------------------------- /src/oidentd.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** oidentd.h - oidentd Ident (RFC 1413) implementation. 3 | ** Copyright (c) 1998-2006 Ryan McCabe 4 | ** Copyright (c) 2018-2019 Janik Rabe 5 | ** 6 | ** This program is free software; you can redistribute it and/or modify 7 | ** it under the terms of the GNU General Public License, version 2, 8 | ** as published by the Free Software Foundation. 9 | ** 10 | ** This program is distributed in the hope that it will be useful, 11 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ** GNU General Public License for more details. 14 | ** 15 | ** You should have received a copy of the GNU General Public License 16 | ** along with this program; if not, write to the Free Software 17 | ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #ifndef __OIDENTD_H_ 21 | #define __OIDENTD_H_ 22 | 23 | #ifndef SYSCONFDIR 24 | #define SYSCONFDIR "/etc" 25 | #endif 26 | 27 | /* 28 | ** File containing the Ident replies to be used for hosts that 29 | ** masquerade through us. 30 | */ 31 | 32 | #define MASQ_MAP SYSCONFDIR "/oidentd_masq.conf" 33 | 34 | /* 35 | ** String prepended to a random number when the random_numeric capability is 36 | ** used. 37 | */ 38 | 39 | #define UPREFIX "user" 40 | 41 | /* 42 | ** System-wide configuration file. 43 | */ 44 | 45 | #define CONFFILE SYSCONFDIR "/oidentd.conf" 46 | 47 | /* 48 | ** Per-user configuration file. This file is relative to the user's 49 | ** home directory. 50 | */ 51 | 52 | #if XDGBDIR_SUPPORT 53 | # define USER_CONF_XDG ".config/oidentd.conf" 54 | #endif 55 | 56 | #define USER_CONF ".oidentd.conf" 57 | 58 | /* 59 | ** Maximum length of Ident replies. 60 | */ 61 | 62 | #define MAX_ULEN 512 63 | 64 | /* 65 | ** Exclusive upper limit for numbers generated by the "random_numeric" 66 | ** capability. 67 | */ 68 | 69 | #define RANDOM_NUMERIC_UPPER_EXCL 100000 70 | 71 | /* 72 | ** Maximum number of random replies -- the number of strings that 73 | ** may follow "reply" statements. 74 | */ 75 | 76 | #define MAX_RANDOM_REPLIES 20 77 | 78 | /* 79 | ** The default UID and GID, respectively, that oidentd will 80 | ** run with. 81 | */ 82 | 83 | #define DEFAULT_UID 65534UL 84 | #define DEFAULT_GID 65534UL 85 | 86 | /* 87 | ** Default port oidentd runs on and default forward port. 88 | ** 89 | ** If you're going to change these default ports, be sure to make them a 90 | ** string (eg. "113" not 113). 91 | */ 92 | 93 | #define DEFAULT_PORT "113" 94 | #define DEFAULT_FPORT "113" 95 | 96 | /* 97 | ** The amount of time oidentd will wait for client input 98 | ** before it drops the connection. 99 | */ 100 | 101 | #define DEFAULT_TIMEOUT 30 102 | 103 | /* 104 | ** Nothing below here should need to be changed. 105 | */ 106 | 107 | #define DEFAULT_UMASK 0022 108 | 109 | #define MAX_HOSTLEN 256 110 | 111 | #ifndef INET_ADDRSTRLEN 112 | # define INET_ADDRSTRLEN 16 113 | #endif 114 | 115 | #if WANT_IPV6 116 | # ifndef INET6_ADDRSTRLEN 117 | # define INET6_ADDRSTRLEN 46 118 | # endif 119 | # if INET6_ADDRSTRLEN < 46 120 | # error "INET6_ADDRSTRLEN is too small" 121 | # endif 122 | # define MAX_IPLEN INET6_ADDRSTRLEN 123 | # define IP_SCAN_SPEC "%45s" 124 | #else 125 | # if INET_ADDRSTRLEN < 16 126 | # error "INET_ADDRSTRLEN is too small" 127 | # endif 128 | # define MAX_IPLEN INET_ADDRSTRLEN 129 | # define IP_SCAN_SPEC "%15s" 130 | #endif 131 | 132 | #define PORT_MAX 0xffff 133 | #define PORT_MIN 1 134 | 135 | /* 136 | ** POSIX reserves these UID and GID values for this purpose. 137 | */ 138 | 139 | #define MISSING_UID ((uid_t) -1) 140 | #define MISSING_GID ((gid_t) -1) 141 | 142 | #define VALID_PORT(p) ((p) >= PORT_MIN && ((p) & PORT_MAX) == (p)) 143 | #define ERROR(x) (opt_enabled(HIDE_ERRORS) ? "UNKNOWN-ERROR" : (x)) 144 | 145 | #if ENABLE_DEBUGGING 146 | # define debug(format, args...) do { o_log(LOG_DEBUG, "[%s:%u:%s] DEBUG: " format, __FILE__, __LINE__, __FUNCTION__, ##args); } while (0) 147 | #else 148 | # define debug(format, args...) do { } while (0) 149 | #endif 150 | 151 | #ifdef HAVE___ATTRIBUTE__UNUSED 152 | #define __notused __attribute__((unused)) 153 | #else 154 | #define __notused 155 | #endif 156 | 157 | #ifdef HAVE___ATTRIBUTE__NORETURN 158 | #define __noreturn __attribute__((noreturn)) 159 | #else 160 | #define __noreturn 161 | #endif 162 | 163 | #ifdef HAVE___ATTRIBUTE__FORMAT 164 | #define __format(x) __attribute__((format x )) 165 | #else 166 | #define __format(x) 167 | #endif 168 | 169 | #ifdef HAVE_STDBOOL_H 170 | # include 171 | #else 172 | typedef enum { 173 | false = 0, 174 | true = 1 175 | } bool; 176 | #endif 177 | 178 | /* 179 | ** Open the kernel memory device. 180 | ** Return 0 on success, or -1 with errno set. 181 | */ 182 | 183 | int k_open(void); 184 | 185 | #ifndef HAVE_STRUCT_SOCKADDR_STORAGE 186 | 187 | struct sockaddr_storage { 188 | struct sockaddr __ss_sockaddr; 189 | char __ss_pad[128 - sizeof(struct sockaddr)]; 190 | }; 191 | 192 | # define ss_family __ss_sockaddr.sa_family 193 | 194 | #endif 195 | 196 | #ifdef HAVE___SS_FAMILY 197 | #define ss_family __ss_family 198 | #endif 199 | 200 | /* 201 | ** System-dependent initialization; called only once. 202 | ** Called before privileges are dropped. 203 | ** Returns non-zero on failure. 204 | */ 205 | 206 | int core_init(void); 207 | 208 | /* 209 | ** Returns the UID of the owner of an IPv4 connection, 210 | ** or MISSING_UID on failure. 211 | */ 212 | 213 | uid_t get_user4( in_port_t lport, 214 | in_port_t fport, 215 | struct sockaddr_storage *laddr, 216 | struct sockaddr_storage *faddr); 217 | 218 | /* 219 | ** Returns the UID of the owner of an IPv6 connection, 220 | ** or MISSING_UID on failure. 221 | */ 222 | 223 | uid_t get_user6( in_port_t lport, 224 | in_port_t fport, 225 | struct sockaddr_storage *laddr, 226 | struct sockaddr_storage *faddr); 227 | 228 | int read_config(const char *config_file); 229 | 230 | #endif 231 | -------------------------------------------------------------------------------- /src/options.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** options.h - oidentd command-line handler. 3 | ** Copyright (c) 2001-2006 Ryan McCabe 4 | ** Copyright (c) 2018-2019 Janik Rabe 5 | ** 6 | ** This program is free software; you can redistribute it and/or modify 7 | ** it under the terms of the GNU General Public License, version 2, 8 | ** as published by the Free Software Foundation. 9 | ** 10 | ** This program is distributed in the hope that it will be useful, 11 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ** GNU General Public License for more details. 14 | ** 15 | ** You should have received a copy of the GNU General Public License 16 | ** along with this program; if not, write to the Free Software 17 | ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #ifndef __OIDENTD_OPTIONS_H_ 21 | #define __OIDENTD_OPTIONS_H_ 22 | 23 | #define _GNU_SOURCE 24 | 25 | #define CHANGE_UID (1 << 0x00) 26 | #define CHANGE_GID (1 << 0x01) 27 | #define HIDE_ERRORS (1 << 0x02) 28 | #define MASQ (1 << 0x03) 29 | #define FORWARD (1 << 0x04) 30 | #define PROXY (1 << 0x05) 31 | #define DEBUG_MSGS (1 << 0x06) 32 | #define QUIET (1 << 0x07) 33 | #define FOREGROUND (1 << 0x08) 34 | #define NOSYSLOG (1 << 0x09) 35 | #define STDIO (1 << 0x0a) 36 | #define MASQ_OVERRIDE (1 << 0x0b) 37 | 38 | #ifndef LIBNFCT_SUPPORT 39 | #define LIBNFCT_SUPPORT 0 40 | #endif 41 | 42 | bool opt_enabled(u_int32_t option); 43 | void disable_opt(u_int32_t option); 44 | int get_options(int argc, char *const argv[]); 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /src/user_db.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** user_db.h - oidentd user database routines. 3 | ** Copyright (c) 2001-2006 Ryan McCabe 4 | ** Copyright (c) 2018-2019 Janik Rabe 5 | ** 6 | ** This program is free software; you can redistribute it and/or modify 7 | ** it under the terms of the GNU General Public License, version 2, 8 | ** as published by the Free Software Foundation. 9 | ** 10 | ** This program is distributed in the hope that it will be useful, 11 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ** GNU General Public License for more details. 14 | ** 15 | ** You should have received a copy of the GNU General Public License 16 | ** along with this program; if not, write to the Free Software 17 | ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #ifndef __OIDENTD_USER_DB_H 21 | #define __OIDENTD_USER_DB_H 22 | 23 | #define PARSE_USER 0x00 24 | #define PARSE_SYSTEM 0x01 25 | 26 | #define ACTION_DENY 0x00 27 | #define ACTION_ALLOW 0x01 28 | #define ACTION_FORCE 0x02 29 | 30 | #define CAP_SPOOF (1 << 0x00) 31 | #define CAP_SPOOF_ALL (1 << 0x01) 32 | #define CAP_SPOOF_PRIVPORT (1 << 0x02) 33 | #define CAP_HIDE (1 << 0x03) 34 | #define CAP_RANDOM (1 << 0x04) 35 | #define CAP_RANDOM_NUMERIC (1 << 0x05) 36 | #define CAP_NUMERIC (1 << 0x06) 37 | #define CAP_REPLY (1 << 0x07) 38 | #define CAP_FORWARD (1 << 0x08) 39 | 40 | #define DB_HASH_SIZE 32 41 | 42 | struct user_cap { 43 | struct port_range { 44 | in_port_t min; 45 | in_port_t max; 46 | } *lport, *fport; 47 | 48 | struct sockaddr_storage *src; 49 | struct sockaddr_storage *dest; 50 | 51 | u_int16_t caps; 52 | u_int16_t action; 53 | 54 | union user_cap_data { 55 | struct replies_data { 56 | char **data; 57 | u_int8_t num; 58 | } replies; 59 | struct forward_data { 60 | struct sockaddr_storage *host; 61 | in_port_t port; 62 | } forward; 63 | } data; 64 | }; 65 | 66 | struct user_info { 67 | uid_t user; 68 | list_t *cap_list; 69 | }; 70 | 71 | struct user_info *user_db_lookup(uid_t uid); 72 | void user_db_add(struct user_info *user_info); 73 | void user_db_destroy(void); 74 | void user_db_cap_destroy_data(void *data); 75 | void user_db_set_default(struct user_info *user_info); 76 | struct user_info *user_db_create_default(void); 77 | 78 | int get_ident( const struct passwd *pwd, 79 | in_port_t lport, 80 | in_port_t fport, 81 | struct sockaddr_storage *laddr, 82 | struct sockaddr_storage *faddr, 83 | char *reply, 84 | size_t len); 85 | 86 | list_t *user_db_get_pref_list(const struct passwd *pw); 87 | 88 | #endif 89 | -------------------------------------------------------------------------------- /src/util.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** util.c - oidentd utility functions. 3 | ** Copyright (c) 2001-2006 Ryan McCabe 4 | ** Copyright (c) 2018-2019 Janik Rabe 5 | ** 6 | ** This program is free software; you can redistribute it and/or modify 7 | ** it under the terms of the GNU General Public License, version 2, 8 | ** as published by the Free Software Foundation. 9 | ** 10 | ** This program is distributed in the hope that it will be useful, 11 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ** GNU General Public License for more details. 14 | ** 15 | ** You should have received a copy of the GNU General Public License 16 | ** along with this program; if not, write to the Free Software 17 | ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #define _GNU_SOURCE 21 | #include 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | 44 | #include "oidentd.h" 45 | #include "util.h" 46 | #include "inet_util.h" 47 | #include "missing.h" 48 | #include "options.h" 49 | 50 | #ifdef HAVE_ARC4RANDOM_UNIFORM 51 | /* no rescale required */ 52 | #elif defined HAVE_LRAND48 53 | # define O_RAND_UPPER_EXCL_UL (1UL << 31) 54 | #else 55 | # define O_RAND_UPPER_EXCL_UL ((unsigned long) RAND_MAX + 1UL) 56 | #endif 57 | 58 | /* 59 | ** Seed the PRNG. 60 | ** A time-based seed is sufficient as oidentd does not require 61 | ** cryptographically secure random numbers. 62 | ** Returns 0 on success, -1 on failure. 63 | */ 64 | 65 | int seed_prng(void) { 66 | #ifndef HAVE_ARC4RANDOM_UNIFORM 67 | # ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION 68 | struct timespec tp; 69 | 70 | if (clock_gettime(CLOCK_REALTIME, &tp)) { 71 | debug("clock_gettime: %s", strerror(errno)); 72 | return -1; 73 | } 74 | # endif 75 | #endif 76 | 77 | #ifdef HAVE_ARC4RANDOM_UNIFORM 78 | /* automatically reseeded upon fork(2) */ 79 | #elif defined HAVE_LRAND48 80 | # ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION 81 | srand48(0); 82 | # else 83 | srand48((long) (tp.tv_sec ^ tp.tv_nsec)); 84 | # endif 85 | #elif defined HAVE_RANDOM 86 | # ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION 87 | srandom(0); 88 | # else 89 | srandom((unsigned int) (tp.tv_sec ^ tp.tv_nsec)); 90 | # endif 91 | #else 92 | # ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION 93 | srand(0); 94 | # else 95 | srand((unsigned int) (tp.tv_sec ^ tp.tv_nsec)); 96 | # endif 97 | #endif 98 | 99 | return 0; 100 | } 101 | 102 | #ifndef HAVE_ARC4RANDOM_UNIFORM 103 | 104 | /* 105 | ** Return a pseudorandom integer in the interval [0, O_RAND_UPPER_EXCL_UL). 106 | */ 107 | unsigned long prng_next(void) { 108 | #ifdef HAVE_LRAND48 109 | return (unsigned long) lrand48(); 110 | #elif defined HAVE_RANDOM 111 | return (unsigned long) random(); 112 | #else 113 | return (unsigned long) rand(); 114 | #endif 115 | } 116 | #endif 117 | 118 | /* 119 | ** Return a pseudorandom integer in the interval [0, i). 120 | */ 121 | 122 | unsigned int randval(unsigned int i) { 123 | #ifdef HAVE_ARC4RANDOM_UNIFORM 124 | return (unsigned int) arc4random_uniform((uint32_t) i); 125 | #else 126 | unsigned long blk_size = O_RAND_UPPER_EXCL_UL / (unsigned long) i; 127 | unsigned long blk_after_last = blk_size * (unsigned long) i; 128 | unsigned long next; 129 | 130 | do { 131 | next = prng_next(); 132 | } while (next >= blk_after_last); 133 | 134 | return (unsigned int) (next / blk_size); 135 | #endif 136 | } 137 | 138 | /* 139 | ** Find the user specified by "temp_user" 140 | ** Returns non-zero on failure. 141 | */ 142 | 143 | int find_user(const char *temp_user, uid_t *uid) { 144 | struct passwd *pw; 145 | 146 | pw = getpwnam(temp_user); 147 | if (!pw) { 148 | char *end; 149 | unsigned long int temp_uid = strtoul(temp_user, &end, 10); 150 | 151 | if (*end != '\0') 152 | return -1; 153 | 154 | if (temp_uid >= MISSING_UID) 155 | return -1; 156 | 157 | *uid = (uid_t) temp_uid; 158 | } else { 159 | *uid = pw->pw_uid; 160 | } 161 | 162 | return 0; 163 | } 164 | 165 | /* 166 | ** Find the group specified by "temp_group" 167 | ** Returns non-zero on failure. 168 | */ 169 | 170 | int find_group(const char *temp_group, gid_t *gid) { 171 | struct group *gr; 172 | 173 | gr = getgrnam(temp_group); 174 | if (!gr) { 175 | char *end; 176 | unsigned long int temp_gid = strtoul(temp_group, &end, 10); 177 | 178 | if (*end != '\0') 179 | return -1; 180 | 181 | if (temp_gid >= MISSING_GID) 182 | return -1; 183 | 184 | *gid = (gid_t) temp_gid; 185 | } else { 186 | *gid = gr->gr_gid; 187 | } 188 | 189 | return 0; 190 | } 191 | 192 | /* 193 | ** Drop privileges and run with specified UID/GID. 194 | ** Returns 0 on success, -1 on failure. 195 | */ 196 | 197 | int drop_privs(uid_t new_uid, gid_t new_gid) { 198 | if (opt_enabled(CHANGE_GID)) { 199 | if (setgid(new_gid) != 0) { 200 | debug("setgid(%lu): %s", (unsigned long) new_gid, strerror(errno)); 201 | return -1; 202 | } 203 | 204 | #ifdef HAVE_SETGROUPS 205 | if (setgroups(0, NULL)) { 206 | debug("setgroups: %s", strerror(errno)); 207 | return -1; 208 | } 209 | #endif 210 | } 211 | 212 | if (opt_enabled(CHANGE_UID)) { 213 | struct passwd *pw; 214 | gid_t my_gid; 215 | int ret; 216 | 217 | pw = getpwuid(new_uid); 218 | if (!pw) { 219 | debug("getpwuid(%lu): No such user ID", (unsigned long) new_uid); 220 | return -1; 221 | } 222 | 223 | if (opt_enabled(CHANGE_GID)) 224 | my_gid = new_gid; 225 | else 226 | my_gid = pw->pw_gid; 227 | 228 | ret = initgroups(pw->pw_name, my_gid); 229 | 230 | if (ret != 0) { 231 | debug("initgroups(%s, %lu): %s", pw->pw_name, (unsigned long) my_gid, 232 | strerror(errno)); 233 | return -1; 234 | } 235 | 236 | if (setuid(new_uid) != 0) { 237 | debug("setuid(%lu): %s", (unsigned long) new_uid, strerror(errno)); 238 | return -1; 239 | } 240 | } 241 | 242 | return 0; 243 | } 244 | 245 | /* 246 | ** Safely open "filename" which is located in the home directory 247 | ** of the user specified by "pw." This function is safe with respect 248 | ** to stat/open races. Only files owned by the user specified by "pw" 249 | ** will be opened. 250 | ** 251 | ** Returns a pointer to the FILE struct returned by fopen on success, 252 | ** NULL on failure. 253 | */ 254 | 255 | FILE *safe_open(const struct passwd *pw, const char *filename) { 256 | size_t len; 257 | char *path; 258 | struct stat st; 259 | FILE *fp; 260 | 261 | len = strlen(pw->pw_dir) + strlen(filename) + 2; 262 | 263 | path = xmalloc(len); 264 | snprintf(path, len, "%s/%s", pw->pw_dir, filename); 265 | 266 | if (stat(path, &st) != 0) 267 | goto out_fail; 268 | 269 | if (st.st_uid != pw->pw_uid) { 270 | o_log(LOG_CRIT, 271 | "Refused to read %s during request for %s (owner is UID %lu)", 272 | path, pw->pw_name, (unsigned long) st.st_uid); 273 | 274 | goto out_fail; 275 | } 276 | 277 | fp = fopen(path, "r"); 278 | if (!fp) { 279 | if (errno != ENOENT) 280 | debug("open: %s: %s", path, strerror(errno)); 281 | 282 | goto out_fail; 283 | } 284 | 285 | if (fstat(fileno(fp), &st) != 0) { 286 | debug("stat: %s: %s", path, strerror(errno)); 287 | 288 | fclose(fp); 289 | goto out_fail; 290 | } 291 | 292 | if (st.st_uid != pw->pw_uid) { 293 | o_log(LOG_CRIT, 294 | "Refused to read %s during request for %s (owner is UID %lu)", 295 | path, pw->pw_name, (unsigned long) st.st_uid); 296 | 297 | fclose(fp); 298 | goto out_fail; 299 | } 300 | 301 | free(path); 302 | return fp; 303 | 304 | out_fail: 305 | free(path); 306 | return NULL; 307 | } 308 | 309 | /* 310 | ** Go background. 311 | */ 312 | 313 | int go_background(void) { 314 | int fd; 315 | 316 | switch (fork()) { 317 | case -1: 318 | return -1; 319 | case 0: 320 | break; 321 | default: 322 | _exit(EXIT_SUCCESS); 323 | } 324 | 325 | if (setsid() == (pid_t) -1) { 326 | debug("setsid: %s", strerror(errno)); 327 | return -1; 328 | } 329 | 330 | if (chdir("/") != 0) { 331 | debug("chdir: %s", strerror(errno)); 332 | return -1; 333 | } 334 | 335 | umask(DEFAULT_UMASK); 336 | 337 | fd = open("/dev/null", O_RDWR); 338 | if (fd == -1) { 339 | debug("open: /dev/null: %s", strerror(errno)); 340 | return -1; 341 | } 342 | 343 | dup2(fd, 0); 344 | dup2(fd, 1); 345 | dup2(fd, 2); 346 | 347 | return 0; 348 | } 349 | 350 | /* 351 | ** Same as malloc(3), except exits on failure. 352 | */ 353 | 354 | void *xmalloc(size_t size) { 355 | void *ret = malloc(size); 356 | 357 | if (!ret) { 358 | o_log(LOG_CRIT, "Fatal: malloc: %s", strerror(errno)); 359 | exit(EXIT_FAILURE); 360 | } 361 | 362 | return ret; 363 | } 364 | 365 | /* 366 | ** Same as calloc(3), except exits on failure. 367 | */ 368 | 369 | void *xcalloc(size_t nmemb, size_t size) { 370 | void *ret = calloc(nmemb, size); 371 | 372 | if (!ret) { 373 | o_log(LOG_CRIT, "Fatal: calloc: %s", strerror(errno)); 374 | exit(EXIT_FAILURE); 375 | } 376 | 377 | return ret; 378 | } 379 | 380 | /* 381 | ** Same as realloc(3), except exits on failure. 382 | */ 383 | 384 | void *xrealloc(void *ptr, size_t len) { 385 | void *ret = realloc(ptr, len); 386 | 387 | if (!ret) { 388 | o_log(LOG_CRIT, "Fatal: realloc: %s", strerror(errno)); 389 | exit(EXIT_FAILURE); 390 | } 391 | 392 | return ret; 393 | } 394 | 395 | /* 396 | ** Copy at most n-1 characters from src to dest and NULL-terminate dest. 397 | ** Returns a pointer to the destination string. 398 | */ 399 | 400 | char *xstrncpy(char *dest, const char *src, size_t n) { 401 | char *ret = dest; 402 | 403 | if (n == 0) 404 | return dest; 405 | 406 | while (--n > 0 && (*dest++ = *src++) != '\0') 407 | ; 408 | 409 | *dest = '\0'; 410 | 411 | return ret; 412 | } 413 | 414 | /* 415 | ** Same as strdup(3), except exits on failure, and returns NULL 416 | ** if passed a NULL pointer. 417 | */ 418 | 419 | char *xstrdup(const char *string) { 420 | char *ret; 421 | 422 | if (!string) 423 | return NULL; 424 | 425 | ret = strdup(string); 426 | 427 | if (!ret) { 428 | o_log(LOG_CRIT, "Fatal: strdup: %s", strerror(errno)); 429 | exit(EXIT_FAILURE); 430 | } 431 | 432 | return ret; 433 | } 434 | 435 | /* 436 | ** Add a link for "new_data" to the front of the linked list, "list". 437 | ** Returns the new list. 438 | */ 439 | 440 | list_t *list_prepend(list_t **list, void *new_data) { 441 | list_t *new_entry = xmalloc(sizeof(list_t)); 442 | 443 | new_entry->next = *list; 444 | new_entry->data = new_data; 445 | *list = new_entry; 446 | 447 | return *list; 448 | } 449 | 450 | /* 451 | ** Destroy the linked list, "list" 452 | */ 453 | 454 | void list_destroy(list_t *list, void (*free_data)(void *)) { 455 | list_t *cur = list; 456 | 457 | while (cur) { 458 | list_t *next = cur->next; 459 | 460 | if (free_data) 461 | free_data(cur->data); 462 | 463 | free(cur); 464 | cur = next; 465 | } 466 | } 467 | 468 | /* 469 | ** Logging mechanism for oidentd. 470 | */ 471 | 472 | int o_log(int priority, const char *fmt, ...) { 473 | va_list ap; 474 | int ret; 475 | char *buf; 476 | 477 | if (opt_enabled(QUIET) && priority != LOG_CRIT) 478 | return 0; 479 | 480 | if (priority == LOG_DEBUG && !opt_enabled(DEBUG_MSGS)) 481 | return 0; 482 | 483 | va_start(ap, fmt); 484 | ret = vasprintf((char **) &buf, fmt, ap); 485 | va_end(ap); 486 | 487 | if (opt_enabled(NOSYSLOG) || isatty(fileno(stderr))) 488 | fprintf(stderr, "%s\n", buf); 489 | else 490 | syslog(priority, "%s", buf); 491 | 492 | free(buf); 493 | return ret; 494 | } 495 | -------------------------------------------------------------------------------- /src/util.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** util.h - oidentd utility functions. 3 | ** Copyright (c) 1998-2006 Ryan McCabe 4 | ** Copyright (c) 2018-2019 Janik Rabe 5 | ** 6 | ** This program is free software; you can redistribute it and/or modify 7 | ** it under the terms of the GNU General Public License, version 2, 8 | ** as published by the Free Software Foundation. 9 | ** 10 | ** This program is distributed in the hope that it will be useful, 11 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ** GNU General Public License for more details. 14 | ** 15 | ** You should have received a copy of the GNU General Public License 16 | ** along with this program; if not, write to the Free Software 17 | ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #ifndef __OIDENTD_UTIL_H 21 | #define __OIDENTD_UTIL_H 22 | 23 | #ifndef MIN 24 | # define MIN(x,y) ((x) < (y) ? (x) : (y)) 25 | #endif 26 | 27 | typedef struct list { 28 | struct list *next; 29 | void *data; 30 | } list_t; 31 | 32 | int o_log(int priority, const char *fmt, ...) __format((printf, 2, 3)); 33 | int drop_privs(uid_t new_uid, gid_t new_gid); 34 | int go_background(void); 35 | 36 | FILE *safe_open(const struct passwd *pw, const char *filename); 37 | 38 | void *xmalloc(size_t size); 39 | void *xcalloc(size_t nmemb, size_t size); 40 | void *xrealloc(void *ptr, size_t len); 41 | 42 | char *xstrncpy(char *dest, const char *src, size_t n); 43 | char *xstrdup(const char *string); 44 | 45 | list_t *list_prepend(list_t **list, void *new_data); 46 | void list_destroy(list_t *list, void (*free_data)(void *)); 47 | 48 | int find_user(const char *temp_user, uid_t *uid); 49 | int find_group(const char *temp_group, gid_t *gid); 50 | 51 | int seed_prng(void); 52 | unsigned long prng_next(void); 53 | unsigned int randval(unsigned int i); 54 | 55 | #endif 56 | --------------------------------------------------------------------------------