Initial commit.
This commit is contained in:
		
							
								
								
									
										64
									
								
								ChangeLog
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								ChangeLog
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,64 @@
 | 
			
		||||
20040906
 | 
			
		||||
	accept_conns() trivial correctness fix: EINTR return from accept should
 | 
			
		||||
	force continue rather than break in handling loop.
 | 
			
		||||
 | 
			
		||||
	fail_on_fdne() is now file_exists() with a slightly different API.
 | 
			
		||||
 | 
			
		||||
20040818
 | 
			
		||||
	Use inet_aton rather than custom function; daemon.[ch] removed.
 | 
			
		||||
 | 
			
		||||
20040817
 | 
			
		||||
	ifchd no longer logs a "FATAL - select returned an error!" when it
 | 
			
		||||
	is -KILL'ed.
 | 
			
		||||
 | 
			
		||||
20040626
 | 
			
		||||
	pending_exit is now static volatile sig_atomic_t rather than
 | 
			
		||||
	static volatile int for pedantic correctness issues.
 | 
			
		||||
 | 
			
		||||
20040614
 | 
			
		||||
	Added --interface (-i) option that allows one to restrict the
 | 
			
		||||
		interfaces that ifchd clients are allowed to modify.  I
 | 
			
		||||
		reccomend that this flag be used to further mitigate the possible
 | 
			
		||||
		effects of a compromised client.  By default, all interfaces
 | 
			
		||||
		may be modified by clients.
 | 
			
		||||
	Minor cleanups.
 | 
			
		||||
	Clear corresponding namesvrs and domains on socket disconnection.
 | 
			
		||||
 | 
			
		||||
20040613
 | 
			
		||||
	Factor out Linux-specific code into linux.c.
 | 
			
		||||
	Nameservers and search domains now tracked per-connection to
 | 
			
		||||
		prevent races where a client could force a writeout of data
 | 
			
		||||
		provided by another client.
 | 
			
		||||
	Interface name now cleared on connection close.
 | 
			
		||||
	Make all headers idempotent.
 | 
			
		||||
	Minor improvements to error messages.
 | 
			
		||||
 | 
			
		||||
20040612
 | 
			
		||||
	Removed iffd[] array; this change makes the state machine action
 | 
			
		||||
	functions (perform_*) depend on less external state.
 | 
			
		||||
 | 
			
		||||
	HOSTNAME command now supported; it is not enabled by default.
 | 
			
		||||
	If you wish for remote daemons to be able to change the hostname
 | 
			
		||||
	of the local machine, use the --hostname (-o) option.
 | 
			
		||||
 | 
			
		||||
20040610
 | 
			
		||||
	Added MTU support.
 | 
			
		||||
 | 
			
		||||
20040609
 | 
			
		||||
	Robustify so that suicide() isn't called at every possible failure.
 | 
			
		||||
	Harmless failures will now simply print an error to the log.  Risky
 | 
			
		||||
	or severe errors still suicide().
 | 
			
		||||
 | 
			
		||||
20040608
 | 
			
		||||
 | 
			
		||||
	Added support for resolv.conf, namely "nameserver" and "search" entries.
 | 
			
		||||
	Make strlist more robust and paranoid.
 | 
			
		||||
 | 
			
		||||
20040607
 | 
			
		||||
 | 
			
		||||
	Improved accept() code to be much more robust; it can now properly error
 | 
			
		||||
	recover.  I hope this will fix the elusive random-exit problem that
 | 
			
		||||
	plagues machines running the 2.6 kernel.
 | 
			
		||||
 | 
			
		||||
	Refactored dispatch_work() to be cleaner.
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										104
									
								
								DESIGN
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								DESIGN
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,104 @@
 | 
			
		||||
Goals:
 | 
			
		||||
 | 
			
		||||
1.  Security
 | 
			
		||||
 | 
			
		||||
	a.  Divide into seperate processes that each have the minimal
 | 
			
		||||
	    system access necessary to complete their task.
 | 
			
		||||
 | 
			
		||||
	b.  Use a well defined IPC mechanism to facilitate cooperation
 | 
			
		||||
	    between processes.  In this case, UNIX domain sockets are
 | 
			
		||||
	    used, since they allow for UNIX DAC (on Linux, at least).
 | 
			
		||||
 | 
			
		||||
	c.  Write each program to be secure; don't rely on the
 | 
			
		||||
	    privilege seperations for security.
 | 
			
		||||
 | 
			
		||||
	d.  Simple error handling is favored rather than complex error
 | 
			
		||||
	    handling that may possibly be caused to "recover" in an
 | 
			
		||||
	    exploitable way.
 | 
			
		||||
 | 
			
		||||
	e.  Don't make stupid assumptions.  Implement only the minimal
 | 
			
		||||
	    functionality necessary to perform a task.  Expect brain
 | 
			
		||||
	    damaged or malicious inputs.
 | 
			
		||||
 | 
			
		||||
	f.  Run inside a chroot, with minimal privileges via
 | 
			
		||||
	    capabilities or MAC.
 | 
			
		||||
 | 
			
		||||
2.  Reliability
 | 
			
		||||
 | 
			
		||||
	a.  Don't try to handle severe errors.  
 | 
			
		||||
 | 
			
		||||
	b.  Log errors if program state is still sane.
 | 
			
		||||
 | 
			
		||||
	c.  Recover from predictable problems if necessary.  Make sure
 | 
			
		||||
	    that recovery behavior is well understood and defined.
 | 
			
		||||
 | 
			
		||||
	d.  Complicated or unsafe recoveries should not be performed;
 | 
			
		||||
	    instead the program should promptly exit.  Dead programs
 | 
			
		||||
	    don't cause exploits.
 | 
			
		||||
 | 
			
		||||
5.  Portability
 | 
			
		||||
 | 
			
		||||
	a.  Portability is good, but portability may not be as wide as
 | 
			
		||||
	    a less secure program.  Capabilities or MAC are not well
 | 
			
		||||
	    standardized, but remain necessary features.  
 | 
			
		||||
	
 | 
			
		||||
        b.  Aside from the previous caveat, try to be as portable as
 | 
			
		||||
	    possible.  At the very least, the dhcp client daemon
 | 
			
		||||
	    should be easily portable (only broadcast and perhaps RAW
 | 
			
		||||
	    packets are necessary).
 | 
			
		||||
 | 
			
		||||
98. Speed
 | 
			
		||||
 | 
			
		||||
	a.  If we aren't required to sacrifice anything more
 | 
			
		||||
	    important, it's always good to be fast.
 | 
			
		||||
 | 
			
		||||
99. Size
 | 
			
		||||
 | 
			
		||||
	a.  If we aren't required to sacrifice anything more
 | 
			
		||||
	    important, it's always good to be frugal.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Specifics:
 | 
			
		||||
 | 
			
		||||
Implementation language will be C.  C is universally available, very
 | 
			
		||||
predictable, and well accepted.  dhcp clients don't have to deal with
 | 
			
		||||
complicated data structures or extensively with strings, so C's
 | 
			
		||||
largest weaknesses should not be highly apparent.  On the other hand,
 | 
			
		||||
dhcp clients must extensively deal with the OS in a low-level fashion.
 | 
			
		||||
C's strongest points will therefore be used.
 | 
			
		||||
 | 
			
		||||
More practically, a program written in a compiled language other than
 | 
			
		||||
C will be poorly accepted by the average user.  Since widespread use
 | 
			
		||||
is an eventual goal of ndhc, this point is very eloquent.
 | 
			
		||||
 | 
			
		||||
For now, I'm taking advantage of the existing udhcpc.  With minor
 | 
			
		||||
modifications, it will serve quite well as the dhcp client daemon.  It
 | 
			
		||||
is then only necessary for me to write a client request translator
 | 
			
		||||
and a interface change daemon.  The result should be a highly modular
 | 
			
		||||
solution.
 | 
			
		||||
 | 
			
		||||
I'm developing on a Linux-based platform.  ndhc will first be designed
 | 
			
		||||
to work properly on a Linux-based system.  I will then make certain
 | 
			
		||||
that ndhc works well on a RSBAC-enabled Linux system.  Afterwards, I
 | 
			
		||||
_may_ spend some effort porting ndhc to FreeBSD (but don't count on it).  I
 | 
			
		||||
have no personal interest in other platforms.
 | 
			
		||||
 | 
			
		||||
Layout:
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
ndhc daemon  (root -> chroot -> drop all !(CAP_NET_BROADCAST|CAP_NET_RAW) 
 | 
			
		||||
              -> nopriv)
 | 
			
		||||
 | 
			
		||||
* handles dhcp protocol issues
 | 
			
		||||
* keeps track of leases
 | 
			
		||||
* talks to ndhif to perform tasks that require
 | 
			
		||||
  higher privileges than CAP_NET_BROADCAST or CAP_NET_RAW
 | 
			
		||||
 | 
			
		||||
ifchd daemon  (root -> openfd -> chroot -> drop all !CAP_NET_ADMIN -> nopriv)
 | 
			
		||||
 | 
			
		||||
* listens for interface change requests via UNIX domain socket
 | 
			
		||||
* restricts valid IP ranges that will be accepted
 | 
			
		||||
* performs interface changes
 | 
			
		||||
* keeps rw fds for system files (such as /etc/resolv.conf) that must
 | 
			
		||||
  be modified outside the chroot
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										339
									
								
								LICENSE
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										339
									
								
								LICENSE
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,339 @@
 | 
			
		||||
		    GNU GENERAL PUBLIC LICENSE
 | 
			
		||||
		       Version 2, June 1991
 | 
			
		||||
 | 
			
		||||
 Copyright (C) 1989, 1991 Free Software Foundation, Inc.
 | 
			
		||||
                          675 Mass Ave, Cambridge, MA 02139, USA
 | 
			
		||||
 Everyone is permitted to copy and distribute verbatim copies
 | 
			
		||||
 of this license document, but changing it is not allowed.
 | 
			
		||||
 | 
			
		||||
			    Preamble
 | 
			
		||||
 | 
			
		||||
  The licenses for most software are designed to take away your
 | 
			
		||||
freedom to share and change it.  By contrast, the GNU General Public
 | 
			
		||||
License is intended to guarantee your freedom to share and change free
 | 
			
		||||
software--to make sure the software is free for all its users.  This
 | 
			
		||||
General Public License applies to most of the Free Software
 | 
			
		||||
Foundation's software and to any other program whose authors commit to
 | 
			
		||||
using it.  (Some other Free Software Foundation software is covered by
 | 
			
		||||
the GNU Library General Public License instead.)  You can apply it to
 | 
			
		||||
your programs, too.
 | 
			
		||||
 | 
			
		||||
  When we speak of free software, we are referring to freedom, not
 | 
			
		||||
price.  Our General Public Licenses are designed to make sure that you
 | 
			
		||||
have the freedom to distribute copies of free software (and charge for
 | 
			
		||||
this service if you wish), that you receive source code or can get it
 | 
			
		||||
if you want it, that you can change the software or use pieces of it
 | 
			
		||||
in new free programs; and that you know you can do these things.
 | 
			
		||||
 | 
			
		||||
  To protect your rights, we need to make restrictions that forbid
 | 
			
		||||
anyone to deny you these rights or to ask you to surrender the rights.
 | 
			
		||||
These restrictions translate to certain responsibilities for you if you
 | 
			
		||||
distribute copies of the software, or if you modify it.
 | 
			
		||||
 | 
			
		||||
  For example, if you distribute copies of such a program, whether
 | 
			
		||||
gratis or for a fee, you must give the recipients all the rights that
 | 
			
		||||
you have.  You must make sure that they, too, receive or can get the
 | 
			
		||||
source code.  And you must show them these terms so they know their
 | 
			
		||||
rights.
 | 
			
		||||
 | 
			
		||||
  We protect your rights with two steps: (1) copyright the software, and
 | 
			
		||||
(2) offer you this license which gives you legal permission to copy,
 | 
			
		||||
distribute and/or modify the software.
 | 
			
		||||
 | 
			
		||||
  Also, for each author's protection and ours, we want to make certain
 | 
			
		||||
that everyone understands that there is no warranty for this free
 | 
			
		||||
software.  If the software is modified by someone else and passed on, we
 | 
			
		||||
want its recipients to know that what they have is not the original, so
 | 
			
		||||
that any problems introduced by others will not reflect on the original
 | 
			
		||||
authors' reputations.
 | 
			
		||||
 | 
			
		||||
  Finally, any free program is threatened constantly by software
 | 
			
		||||
patents.  We wish to avoid the danger that redistributors of a free
 | 
			
		||||
program will individually obtain patent licenses, in effect making the
 | 
			
		||||
program proprietary.  To prevent this, we have made it clear that any
 | 
			
		||||
patent must be licensed for everyone's free use or not licensed at all.
 | 
			
		||||
 | 
			
		||||
  The precise terms and conditions for copying, distribution and
 | 
			
		||||
modification follow.
 | 
			
		||||
 | 
			
		||||
		    GNU GENERAL PUBLIC LICENSE
 | 
			
		||||
   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
 | 
			
		||||
 | 
			
		||||
  0. This License applies to any program or other work which contains
 | 
			
		||||
a notice placed by the copyright holder saying it may be distributed
 | 
			
		||||
under the terms of this General Public License.  The "Program", below,
 | 
			
		||||
refers to any such program or work, and a "work based on the Program"
 | 
			
		||||
means either the Program or any derivative work under copyright law:
 | 
			
		||||
that is to say, a work containing the Program or a portion of it,
 | 
			
		||||
either verbatim or with modifications and/or translated into another
 | 
			
		||||
language.  (Hereinafter, translation is included without limitation in
 | 
			
		||||
the term "modification".)  Each licensee is addressed as "you".
 | 
			
		||||
 | 
			
		||||
Activities other than copying, distribution and modification are not
 | 
			
		||||
covered by this License; they are outside its scope.  The act of
 | 
			
		||||
running the Program is not restricted, and the output from the Program
 | 
			
		||||
is covered only if its contents constitute a work based on the
 | 
			
		||||
Program (independent of having been made by running the Program).
 | 
			
		||||
Whether that is true depends on what the Program does.
 | 
			
		||||
 | 
			
		||||
  1. You may copy and distribute verbatim copies of the Program's
 | 
			
		||||
source code as you receive it, in any medium, provided that you
 | 
			
		||||
conspicuously and appropriately publish on each copy an appropriate
 | 
			
		||||
copyright notice and disclaimer of warranty; keep intact all the
 | 
			
		||||
notices that refer to this License and to the absence of any warranty;
 | 
			
		||||
and give any other recipients of the Program a copy of this License
 | 
			
		||||
along with the Program.
 | 
			
		||||
 | 
			
		||||
You may charge a fee for the physical act of transferring a copy, and
 | 
			
		||||
you may at your option offer warranty protection in exchange for a fee.
 | 
			
		||||
 | 
			
		||||
  2. You may modify your copy or copies of the Program or any portion
 | 
			
		||||
of it, thus forming a work based on the Program, and copy and
 | 
			
		||||
distribute such modifications or work under the terms of Section 1
 | 
			
		||||
above, provided that you also meet all of these conditions:
 | 
			
		||||
 | 
			
		||||
    a) You must cause the modified files to carry prominent notices
 | 
			
		||||
    stating that you changed the files and the date of any change.
 | 
			
		||||
 | 
			
		||||
    b) You must cause any work that you distribute or publish, that in
 | 
			
		||||
    whole or in part contains or is derived from the Program or any
 | 
			
		||||
    part thereof, to be licensed as a whole at no charge to all third
 | 
			
		||||
    parties under the terms of this License.
 | 
			
		||||
 | 
			
		||||
    c) If the modified program normally reads commands interactively
 | 
			
		||||
    when run, you must cause it, when started running for such
 | 
			
		||||
    interactive use in the most ordinary way, to print or display an
 | 
			
		||||
    announcement including an appropriate copyright notice and a
 | 
			
		||||
    notice that there is no warranty (or else, saying that you provide
 | 
			
		||||
    a warranty) and that users may redistribute the program under
 | 
			
		||||
    these conditions, and telling the user how to view a copy of this
 | 
			
		||||
    License.  (Exception: if the Program itself is interactive but
 | 
			
		||||
    does not normally print such an announcement, your work based on
 | 
			
		||||
    the Program is not required to print an announcement.)
 | 
			
		||||
 | 
			
		||||
These requirements apply to the modified work as a whole.  If
 | 
			
		||||
identifiable sections of that work are not derived from the Program,
 | 
			
		||||
and can be reasonably considered independent and separate works in
 | 
			
		||||
themselves, then this License, and its terms, do not apply to those
 | 
			
		||||
sections when you distribute them as separate works.  But when you
 | 
			
		||||
distribute the same sections as part of a whole which is a work based
 | 
			
		||||
on the Program, the distribution of the whole must be on the terms of
 | 
			
		||||
this License, whose permissions for other licensees extend to the
 | 
			
		||||
entire whole, and thus to each and every part regardless of who wrote it.
 | 
			
		||||
 | 
			
		||||
Thus, it is not the intent of this section to claim rights or contest
 | 
			
		||||
your rights to work written entirely by you; rather, the intent is to
 | 
			
		||||
exercise the right to control the distribution of derivative or
 | 
			
		||||
collective works based on the Program.
 | 
			
		||||
 | 
			
		||||
In addition, mere aggregation of another work not based on the Program
 | 
			
		||||
with the Program (or with a work based on the Program) on a volume of
 | 
			
		||||
a storage or distribution medium does not bring the other work under
 | 
			
		||||
the scope of this License.
 | 
			
		||||
 | 
			
		||||
  3. You may copy and distribute the Program (or a work based on it,
 | 
			
		||||
under Section 2) in object code or executable form under the terms of
 | 
			
		||||
Sections 1 and 2 above provided that you also do one of the following:
 | 
			
		||||
 | 
			
		||||
    a) Accompany it with the complete corresponding machine-readable
 | 
			
		||||
    source code, which must be distributed under the terms of Sections
 | 
			
		||||
    1 and 2 above on a medium customarily used for software interchange; or,
 | 
			
		||||
 | 
			
		||||
    b) Accompany it with a written offer, valid for at least three
 | 
			
		||||
    years, to give any third party, for a charge no more than your
 | 
			
		||||
    cost of physically performing source distribution, a complete
 | 
			
		||||
    machine-readable copy of the corresponding source code, to be
 | 
			
		||||
    distributed under the terms of Sections 1 and 2 above on a medium
 | 
			
		||||
    customarily used for software interchange; or,
 | 
			
		||||
 | 
			
		||||
    c) Accompany it with the information you received as to the offer
 | 
			
		||||
    to distribute corresponding source code.  (This alternative is
 | 
			
		||||
    allowed only for noncommercial distribution and only if you
 | 
			
		||||
    received the program in object code or executable form with such
 | 
			
		||||
    an offer, in accord with Subsection b above.)
 | 
			
		||||
 | 
			
		||||
The source code for a work means the preferred form of the work for
 | 
			
		||||
making modifications to it.  For an executable work, complete source
 | 
			
		||||
code means all the source code for all modules it contains, plus any
 | 
			
		||||
associated interface definition files, plus the scripts used to
 | 
			
		||||
control compilation and installation of the executable.  However, as a
 | 
			
		||||
special exception, the source code distributed need not include
 | 
			
		||||
anything that is normally distributed (in either source or binary
 | 
			
		||||
form) with the major components (compiler, kernel, and so on) of the
 | 
			
		||||
operating system on which the executable runs, unless that component
 | 
			
		||||
itself accompanies the executable.
 | 
			
		||||
 | 
			
		||||
If distribution of executable or object code is made by offering
 | 
			
		||||
access to copy from a designated place, then offering equivalent
 | 
			
		||||
access to copy the source code from the same place counts as
 | 
			
		||||
distribution of the source code, even though third parties are not
 | 
			
		||||
compelled to copy the source along with the object code.
 | 
			
		||||
 | 
			
		||||
  4. You may not copy, modify, sublicense, or distribute the Program
 | 
			
		||||
except as expressly provided under this License.  Any attempt
 | 
			
		||||
otherwise to copy, modify, sublicense or distribute the Program is
 | 
			
		||||
void, and will automatically terminate your rights under this License.
 | 
			
		||||
However, parties who have received copies, or rights, from you under
 | 
			
		||||
this License will not have their licenses terminated so long as such
 | 
			
		||||
parties remain in full compliance.
 | 
			
		||||
 | 
			
		||||
  5. You are not required to accept this License, since you have not
 | 
			
		||||
signed it.  However, nothing else grants you permission to modify or
 | 
			
		||||
distribute the Program or its derivative works.  These actions are
 | 
			
		||||
prohibited by law if you do not accept this License.  Therefore, by
 | 
			
		||||
modifying or distributing the Program (or any work based on the
 | 
			
		||||
Program), you indicate your acceptance of this License to do so, and
 | 
			
		||||
all its terms and conditions for copying, distributing or modifying
 | 
			
		||||
the Program or works based on it.
 | 
			
		||||
 | 
			
		||||
  6. Each time you redistribute the Program (or any work based on the
 | 
			
		||||
Program), the recipient automatically receives a license from the
 | 
			
		||||
original licensor to copy, distribute or modify the Program subject to
 | 
			
		||||
these terms and conditions.  You may not impose any further
 | 
			
		||||
restrictions on the recipients' exercise of the rights granted herein.
 | 
			
		||||
You are not responsible for enforcing compliance by third parties to
 | 
			
		||||
this License.
 | 
			
		||||
 | 
			
		||||
  7. If, as a consequence of a court judgment or allegation of patent
 | 
			
		||||
infringement or for any other reason (not limited to patent issues),
 | 
			
		||||
conditions are imposed on you (whether by court order, agreement or
 | 
			
		||||
otherwise) that contradict the conditions of this License, they do not
 | 
			
		||||
excuse you from the conditions of this License.  If you cannot
 | 
			
		||||
distribute so as to satisfy simultaneously your obligations under this
 | 
			
		||||
License and any other pertinent obligations, then as a consequence you
 | 
			
		||||
may not distribute the Program at all.  For example, if a patent
 | 
			
		||||
license would not permit royalty-free redistribution of the Program by
 | 
			
		||||
all those who receive copies directly or indirectly through you, then
 | 
			
		||||
the only way you could satisfy both it and this License would be to
 | 
			
		||||
refrain entirely from distribution of the Program.
 | 
			
		||||
 | 
			
		||||
If any portion of this section is held invalid or unenforceable under
 | 
			
		||||
any particular circumstance, the balance of the section is intended to
 | 
			
		||||
apply and the section as a whole is intended to apply in other
 | 
			
		||||
circumstances.
 | 
			
		||||
 | 
			
		||||
It is not the purpose of this section to induce you to infringe any
 | 
			
		||||
patents or other property right claims or to contest validity of any
 | 
			
		||||
such claims; this section has the sole purpose of protecting the
 | 
			
		||||
integrity of the free software distribution system, which is
 | 
			
		||||
implemented by public license practices.  Many people have made
 | 
			
		||||
generous contributions to the wide range of software distributed
 | 
			
		||||
through that system in reliance on consistent application of that
 | 
			
		||||
system; it is up to the author/donor to decide if he or she is willing
 | 
			
		||||
to distribute software through any other system and a licensee cannot
 | 
			
		||||
impose that choice.
 | 
			
		||||
 | 
			
		||||
This section is intended to make thoroughly clear what is believed to
 | 
			
		||||
be a consequence of the rest of this License.
 | 
			
		||||
 | 
			
		||||
  8. If the distribution and/or use of the Program is restricted in
 | 
			
		||||
certain countries either by patents or by copyrighted interfaces, the
 | 
			
		||||
original copyright holder who places the Program under this License
 | 
			
		||||
may add an explicit geographical distribution limitation excluding
 | 
			
		||||
those countries, so that distribution is permitted only in or among
 | 
			
		||||
countries not thus excluded.  In such case, this License incorporates
 | 
			
		||||
the limitation as if written in the body of this License.
 | 
			
		||||
 | 
			
		||||
  9. The Free Software Foundation may publish revised and/or new versions
 | 
			
		||||
of the General Public License from time to time.  Such new versions will
 | 
			
		||||
be similar in spirit to the present version, but may differ in detail to
 | 
			
		||||
address new problems or concerns.
 | 
			
		||||
 | 
			
		||||
Each version is given a distinguishing version number.  If the Program
 | 
			
		||||
specifies a version number of this License which applies to it and "any
 | 
			
		||||
later version", you have the option of following the terms and conditions
 | 
			
		||||
either of that version or of any later version published by the Free
 | 
			
		||||
Software Foundation.  If the Program does not specify a version number of
 | 
			
		||||
this License, you may choose any version ever published by the Free Software
 | 
			
		||||
Foundation.
 | 
			
		||||
 | 
			
		||||
  10. If you wish to incorporate parts of the Program into other free
 | 
			
		||||
programs whose distribution conditions are different, write to the author
 | 
			
		||||
to ask for permission.  For software which is copyrighted by the Free
 | 
			
		||||
Software Foundation, write to the Free Software Foundation; we sometimes
 | 
			
		||||
make exceptions for this.  Our decision will be guided by the two goals
 | 
			
		||||
of preserving the free status of all derivatives of our free software and
 | 
			
		||||
of promoting the sharing and reuse of software generally.
 | 
			
		||||
 | 
			
		||||
			    NO WARRANTY
 | 
			
		||||
 | 
			
		||||
  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
 | 
			
		||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
 | 
			
		||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
 | 
			
		||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
 | 
			
		||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 | 
			
		||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
 | 
			
		||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
 | 
			
		||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
 | 
			
		||||
REPAIR OR CORRECTION.
 | 
			
		||||
 | 
			
		||||
  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
 | 
			
		||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
 | 
			
		||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
 | 
			
		||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
 | 
			
		||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
 | 
			
		||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
 | 
			
		||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
 | 
			
		||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
 | 
			
		||||
POSSIBILITY OF SUCH DAMAGES.
 | 
			
		||||
 | 
			
		||||
		     END OF TERMS AND CONDITIONS
 | 
			
		||||
 | 
			
		||||
	Appendix: How to Apply These Terms to Your New Programs
 | 
			
		||||
 | 
			
		||||
  If you develop a new program, and you want it to be of the greatest
 | 
			
		||||
possible use to the public, the best way to achieve this is to make it
 | 
			
		||||
free software which everyone can redistribute and change under these terms.
 | 
			
		||||
 | 
			
		||||
  To do so, attach the following notices to the program.  It is safest
 | 
			
		||||
to attach them to the start of each source file to most effectively
 | 
			
		||||
convey the exclusion of warranty; and each file should have at least
 | 
			
		||||
the "copyright" line and a pointer to where the full notice is found.
 | 
			
		||||
 | 
			
		||||
    <one line to give the program's name and a brief idea of what it does.>
 | 
			
		||||
    Copyright (C) 19yy  <name of author>
 | 
			
		||||
 | 
			
		||||
    This program is free software; you can redistribute it and/or modify
 | 
			
		||||
    it under the terms of the GNU General Public License as published by
 | 
			
		||||
    the Free Software Foundation; either version 2 of the License, or
 | 
			
		||||
    (at your option) any later version.
 | 
			
		||||
 | 
			
		||||
    This program is distributed in the hope that it will be useful,
 | 
			
		||||
    but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
    GNU General Public License for more details.
 | 
			
		||||
 | 
			
		||||
    You should have received a copy of the GNU General Public License
 | 
			
		||||
    along with this program; if not, write to the Free Software
 | 
			
		||||
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 | 
			
		||||
 | 
			
		||||
Also add information on how to contact you by electronic and paper mail.
 | 
			
		||||
 | 
			
		||||
If the program is interactive, make it output a short notice like this
 | 
			
		||||
when it starts in an interactive mode:
 | 
			
		||||
 | 
			
		||||
    Gnomovision version 69, Copyright (C) 19yy name of author
 | 
			
		||||
    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
 | 
			
		||||
    This is free software, and you are welcome to redistribute it
 | 
			
		||||
    under certain conditions; type `show c' for details.
 | 
			
		||||
 | 
			
		||||
The hypothetical commands `show w' and `show c' should show the appropriate
 | 
			
		||||
parts of the General Public License.  Of course, the commands you use may
 | 
			
		||||
be called something other than `show w' and `show c'; they could even be
 | 
			
		||||
mouse-clicks or menu items--whatever suits your program.
 | 
			
		||||
 | 
			
		||||
You should also get your employer (if you work as a programmer) or your
 | 
			
		||||
school, if any, to sign a "copyright disclaimer" for the program, if
 | 
			
		||||
necessary.  Here is a sample; alter the names:
 | 
			
		||||
 | 
			
		||||
  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
 | 
			
		||||
  `Gnomovision' (which makes passes at compilers) written by James Hacker.
 | 
			
		||||
 | 
			
		||||
  <signature of Ty Coon>, 1 April 1989
 | 
			
		||||
  Ty Coon, President of Vice
 | 
			
		||||
 | 
			
		||||
This General Public License does not permit incorporating your program into
 | 
			
		||||
proprietary programs.  If your program is a subroutine library, you may
 | 
			
		||||
consider it more useful to permit linking proprietary applications with the
 | 
			
		||||
library.  If this is what you want to do, use the GNU Library General
 | 
			
		||||
Public License instead of this License.
 | 
			
		||||
							
								
								
									
										28
									
								
								Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								Makefile
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,28 @@
 | 
			
		||||
CC = gcc -Wall -Wpointer-arith -Wstrict-prototypes
 | 
			
		||||
AR = ar
 | 
			
		||||
objects = log.o nstrl.o chroot.o pidfile.o signals.o strlist.o linux.o ifchd.o
 | 
			
		||||
 | 
			
		||||
ifchd : $(objects)
 | 
			
		||||
	$(CC) -lcap -o ifchd $(objects)
 | 
			
		||||
 | 
			
		||||
ifchd.o : log.h nstrl.h chroot.h pidfile.h signals.h strlist.h linux.h
 | 
			
		||||
	$(CC) $(CFLAGS) $(archflags) $(LDFLAGS) -c -o $@ ifchd.c
 | 
			
		||||
 | 
			
		||||
linux.o: log.h strlist.h
 | 
			
		||||
chroot.o: log.h
 | 
			
		||||
pidfile.o: log.h
 | 
			
		||||
signals.o: log.h
 | 
			
		||||
strlist.o:
 | 
			
		||||
nstrl.o:
 | 
			
		||||
log.o :
 | 
			
		||||
 | 
			
		||||
install: ifchd
 | 
			
		||||
	-install -s -m 755 ifchd /usr/sbin/ifchd
 | 
			
		||||
tags:
 | 
			
		||||
	-ctags -f tags *.[ch]
 | 
			
		||||
	-cscope -b
 | 
			
		||||
clean:
 | 
			
		||||
	-rm -f *.o ifchd
 | 
			
		||||
distclean:
 | 
			
		||||
	-rm -f *.o ifchd tags cscope.out
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										191
									
								
								README.ifchd
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										191
									
								
								README.ifchd
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,191 @@
 | 
			
		||||
ifchd, copyright (c) 2004 Nicholas Kain.  Licensed under GNU GPL.
 | 
			
		||||
 | 
			
		||||
Requirements:
 | 
			
		||||
 | 
			
		||||
Linux kernel (tested: 2.4, 2.6)
 | 
			
		||||
	* libcap is required (available via ftp.kernel.org)
 | 
			
		||||
 | 
			
		||||
C99-compliant C compiler (for C99 struct subobject init)
 | 
			
		||||
	* any modern GCC should be sufficient
 | 
			
		||||
 | 
			
		||||
Tested with glibc 2.2.x and 2.3.x.  dietlibc is not compatible.  I have not yet
 | 
			
		||||
tested uclibc.
 | 
			
		||||
 | 
			
		||||
I may bother to port to other operating systems, but don't count on it.  Other
 | 
			
		||||
OSes lack the functionality of a [RSBAC|SELinux]+PaX enabled kernel, so I find
 | 
			
		||||
them to be less useful for a highly secured system.
 | 
			
		||||
 | 
			
		||||
INTRODUCTION
 | 
			
		||||
------------
 | 
			
		||||
 | 
			
		||||
ndhc consists of a set of daemons that cooperate in order to provide
 | 
			
		||||
privilege-seperated dhcp client services.  Each daemon runs with the minimal
 | 
			
		||||
necessary privileges in order to perform its task.  Currently, ndhc consists of
 | 
			
		||||
two daemons: the eponymous ndhc and ifchd.
 | 
			
		||||
 | 
			
		||||
ndhc communicates with dhcp servers and handles the vagaries of the dhcp
 | 
			
		||||
client protocol.  It runs as a non-root user inside a chroot.  ndhc retains
 | 
			
		||||
only the minimum necessary set of privileges required to perform its duties.
 | 
			
		||||
These powers include the ability to bind to a low port, the ability to open a
 | 
			
		||||
raw socket, and the ability to communicate on broadcast channels.  ndhc holds
 | 
			
		||||
no other powers and is restricted to a chroot that contains nothing more than a
 | 
			
		||||
domain socket filesystem object and (at least on Linux) a urandom device node.
 | 
			
		||||
 | 
			
		||||
ifchd handles interface change requests.  It listens on a UNIX domain socket
 | 
			
		||||
for such requests, and denies any client that does not match an authorized gid,
 | 
			
		||||
uid, or pid.  ifchd runs as a non-root user inside a chroot, and retains only
 | 
			
		||||
the power to configure network interfaces.  ifchd is designed so that it has
 | 
			
		||||
the ability to service multiple client requests simultaneously; a single ifchd
 | 
			
		||||
is sufficient for multiple ndhc clients.  Only exotic setups should require
 | 
			
		||||
this functionality, but it does exist.
 | 
			
		||||
 | 
			
		||||
Note that ndhc does not support the entire DHCP client protocol.  Only the
 | 
			
		||||
minimum necessary featureset is implemented.  This behavior should be familiar
 | 
			
		||||
to anyone who has used software that purports to be be secure.
 | 
			
		||||
 | 
			
		||||
Many of the features that ndhc depends upon are not entirely standard and vary
 | 
			
		||||
between UNIX systems.  It is likely that some effort will be required in order
 | 
			
		||||
to port ndhc to new systems.  The ndhc daemon should be entirely portable aside
 | 
			
		||||
from its use of Linux-style POSIX capabilities.
 | 
			
		||||
 | 
			
		||||
ifchd is necessarily less portable, since it must use system-specific ioctls in
 | 
			
		||||
order to configure network interfaces.  Additionally, ifchd uses extensions to
 | 
			
		||||
the UNIX domain socket family to limit connections to user defined subsets of
 | 
			
		||||
possible uids, gids, and pids.  These extensions are present in Linux and BSD,
 | 
			
		||||
although both Linux and BSD have different interfaces for the functionality.
 | 
			
		||||
Patches that provide support for new systems are welcome.
 | 
			
		||||
 | 
			
		||||
USAGE
 | 
			
		||||
-----
 | 
			
		||||
 | 
			
		||||
1) Compile and install ifchd and ndhc. 
 | 
			
		||||
    a) Build ifchd with "make"
 | 
			
		||||
    b) Enter ndhc directory and build ndhc with "make"
 | 
			
		||||
    c) Install the ifchd and ndhc executables in a normal place.  I would
 | 
			
		||||
       suggest /usr/sbin or /usr/local/sbin.
 | 
			
		||||
 | 
			
		||||
2) Time to create the jail in which ifchd and ndhc will run.
 | 
			
		||||
    a) Become root and create new group "ifchd".
 | 
			
		||||
 | 
			
		||||
	$ su -
 | 
			
		||||
	# umask 077
 | 
			
		||||
	# groupadd ifchd
 | 
			
		||||
    
 | 
			
		||||
    b) Create new users "ifchd" and "dhcp".  The primary group of these
 | 
			
		||||
       users should be "ifchd".
 | 
			
		||||
 | 
			
		||||
	# useradd -d /var/lib/ndhc -g ifchd ifchd
 | 
			
		||||
	# useradd -d /var/lib/ndhc -g ifchd dhcp
 | 
			
		||||
       
 | 
			
		||||
    b) Create the jail directory and set its ownership properly.
 | 
			
		||||
 | 
			
		||||
	# mkdir /var/lib/ndhc
 | 
			
		||||
	# chown ifchd.ifchd /var/lib/ndhc
 | 
			
		||||
	# chmod a+rx /var/lib/ndhc
 | 
			
		||||
	
 | 
			
		||||
    c) Create a urandom device for ndhc to use within the jail.
 | 
			
		||||
 | 
			
		||||
	# cd /var/lib/ndhc
 | 
			
		||||
	# mkdir dev
 | 
			
		||||
	# mknod dev/urandom c 1 9
 | 
			
		||||
	# chown -R root.root dev
 | 
			
		||||
	# chmod a+rx dev
 | 
			
		||||
	# chmod a+r dev/urandom
 | 
			
		||||
 | 
			
		||||
	d) (optional) If you wish for logging to properly work, you
 | 
			
		||||
	   will need to properly configure your logging daemon so that it
 | 
			
		||||
	   opens a domain socket in the proper location within the jail.
 | 
			
		||||
	   Since this varies per-daemon, I cannot provide a general
 | 
			
		||||
	   configuration.
 | 
			
		||||
 | 
			
		||||
3)  At this point the jail is usable; ifchd and ndhc are ready to
 | 
			
		||||
    be used.  As an example of a sample configuration, here is my
 | 
			
		||||
    rc.dhcp:
 | 
			
		||||
 | 
			
		||||
--START--
 | 
			
		||||
 | 
			
		||||
#!/bin/sh
 | 
			
		||||
case "$1" in
 | 
			
		||||
	start)
 | 
			
		||||
		ifchd -i eth0 -p /var/run/ifchd.pid -u ifchd -g ifchd -U dhcp -G ifchd \
 | 
			
		||||
			-c /var/lib/ndhc &> /dev/null
 | 
			
		||||
		ndhc -b -i eth0 -u dhcp -C /var/lib/ndhc &> /dev/null
 | 
			
		||||
		;;
 | 
			
		||||
	stop)
 | 
			
		||||
		killall ndhc ifchd
 | 
			
		||||
		;;
 | 
			
		||||
esac
 | 
			
		||||
 | 
			
		||||
--END--
 | 
			
		||||
 | 
			
		||||
    This script works fine with my personal machines, which are set up
 | 
			
		||||
    exactly as I have outlined above.  If you have not entirely followed my
 | 
			
		||||
    directions, the script will of course require modifications.
 | 
			
		||||
 | 
			
		||||
4o) If you encounter problems, I suggest running both ifchd and ndhc in the
 | 
			
		||||
   foreground, and perhaps compiling ndhc with extra debugging output
 | 
			
		||||
   (uncomment DEBUG=1 in the Makefile).
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
BEHAVIOR NOTES
 | 
			
		||||
--------------
 | 
			
		||||
 | 
			
		||||
ifchd does not enable updates of the local hostname and resolv.conf by default.
 | 
			
		||||
If you wish to enable these functions, use the --resolve (-r) and --hostname
 | 
			
		||||
(-o) flags.  See ifchd --help.
 | 
			
		||||
 | 
			
		||||
ifchd can be set such that it only allows clients to configure particular
 | 
			
		||||
network interfaces.  The --interface (-i) argument does the trick, and may
 | 
			
		||||
be used multiple times to allow multiple interfaces.
 | 
			
		||||
 | 
			
		||||
RSBAC NOTES
 | 
			
		||||
-----------
 | 
			
		||||
 | 
			
		||||
I was personally unable to get ifchd to properly function with RSBAC_NET_DEV
 | 
			
		||||
enabled.  Browsing the rsbac source, I was unable to figure out what I was
 | 
			
		||||
doing incorrectly -- my RC definitions were as far as I could tell, correct.
 | 
			
		||||
Therefore, my directions assume that you have disabled RSBAC_NET_DEV in your
 | 
			
		||||
kernel configuration.
 | 
			
		||||
 | 
			
		||||
The normal usage directions may be followed, but an additional step for rsbac
 | 
			
		||||
is necessary.  Change to your secoff account and invoke rsbac_fd_menu on the
 | 
			
		||||
ifchd and ndhc executables.  The AUTH capability for your ifchd and dhcp groups
 | 
			
		||||
must be allowed on the corresponding executables, otherwise ifchd and ndhc will
 | 
			
		||||
be unable to change to a non-root user and will refuse to run.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
GRSECURITY NOTES
 | 
			
		||||
----------------
 | 
			
		||||
 | 
			
		||||
Make sure that CONFIG_GRKERNSEC_CHROOT_CAPS is disabled.  Otherwise, ifchd will
 | 
			
		||||
lose its capabilities (in particular, the ability to reconfigure interfaces)
 | 
			
		||||
when it chroots.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
PORTING NOTES
 | 
			
		||||
-------------
 | 
			
		||||
 | 
			
		||||
Unportable functions are isolated to linux.c.  Any attempts to port ifchd to
 | 
			
		||||
other platforms should isolate platform-dependent code to similarly named
 | 
			
		||||
compilation units (eg: for FreeBSD, freebsd.[ch]).
 | 
			
		||||
 | 
			
		||||
There are four major functions that ifchd depends upon that are not generally
 | 
			
		||||
portable.  First, it uses the SO_PEERCRED flag of getsockopt() to discriminate
 | 
			
		||||
authorized connections by uid, gid, and pid.  Similar functionality exists in
 | 
			
		||||
at least the BSDs; however, it has a different API.  Second, ifchd takes
 | 
			
		||||
advantage of Linux capabilities so that it does not need full root privileges.
 | 
			
		||||
Capabilities are supposedly a POSIX feature, but in practice, they vary greatly
 | 
			
		||||
from system to system.  Third and fourth, ifchd configures network interfaces
 | 
			
		||||
and routes.  Interface and route configuration is entirely non-portable,
 | 
			
		||||
usually requiring calls to the catch-all ioctl(), and will almost certainly
 | 
			
		||||
require platform-dependent code.
 | 
			
		||||
 | 
			
		||||
Some standard C libraries include a native implementation of strlcpy() and
 | 
			
		||||
strlcat().  Such defines may conflict with my implementations in
 | 
			
		||||
nstrl.c/nstrl.h.  It is up to the user whether the standard C library
 | 
			
		||||
implementations should be used.  Note that some machines implement strlcpy()
 | 
			
		||||
and strlcat() with nonstandard semantics (notably Solaris).  On these systems,
 | 
			
		||||
using the system-provided implementations may lead to security problems.  Such
 | 
			
		||||
problems are the fault of the vendor.  If you are unsure whether your system is
 | 
			
		||||
correct or not, I suggest using the implementation that I provide.
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										42
									
								
								chroot.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								chroot.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,42 @@
 | 
			
		||||
/* chroot.c - chroots ncron jobs
 | 
			
		||||
   (C) 2003 Nicholas J. Kain <njk@aerifal.cx>
 | 
			
		||||
 | 
			
		||||
   This library is free software; you can redistribute it and/or
 | 
			
		||||
   modify it under the terms of the GNU Lesser General Public
 | 
			
		||||
   License as published by the Free Software Foundation; either
 | 
			
		||||
   version 2.1 of the License, or (at your option) any later version.
 | 
			
		||||
 | 
			
		||||
   This library is distributed in the hope that it will be useful,
 | 
			
		||||
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
			
		||||
   Lesser General Public License for more details.
 | 
			
		||||
 | 
			
		||||
   You should have received a copy of the GNU Lesser General Public
 | 
			
		||||
   License along with this library; if not, write to the Free Software
 | 
			
		||||
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 | 
			
		||||
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
 | 
			
		||||
#include "log.h"
 | 
			
		||||
 | 
			
		||||
void imprison(char *path)
 | 
			
		||||
{
 | 
			
		||||
    int ret;
 | 
			
		||||
 | 
			
		||||
    if (path == NULL)
 | 
			
		||||
	return;
 | 
			
		||||
 | 
			
		||||
    ret = chdir(path);
 | 
			
		||||
    if (ret) {
 | 
			
		||||
	log_line("Failed to chdir(%s).  Not invoking job.", path);
 | 
			
		||||
	exit(EXIT_FAILURE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ret = chroot(path);
 | 
			
		||||
    if (ret) {
 | 
			
		||||
	log_line("Failed to chroot(%s).  Not invoking job.", path);
 | 
			
		||||
	exit(EXIT_FAILURE);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										21
									
								
								chroot.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								chroot.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
			
		||||
/* chroot.h - include file for chroot.c
 | 
			
		||||
   (C) 2003 Nicholas J. Kain <njk@aerifal.cx>
 | 
			
		||||
 | 
			
		||||
   This library is free software; you can redistribute it and/or
 | 
			
		||||
   modify it under the terms of the GNU Lesser General Public
 | 
			
		||||
   License as published by the Free Software Foundation; either
 | 
			
		||||
   version 2.1 of the License, or (at your option) any later version.
 | 
			
		||||
 | 
			
		||||
   This library is distributed in the hope that it will be useful,
 | 
			
		||||
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
			
		||||
   Lesser General Public License for more details.
 | 
			
		||||
 | 
			
		||||
   You should have received a copy of the GNU Lesser General Public
 | 
			
		||||
   License along with this library; if not, write to the Free Software
 | 
			
		||||
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 | 
			
		||||
 | 
			
		||||
#ifndef NJK_CHROOT_H_
 | 
			
		||||
#define NJK_CHROOT_H_ 1
 | 
			
		||||
void imprison(char *path);
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										12
									
								
								defines.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								defines.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
			
		||||
#define MAX_PATH_LENGTH 1024
 | 
			
		||||
#define PID_FILE_DEFAULT "/var/run/ifchd.pid"
 | 
			
		||||
#define IFCHD_VERSION "0.8"
 | 
			
		||||
 | 
			
		||||
#define COMM_SOCKET_PATH "ifchange"
 | 
			
		||||
#define MAX_BUF 1024
 | 
			
		||||
#define MAXLINE 1024
 | 
			
		||||
 | 
			
		||||
#define SOCK_QUEUE 2
 | 
			
		||||
#define CONN_TIMEOUT 60
 | 
			
		||||
#define LINUX 1
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										916
									
								
								ifchd.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										916
									
								
								ifchd.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,916 @@
 | 
			
		||||
/* ifchd.c - interface change daemon
 | 
			
		||||
 * Time-stamp: <2004-06-14 njk>
 | 
			
		||||
 *
 | 
			
		||||
 * (C) 2004 Nicholas J. Kain <njk@aerifal.cx>
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; if not, write to the Free Software
 | 
			
		||||
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <sys/socket.h>
 | 
			
		||||
#include <sys/un.h>
 | 
			
		||||
#include <sys/time.h>
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
 | 
			
		||||
#include <time.h>
 | 
			
		||||
#include <pwd.h>
 | 
			
		||||
#include <grp.h>
 | 
			
		||||
 | 
			
		||||
#include <signal.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
 | 
			
		||||
#define _GNU_SOURCE
 | 
			
		||||
#include <getopt.h>
 | 
			
		||||
 | 
			
		||||
#include "defines.h"
 | 
			
		||||
#include "log.h"
 | 
			
		||||
#include "chroot.h"
 | 
			
		||||
#include "pidfile.h"
 | 
			
		||||
#include "signals.h"
 | 
			
		||||
#include "strlist.h"
 | 
			
		||||
#include "ifproto.h"
 | 
			
		||||
#include "nstrl.h"
 | 
			
		||||
#include "linux.h"
 | 
			
		||||
 | 
			
		||||
enum states {
 | 
			
		||||
    STATE_NOTHING,
 | 
			
		||||
    STATE_INTERFACE,
 | 
			
		||||
    STATE_IP,
 | 
			
		||||
    STATE_SUBNET,
 | 
			
		||||
    STATE_TIMEZONE,
 | 
			
		||||
    STATE_ROUTER,
 | 
			
		||||
    STATE_TIMESVR,
 | 
			
		||||
    STATE_DNS,
 | 
			
		||||
    STATE_LPRSVR,
 | 
			
		||||
    STATE_HOSTNAME,
 | 
			
		||||
    STATE_DOMAIN,
 | 
			
		||||
    STATE_IPTTL,
 | 
			
		||||
    STATE_MTU,
 | 
			
		||||
    STATE_BROADCAST,
 | 
			
		||||
    STATE_NTPSRV,
 | 
			
		||||
    STATE_WINS
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static volatile sig_atomic_t pending_exit;
 | 
			
		||||
 | 
			
		||||
/* Socket fd, current state, and idle time for connections. */
 | 
			
		||||
static int sks[SOCK_QUEUE], state[SOCK_QUEUE], idle_time[SOCK_QUEUE];
 | 
			
		||||
 | 
			
		||||
/* Per-connection buffers. */
 | 
			
		||||
static char ibuf[SOCK_QUEUE][MAX_BUF];
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Per-connection pointers into the command lists.  Respectively, the
 | 
			
		||||
 * topmost item on the list, the current item, and the last item on the list.
 | 
			
		||||
 */
 | 
			
		||||
static strlist_t *head[SOCK_QUEUE], *curl[SOCK_QUEUE], *last[SOCK_QUEUE];
 | 
			
		||||
 | 
			
		||||
int resolv_conf_fd = -1;
 | 
			
		||||
/* int ntp_conf_fd = -1; */
 | 
			
		||||
 | 
			
		||||
/* If true, allow HOSTNAME changes from dhcp server. */
 | 
			
		||||
int allow_hostname = 0;
 | 
			
		||||
 | 
			
		||||
static uid_t peer_uid;
 | 
			
		||||
static gid_t peer_gid;
 | 
			
		||||
static pid_t peer_pid;
 | 
			
		||||
 | 
			
		||||
/* Lists of nameservers and search domains.  Unfortunately they must be
 | 
			
		||||
 * per-connection, since otherwise seperate clients could race against
 | 
			
		||||
 * one another to write out unpredictable data.
 | 
			
		||||
 */
 | 
			
		||||
static strlist_t *namesvrs[SOCK_QUEUE];
 | 
			
		||||
static strlist_t *domains[SOCK_QUEUE];
 | 
			
		||||
 | 
			
		||||
static void sighandler(int sig) {
 | 
			
		||||
    pending_exit = 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void fix_signals(void) {
 | 
			
		||||
    disable_signal(SIGPIPE);
 | 
			
		||||
    disable_signal(SIGUSR1);
 | 
			
		||||
    disable_signal(SIGUSR2);
 | 
			
		||||
    disable_signal(SIGTSTP);
 | 
			
		||||
    disable_signal(SIGTTIN);
 | 
			
		||||
    disable_signal(SIGCHLD);
 | 
			
		||||
    disable_signal(SIGHUP);
 | 
			
		||||
 | 
			
		||||
    hook_signal(SIGINT, sighandler, 0);
 | 
			
		||||
    hook_signal(SIGTERM, sighandler, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void suicide(char *errmsg, const char *perrmsg, int status)
 | 
			
		||||
{
 | 
			
		||||
    if (errmsg)
 | 
			
		||||
	log_line(errmsg);
 | 
			
		||||
    if (!gflags_detach && perrmsg)
 | 
			
		||||
	perror(perrmsg);
 | 
			
		||||
    exit(status);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void die_nulstr(strlist_t *p)
 | 
			
		||||
{
 | 
			
		||||
    if (!p)
 | 
			
		||||
	suicide("FATAL - NULL passed to die_nulstr\n", NULL, EXIT_FAILURE);
 | 
			
		||||
    if (!p->str)
 | 
			
		||||
	suicide("FATAL - NULL string in strlist\n", NULL, EXIT_FAILURE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Writes out each element in a strlist as an argument to a keyword in
 | 
			
		||||
 * a file. */
 | 
			
		||||
static void write_resolve_list(const char *keyword, strlist_t *list)
 | 
			
		||||
{
 | 
			
		||||
    char *buf;
 | 
			
		||||
    strlist_t *p = list;
 | 
			
		||||
    unsigned int len;
 | 
			
		||||
 | 
			
		||||
    if (!keyword || resolv_conf_fd == -1)
 | 
			
		||||
	return;
 | 
			
		||||
 | 
			
		||||
    while (p) {
 | 
			
		||||
	buf = p->str;
 | 
			
		||||
	len = strlen(buf);
 | 
			
		||||
	if (len) {
 | 
			
		||||
	    write(resolv_conf_fd, keyword, strlen(keyword));
 | 
			
		||||
	    write(resolv_conf_fd, buf, strlen(buf));
 | 
			
		||||
	    write(resolv_conf_fd, "\n", 1);
 | 
			
		||||
	}
 | 
			
		||||
	p = p->next;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Writes a new resolv.conf based on the information we have received. */
 | 
			
		||||
static void write_resolve_conf(int idx)
 | 
			
		||||
{
 | 
			
		||||
    off_t off;
 | 
			
		||||
 | 
			
		||||
    if (resolv_conf_fd == -1)
 | 
			
		||||
	return;
 | 
			
		||||
    if (lseek(resolv_conf_fd, 0, SEEK_SET) == -1)
 | 
			
		||||
	return;
 | 
			
		||||
 | 
			
		||||
    write_resolve_list("nameserver ", namesvrs[idx]);
 | 
			
		||||
    write_resolve_list("search ", domains[idx]);
 | 
			
		||||
    off = lseek(resolv_conf_fd, 0, SEEK_CUR);
 | 
			
		||||
    if (off == -1) {
 | 
			
		||||
	log_line("write_resolve_conf: lseek returned error: %s\n",
 | 
			
		||||
		strerror(errno));
 | 
			
		||||
	return;
 | 
			
		||||
    }
 | 
			
		||||
    ftruncate(resolv_conf_fd, off);
 | 
			
		||||
    fsync(resolv_conf_fd);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Decomposes a ' '-delimited flat character array onto a strlist, then
 | 
			
		||||
 * calls the given function to perform work on the generated strlist. */
 | 
			
		||||
static void parse_list(int idx, char *str, strlist_t **toplist,
 | 
			
		||||
                       void (*fn)(int))
 | 
			
		||||
{
 | 
			
		||||
    char *p, n[256];
 | 
			
		||||
    unsigned int i;
 | 
			
		||||
    strlist_t *newn = 0;
 | 
			
		||||
 | 
			
		||||
    if (!str || !toplist || !fn)
 | 
			
		||||
	return;
 | 
			
		||||
    p = str;
 | 
			
		||||
 | 
			
		||||
    while (p != '\0') {
 | 
			
		||||
	memset(n, '\0', sizeof n);
 | 
			
		||||
	for (i = 0; i < sizeof n - 1 && *p != '\0' && *p != ' '; ++p, ++i)
 | 
			
		||||
	    n[i] = *p;
 | 
			
		||||
	if (*p == ' ')
 | 
			
		||||
	    ++p;
 | 
			
		||||
	add_to_strlist(n, &newn);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (newn) {
 | 
			
		||||
	free_strlist(*toplist);
 | 
			
		||||
	*toplist = newn;
 | 
			
		||||
    } else
 | 
			
		||||
	return;
 | 
			
		||||
 | 
			
		||||
    (*fn)(idx);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* XXX: addme */
 | 
			
		||||
static void perform_timezone(int idx, char *str)
 | 
			
		||||
{}
 | 
			
		||||
 | 
			
		||||
/* Does anyone use this command? */
 | 
			
		||||
static void perform_timesvr(int idx, char *str)
 | 
			
		||||
{}
 | 
			
		||||
 | 
			
		||||
/* Add a dns server to the /etc/resolv.conf -- we already have a fd. */
 | 
			
		||||
static void perform_dns(int idx, char *str)
 | 
			
		||||
{
 | 
			
		||||
    if (!str || resolv_conf_fd == -1)
 | 
			
		||||
	return;
 | 
			
		||||
    parse_list(idx, str, &(namesvrs[idx]), &write_resolve_conf);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Updates for print daemons are too non-standard to be useful. */
 | 
			
		||||
static void perform_lprsvr(int idx, char *str)
 | 
			
		||||
{}
 | 
			
		||||
 | 
			
		||||
/* Sets machine hostname. */
 | 
			
		||||
static void perform_hostname(int idx, char *str)
 | 
			
		||||
{
 | 
			
		||||
    if (!allow_hostname || !str)
 | 
			
		||||
	return;
 | 
			
		||||
    if (sethostname(str, strlen(str) + 1) == -1)
 | 
			
		||||
	log_line("sethostname returned %s\n", strerror(errno));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* update "search" in /etc/resolv.conf */
 | 
			
		||||
static void perform_domain(int idx, char *str)
 | 
			
		||||
{
 | 
			
		||||
    if (!str || resolv_conf_fd == -1)
 | 
			
		||||
	return;
 | 
			
		||||
    parse_list(idx, str, &(domains[idx]), &write_resolve_conf);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* I don't think this can be done without a netfilter extension
 | 
			
		||||
 * that isn't in the mainline kernels. */
 | 
			
		||||
static void perform_ipttl(int idx, char *str)
 | 
			
		||||
{}
 | 
			
		||||
 | 
			
		||||
/* XXX: addme */
 | 
			
		||||
static void perform_ntpsrv(int idx, char *str)
 | 
			
		||||
{}
 | 
			
		||||
 | 
			
		||||
/* Maybe Samba cares about this feature?  I don't know. */
 | 
			
		||||
static void perform_wins(int idx, char *str)
 | 
			
		||||
{}
 | 
			
		||||
 | 
			
		||||
/* Wipes all state associated with a given connection. */
 | 
			
		||||
static void new_sk(int idx, int val) 
 | 
			
		||||
{
 | 
			
		||||
    sks[idx] = val;
 | 
			
		||||
    memset(ibuf[idx], '\0', sizeof(ibuf[idx]));
 | 
			
		||||
    free_strlist(head[idx]);
 | 
			
		||||
    free_strlist(namesvrs[idx]);
 | 
			
		||||
    free_strlist(domains[idx]);
 | 
			
		||||
    head[idx] = NULL;
 | 
			
		||||
    curl[idx] = NULL;
 | 
			
		||||
    last[idx] = NULL;
 | 
			
		||||
    namesvrs[idx] = NULL;
 | 
			
		||||
    domains[idx] = NULL;
 | 
			
		||||
    idle_time[idx] = time(NULL);
 | 
			
		||||
    state[idx] = STATE_NOTHING;
 | 
			
		||||
    clear_if_data(idx);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Conditionally accepts a new connection and initializes data structures. */
 | 
			
		||||
static void add_sk(int sk)
 | 
			
		||||
{
 | 
			
		||||
    int i;
 | 
			
		||||
 | 
			
		||||
    if (authorized_peer(sk, peer_pid, peer_uid, peer_gid)) {
 | 
			
		||||
	for (i=0; i<SOCK_QUEUE; i++)
 | 
			
		||||
	    if (sks[i] == -1) {
 | 
			
		||||
		new_sk(i, sk);
 | 
			
		||||
		return;
 | 
			
		||||
	    }
 | 
			
		||||
    }
 | 
			
		||||
    close(sk);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Closes idle connections. */
 | 
			
		||||
static void close_idle_sk(void)
 | 
			
		||||
{
 | 
			
		||||
    int i;
 | 
			
		||||
 | 
			
		||||
    for (i=0; i<SOCK_QUEUE; i++) {
 | 
			
		||||
	if (sks[i] == -1)
 | 
			
		||||
	    continue;
 | 
			
		||||
	if (time(NULL) - idle_time[i] > CONN_TIMEOUT) {
 | 
			
		||||
	    close(sks[i]);
 | 
			
		||||
	    new_sk(i, -1);
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Decomposes a ':'-delimited flat character array onto a strlist. */
 | 
			
		||||
static int stream_onto_list(int i)
 | 
			
		||||
{
 | 
			
		||||
    int e, s;
 | 
			
		||||
 | 
			
		||||
    for (e = 0, s = 0; ibuf[i][e] != '\0'; e++) {
 | 
			
		||||
	if (ibuf[i][e] == ':') {
 | 
			
		||||
	    /* Zero-length command: skip. */
 | 
			
		||||
	    if (s == e) {
 | 
			
		||||
		s = e + 1;
 | 
			
		||||
		continue;
 | 
			
		||||
	    }
 | 
			
		||||
	    curl[i] = malloc(sizeof(strlist_t));
 | 
			
		||||
 | 
			
		||||
	    if (curl[i] == NULL)
 | 
			
		||||
		suicide("FATAL - malloc failed\n", "malloc",
 | 
			
		||||
			EXIT_FAILURE);
 | 
			
		||||
 | 
			
		||||
	    if (head[i] == NULL) {
 | 
			
		||||
		head[i] = curl[i];
 | 
			
		||||
		last[i] = NULL;
 | 
			
		||||
	    }
 | 
			
		||||
 | 
			
		||||
	    curl[i]->next = NULL;
 | 
			
		||||
	    if (last[i] != NULL)
 | 
			
		||||
		last[i]->next = curl[i];
 | 
			
		||||
 | 
			
		||||
	    curl[i]->str = malloc(e - s + 1);
 | 
			
		||||
 | 
			
		||||
	    if (curl[i]->str == NULL)
 | 
			
		||||
		suicide("FATAL - malloc failed\n", "malloc",
 | 
			
		||||
			EXIT_FAILURE);
 | 
			
		||||
 | 
			
		||||
	    strlcpy(curl[i]->str, ibuf[i] + s, e - s);
 | 
			
		||||
	    last[i] = curl[i];
 | 
			
		||||
	    s = e + 1;
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
    return s;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* State machine that runs over the command and argument list,
 | 
			
		||||
 * executing commands. */
 | 
			
		||||
static void execute_list(int i)
 | 
			
		||||
{
 | 
			
		||||
    char *p;
 | 
			
		||||
 | 
			
		||||
    for (;;) {
 | 
			
		||||
	if (!curl[i])
 | 
			
		||||
	    break;
 | 
			
		||||
	die_nulstr(curl[i]);
 | 
			
		||||
 | 
			
		||||
	p = curl[i]->str;
 | 
			
		||||
 | 
			
		||||
	switch (state[i]) {
 | 
			
		||||
	    case STATE_NOTHING:
 | 
			
		||||
		if (strncmp(p, CMD_INTERFACE, sizeof(CMD_INTERFACE)) == 0)
 | 
			
		||||
		    state[i] = STATE_INTERFACE;
 | 
			
		||||
		if (strncmp(p, CMD_IP, sizeof(CMD_IP)) == 0)
 | 
			
		||||
		    state[i] = STATE_IP;
 | 
			
		||||
		if (strncmp(p, CMD_SUBNET, sizeof(CMD_SUBNET)) == 0)
 | 
			
		||||
		    state[i] = STATE_SUBNET;
 | 
			
		||||
		if (strncmp(p, CMD_TIMEZONE, sizeof(CMD_TIMEZONE)) == 0)
 | 
			
		||||
		    state[i] = STATE_TIMEZONE;
 | 
			
		||||
		if (strncmp(p, CMD_ROUTER, sizeof(CMD_ROUTER)) == 0)
 | 
			
		||||
		    state[i] = STATE_ROUTER;
 | 
			
		||||
		if (strncmp(p, CMD_TIMESVR, sizeof(CMD_TIMESVR)) == 0)
 | 
			
		||||
		    state[i] = STATE_TIMESVR;
 | 
			
		||||
		if (strncmp(p, CMD_DNS, sizeof(CMD_DNS)) == 0)
 | 
			
		||||
		    state[i] = STATE_DNS;
 | 
			
		||||
		if (strncmp(p, CMD_LPRSVR, sizeof(CMD_LPRSVR)) == 0)
 | 
			
		||||
		    state[i] = STATE_LPRSVR;
 | 
			
		||||
		if (strncmp(p, CMD_HOSTNAME, sizeof(CMD_HOSTNAME)) == 0)
 | 
			
		||||
		    state[i] = STATE_HOSTNAME;
 | 
			
		||||
		if (strncmp(p, CMD_DOMAIN, sizeof(CMD_DOMAIN)) == 0)
 | 
			
		||||
		    state[i] = STATE_DOMAIN;
 | 
			
		||||
		if (strncmp(p, CMD_IPTTL, sizeof(CMD_IPTTL)) == 0)
 | 
			
		||||
		    state[i] = STATE_IPTTL;
 | 
			
		||||
		if (strncmp(p, CMD_MTU, sizeof(CMD_MTU)) == 0)
 | 
			
		||||
		    state[i] = STATE_MTU;
 | 
			
		||||
		if (strncmp(p, CMD_BROADCAST, sizeof(CMD_BROADCAST)) == 0)
 | 
			
		||||
		    state[i] = STATE_BROADCAST;
 | 
			
		||||
		if (strncmp(p, CMD_NTPSRV, sizeof(CMD_NTPSRV)) == 0)
 | 
			
		||||
		    state[i] = STATE_NTPSRV;
 | 
			
		||||
		if (strncmp(p, CMD_WINS, sizeof(CMD_WINS)) == 0)
 | 
			
		||||
		    state[i] = STATE_WINS;
 | 
			
		||||
		free_stritem(&(curl[i]));
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	    case STATE_INTERFACE:
 | 
			
		||||
		perform_interface(i, p);
 | 
			
		||||
		free_stritem(&(curl[i]));
 | 
			
		||||
		state[i] = STATE_NOTHING;
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	    case STATE_IP:
 | 
			
		||||
		perform_ip(i, p);
 | 
			
		||||
		free_stritem(&(curl[i]));
 | 
			
		||||
		state[i] = STATE_NOTHING;
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	    case STATE_SUBNET:
 | 
			
		||||
		perform_subnet(i, p);
 | 
			
		||||
		free_stritem(&(curl[i]));
 | 
			
		||||
		state[i] = STATE_NOTHING;
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	    case STATE_TIMEZONE:
 | 
			
		||||
		perform_timezone(i, p);
 | 
			
		||||
		free_stritem(&(curl[i]));
 | 
			
		||||
		state[i] = STATE_NOTHING;
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	    case STATE_ROUTER:
 | 
			
		||||
		perform_router(i, p);
 | 
			
		||||
		free_stritem(&(curl[i]));
 | 
			
		||||
		state[i] = STATE_NOTHING;
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	    case STATE_TIMESVR:
 | 
			
		||||
		perform_timesvr(i, p);
 | 
			
		||||
		free_stritem(&(curl[i]));
 | 
			
		||||
		state[i] = STATE_NOTHING;
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	    case STATE_DNS:
 | 
			
		||||
		perform_dns(i, p);
 | 
			
		||||
		free_stritem(&(curl[i]));
 | 
			
		||||
		state[i] = STATE_NOTHING;
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	    case STATE_LPRSVR:
 | 
			
		||||
		perform_lprsvr(i, p);
 | 
			
		||||
		free_stritem(&(curl[i]));
 | 
			
		||||
		state[i] = STATE_NOTHING;
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	    case STATE_HOSTNAME:
 | 
			
		||||
		perform_hostname(i, p);
 | 
			
		||||
		free_stritem(&(curl[i]));
 | 
			
		||||
		state[i] = STATE_NOTHING;
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	    case STATE_DOMAIN:
 | 
			
		||||
		perform_domain(i, p);
 | 
			
		||||
		free_stritem(&(curl[i]));
 | 
			
		||||
		state[i] = STATE_NOTHING;
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	    case STATE_IPTTL:
 | 
			
		||||
		perform_ipttl(i, p);
 | 
			
		||||
		free_stritem(&(curl[i]));
 | 
			
		||||
		state[i] = STATE_NOTHING;
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	    case STATE_MTU:
 | 
			
		||||
		perform_mtu(i, p);
 | 
			
		||||
		free_stritem(&(curl[i]));
 | 
			
		||||
		state[i] = STATE_NOTHING;
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	    case STATE_BROADCAST:
 | 
			
		||||
		perform_broadcast(i, p);
 | 
			
		||||
		free_stritem(&(curl[i]));
 | 
			
		||||
		state[i] = STATE_NOTHING;
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	    case STATE_NTPSRV:
 | 
			
		||||
		perform_ntpsrv(i, p);
 | 
			
		||||
		free_stritem(&(curl[i]));
 | 
			
		||||
		state[i] = STATE_NOTHING;
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	    case STATE_WINS:
 | 
			
		||||
		perform_wins(i, p);
 | 
			
		||||
		free_stritem(&(curl[i]));
 | 
			
		||||
		state[i] = STATE_NOTHING;
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	    default:
 | 
			
		||||
		log_line("warning: invalid state in dispatch_work\n");
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
    head[i] = curl[i];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Opens a non-blocking listening socket with the appropriate properties. */
 | 
			
		||||
static int get_listen(void)
 | 
			
		||||
{
 | 
			
		||||
    int lsock, ret;
 | 
			
		||||
    struct sockaddr_un lsock_addr =
 | 
			
		||||
    {
 | 
			
		||||
	.sun_family = AF_UNIX,
 | 
			
		||||
	.sun_path = COMM_SOCKET_PATH
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    lsock = socket(PF_UNIX, SOCK_STREAM, 0);
 | 
			
		||||
    if (lsock == -1)
 | 
			
		||||
	suicide("FATAL - failed to create socket\n",
 | 
			
		||||
		"dispatch_work - socket", EXIT_FAILURE);
 | 
			
		||||
 | 
			
		||||
    fcntl(lsock, F_SETFL, O_NONBLOCK);
 | 
			
		||||
 | 
			
		||||
    (void) unlink(COMM_SOCKET_PATH);
 | 
			
		||||
    ret = bind(lsock, (struct sockaddr *) &lsock_addr, sizeof(lsock_addr));
 | 
			
		||||
    if (ret)
 | 
			
		||||
	suicide("FATAL - failed to bind socket\n",
 | 
			
		||||
		"dispatch_work - bind", EXIT_FAILURE);
 | 
			
		||||
    ret = chmod(COMM_SOCKET_PATH, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
 | 
			
		||||
    if (ret)
 | 
			
		||||
	suicide("FATAL - failed to chmod socket\n",
 | 
			
		||||
		"dispatch_work - chmod", EXIT_FAILURE);
 | 
			
		||||
    ret = listen(lsock, SOCK_QUEUE);
 | 
			
		||||
    if (ret)
 | 
			
		||||
	suicide("FATAL - failed to listen on socket\n",
 | 
			
		||||
		"dispatch_work - listen", EXIT_FAILURE);
 | 
			
		||||
 | 
			
		||||
    return lsock;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Abstracts away the details of accept()ing a socket connection. */
 | 
			
		||||
static void accept_conns(int *lsock)
 | 
			
		||||
{
 | 
			
		||||
    int ret;
 | 
			
		||||
    struct sockaddr_un sock_addr;
 | 
			
		||||
    socklen_t sock_len = sizeof(sock_addr);
 | 
			
		||||
 | 
			
		||||
    for(;;)
 | 
			
		||||
    {
 | 
			
		||||
	ret = accept(*lsock, (struct sockaddr *) &sock_addr, &sock_len);
 | 
			
		||||
	if (ret != -1) {
 | 
			
		||||
	    add_sk(ret);
 | 
			
		||||
	    return;
 | 
			
		||||
	}
 | 
			
		||||
	switch (errno) {
 | 
			
		||||
	    case EAGAIN:
 | 
			
		||||
#ifdef LINUX
 | 
			
		||||
	    case ENETDOWN:
 | 
			
		||||
	    case EPROTO:
 | 
			
		||||
	    case ENOPROTOOPT:
 | 
			
		||||
	    case EHOSTDOWN:
 | 
			
		||||
	    case ENONET:
 | 
			
		||||
	    case EHOSTUNREACH:
 | 
			
		||||
	    case EOPNOTSUPP:
 | 
			
		||||
	    case ENETUNREACH:
 | 
			
		||||
#endif
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	    case EINTR:
 | 
			
		||||
		continue;
 | 
			
		||||
 | 
			
		||||
	    case EBADF:
 | 
			
		||||
	    case ENOTSOCK:
 | 
			
		||||
	    case EINVAL:
 | 
			
		||||
		log_line("warning: accept returned %s!\n", strerror(errno));
 | 
			
		||||
		close(*lsock);
 | 
			
		||||
		*lsock = get_listen();
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	    case ECONNABORTED:
 | 
			
		||||
	    case EMFILE:
 | 
			
		||||
	    case ENFILE:
 | 
			
		||||
		log_line("warning: accept returned %s!\n", strerror(errno));
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	    default:
 | 
			
		||||
		log_line("warning: accept returned a mysterious error: %s\n",
 | 
			
		||||
			strerror(errno));
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Core function that handles connections, gathers input, and calls
 | 
			
		||||
 * the state machine to do actual work. */
 | 
			
		||||
static void dispatch_work(void)
 | 
			
		||||
{
 | 
			
		||||
    int lsock, ret, highfd, i, index;
 | 
			
		||||
    fd_set rfds;
 | 
			
		||||
    char buf[MAX_BUF];
 | 
			
		||||
 | 
			
		||||
    /* Initialize all structures to blank state. */
 | 
			
		||||
    for (i=0; i<SOCK_QUEUE; i++)
 | 
			
		||||
	sks[i] = -1;
 | 
			
		||||
    initialize_if_data();
 | 
			
		||||
 | 
			
		||||
    lsock = get_listen();
 | 
			
		||||
 | 
			
		||||
    for (;;) {
 | 
			
		||||
	FD_ZERO(&rfds);
 | 
			
		||||
	FD_SET(lsock, &rfds);
 | 
			
		||||
 | 
			
		||||
	/* find highest fd */
 | 
			
		||||
	for (i=0, highfd=0; i<SOCK_QUEUE; i++) {
 | 
			
		||||
	    if (sks[i] != -1) {
 | 
			
		||||
		FD_SET(sks[i], &rfds);
 | 
			
		||||
		if (sks[i] > highfd)
 | 
			
		||||
		    highfd = sks[i];
 | 
			
		||||
	    }
 | 
			
		||||
	}
 | 
			
		||||
	if (lsock > highfd)
 | 
			
		||||
	    highfd = lsock;
 | 
			
		||||
 | 
			
		||||
	ret = select(highfd + 1, &rfds, NULL, NULL, NULL);
 | 
			
		||||
	switch (ret) {
 | 
			
		||||
	    case 0:
 | 
			
		||||
		close_idle_sk();
 | 
			
		||||
		break;
 | 
			
		||||
	    case -1:
 | 
			
		||||
		if (pending_exit == 1)
 | 
			
		||||
		    return;
 | 
			
		||||
		suicide("FATAL - select returned an error!\n",
 | 
			
		||||
			"dispatch_work - select", EXIT_FAILURE);
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (pending_exit == 1)
 | 
			
		||||
	    return;
 | 
			
		||||
 | 
			
		||||
	/* handle pending connections */
 | 
			
		||||
	if (FD_ISSET(lsock, &rfds))
 | 
			
		||||
	    accept_conns(&lsock);
 | 
			
		||||
 | 
			
		||||
	/* Read in and process data on waiting connections */
 | 
			
		||||
	for (i=0; i<SOCK_QUEUE; i++) {
 | 
			
		||||
	    if (sks[i] == -1)
 | 
			
		||||
		continue;
 | 
			
		||||
	    if (!FD_ISSET(sks[i], &rfds))
 | 
			
		||||
		continue;
 | 
			
		||||
 | 
			
		||||
	    idle_time[i] = time(NULL);
 | 
			
		||||
	    memset(buf, '\0', sizeof(buf));
 | 
			
		||||
 | 
			
		||||
dispatch_work_read_again:
 | 
			
		||||
	    ret = (int) read(sks[i], buf, MAX_BUF / 2 - 1);
 | 
			
		||||
 | 
			
		||||
	    /* Check to see if peer closed socket */
 | 
			
		||||
	    if (ret == 0) {
 | 
			
		||||
		close(sks[i]);
 | 
			
		||||
		new_sk(i, -1);
 | 
			
		||||
		continue;
 | 
			
		||||
	    }
 | 
			
		||||
 | 
			
		||||
	    if (ret == -1) {
 | 
			
		||||
		if (errno == EINTR)
 | 
			
		||||
		    goto dispatch_work_read_again;
 | 
			
		||||
		log_line("dispatch_work: read returned %s.\n", strerror(errno));
 | 
			
		||||
		close(sks[i]);
 | 
			
		||||
		new_sk(i, -1);
 | 
			
		||||
		continue;
 | 
			
		||||
	    }
 | 
			
		||||
 | 
			
		||||
	    /* Discard everything and close connection if we risk overflow.
 | 
			
		||||
	     * This approach is maximally conservative... worst case is that
 | 
			
		||||
	     * some client requests will get dropped. */
 | 
			
		||||
	    index = strlen(ibuf[i]);
 | 
			
		||||
	    if (index + strlen(buf) > MAX_BUF - 2) {
 | 
			
		||||
		close(sks[i]);
 | 
			
		||||
		new_sk(i, -1);
 | 
			
		||||
		continue;
 | 
			
		||||
	    }
 | 
			
		||||
 | 
			
		||||
	    /* Append new stream input avoiding overflow. */
 | 
			
		||||
	    strlcpy(ibuf[i] + index, buf, sizeof(ibuf[i]) - index - 1);
 | 
			
		||||
 | 
			
		||||
	    /* Decompose ibuf contents onto strlist. */
 | 
			
		||||
	    index = stream_onto_list(i);
 | 
			
		||||
 | 
			
		||||
	    /* Remove everything that we've parsed into the list. */
 | 
			
		||||
	    strlcpy(buf, ibuf[i] + index, sizeof(buf));
 | 
			
		||||
	    strlcpy(ibuf[i], buf, sizeof(ibuf[i]));
 | 
			
		||||
 | 
			
		||||
	    /* Now we have a strlist of commands and arguments.
 | 
			
		||||
	     * Decompose and execute it. */
 | 
			
		||||
	    if (!head[i])
 | 
			
		||||
		continue;
 | 
			
		||||
	    curl[i] = head[i];
 | 
			
		||||
	    execute_list(i);
 | 
			
		||||
	}
 | 
			
		||||
	close_idle_sk();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main(int argc, char** argv) {
 | 
			
		||||
    int c, t, uid = 0, gid = 0;
 | 
			
		||||
    char pidfile[MAX_PATH_LENGTH] = PID_FILE_DEFAULT;
 | 
			
		||||
    char chrootd[MAX_PATH_LENGTH] = "";
 | 
			
		||||
    char resolv_conf_d[MAX_PATH_LENGTH] = "";
 | 
			
		||||
    char *p;
 | 
			
		||||
    struct passwd *pws;
 | 
			
		||||
    struct group *grp;
 | 
			
		||||
 | 
			
		||||
    while (1) {
 | 
			
		||||
	int option_index = 0;
 | 
			
		||||
	static struct option long_options[] = {
 | 
			
		||||
	    {"detach", 0, 0, 'd'},
 | 
			
		||||
	    {"nodetach", 0, 0, 'n'},
 | 
			
		||||
	    {"pidfile", 1, 0, 'p'},
 | 
			
		||||
	    {"quiet", 0, 0, 'q'},
 | 
			
		||||
	    {"chroot", 1, 0, 'c'},
 | 
			
		||||
	    {"resolve", 1, 0, 'r'},
 | 
			
		||||
	    {"hostname", 0, 0, 'o'},
 | 
			
		||||
	    {"user", 1, 0, 'u'},
 | 
			
		||||
	    {"group", 1, 0, 'g'},
 | 
			
		||||
	    {"cuser", 1, 0, 'U'},
 | 
			
		||||
	    {"cgroup", 1, 0, 'G'},
 | 
			
		||||
	    {"cpid", 1, 0, 'P'},
 | 
			
		||||
	    {"interface", 1, 0, 'i'},
 | 
			
		||||
	    {"help", 0, 0, 'h'},
 | 
			
		||||
	    {"version", 0, 0, 'v'},
 | 
			
		||||
	    {0, 0, 0, 0}
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	c = getopt_long(argc, argv, "dnp:qc:r:ou:g:U:G:P:i:hv", long_options,
 | 
			
		||||
	                &option_index);
 | 
			
		||||
	if (c == -1)
 | 
			
		||||
	    break;
 | 
			
		||||
 | 
			
		||||
	switch (c) {
 | 
			
		||||
 | 
			
		||||
	    case 'h':
 | 
			
		||||
		printf(
 | 
			
		||||
"ifchd %s, if change daemon.  Licensed under GNU GPL.\n", IFCHD_VERSION);
 | 
			
		||||
		printf(
 | 
			
		||||
"Copyright (C) 2004 Nicholas J. Kain\n"
 | 
			
		||||
"Usage: ifchd [OPTIONS]\n"
 | 
			
		||||
"  -d, --detach                detach from TTY and daemonize\n"
 | 
			
		||||
"  -n, --nodetach              stay attached to TTY\n"
 | 
			
		||||
"  -q, --quiet                 don't print to std(out|err) or log\n"
 | 
			
		||||
"  -c, --chroot                path where ifchd should chroot\n"
 | 
			
		||||
"  -r, --resolve               path to resolv.conf or equiv\n"
 | 
			
		||||
"  -o, --hostname              allow dhcp to set machine hostname\n"
 | 
			
		||||
"  -p, --pidfile               pidfile path\n");
 | 
			
		||||
		printf(
 | 
			
		||||
"  -u, --user                  user name that ifchd should run as\n"
 | 
			
		||||
"  -g, --group                 group name that ifchd should run as\n"
 | 
			
		||||
"  -U, --cuser                 user name of clients\n"
 | 
			
		||||
"  -G, --cgroup                group name of clients\n"
 | 
			
		||||
"  -P, --cpid                  process id of client\n"
 | 
			
		||||
"  -i, --interface             ifchd clients may modify this interface\n"
 | 
			
		||||
"  -h, --help                  print this help and exit\n"
 | 
			
		||||
"  -v, --version               print version information and exit\n");
 | 
			
		||||
		exit(EXIT_FAILURE);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	    case 'v':
 | 
			
		||||
		printf(
 | 
			
		||||
"ifchd %s, if change daemon.  Licensed under GNU GPL.\n", IFCHD_VERSION);
 | 
			
		||||
		printf(
 | 
			
		||||
"Copyright (C) 2004 Nicholas J. Kain\n"
 | 
			
		||||
"This is free software; see the source for copying conditions.  There is NO\n"
 | 
			
		||||
"WARRANTY; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n");
 | 
			
		||||
		exit(EXIT_FAILURE);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	    case 'd':
 | 
			
		||||
		gflags_detach = 1;
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	    case 'n':
 | 
			
		||||
		gflags_detach = 0;
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	    case 'q':
 | 
			
		||||
		gflags_quiet = 1;
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	    case 'c':
 | 
			
		||||
		strlcpy(chrootd, optarg, MAX_PATH_LENGTH);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	    case 'p':
 | 
			
		||||
		strlcpy(pidfile, optarg, MAX_PATH_LENGTH);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	    case 'r':
 | 
			
		||||
		strlcpy(resolv_conf_d, optarg, MAX_PATH_LENGTH);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	    case 'o':
 | 
			
		||||
		allow_hostname = 1;
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	    case 'u':
 | 
			
		||||
		t = (unsigned int) strtol(optarg, &p, 10);
 | 
			
		||||
		if (*p != '\0') {
 | 
			
		||||
		    pws = getpwnam(optarg);
 | 
			
		||||
		    if (pws) {
 | 
			
		||||
			uid = (int)pws->pw_uid;
 | 
			
		||||
			if (!gid)
 | 
			
		||||
			    gid = (int)pws->pw_gid;
 | 
			
		||||
		    } else suicide("FATAL - Invalid uid specified.\n", NULL,
 | 
			
		||||
			    EXIT_FAILURE);
 | 
			
		||||
		} else
 | 
			
		||||
		    uid = t;
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	    case 'g':
 | 
			
		||||
		t = (unsigned int) strtol(optarg, &p, 10);
 | 
			
		||||
		if (*p != '\0') {
 | 
			
		||||
		    grp = getgrnam(optarg);
 | 
			
		||||
		    if (grp) {
 | 
			
		||||
			gid = (int)grp->gr_gid;
 | 
			
		||||
		    } else suicide("FATAL - Invalid gid specified.\n", NULL,
 | 
			
		||||
			    EXIT_FAILURE);
 | 
			
		||||
		} else
 | 
			
		||||
		    gid = t;
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	    case 'U':
 | 
			
		||||
		t = (unsigned int) strtol(optarg, &p, 10);
 | 
			
		||||
		if (*p != '\0') {
 | 
			
		||||
		    pws = getpwnam(optarg);
 | 
			
		||||
		    if (pws) {
 | 
			
		||||
			peer_uid = (int)pws->pw_uid;
 | 
			
		||||
			if (!peer_gid)
 | 
			
		||||
			    peer_gid = (int)pws->pw_gid;
 | 
			
		||||
		    } else suicide("FATAL - Invalid uid specified.\n", NULL,
 | 
			
		||||
			    EXIT_FAILURE);
 | 
			
		||||
		} else
 | 
			
		||||
		    peer_uid = t;
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	    case 'G':
 | 
			
		||||
		t = (unsigned int) strtol(optarg, &p, 10);
 | 
			
		||||
		if (*p != '\0') {
 | 
			
		||||
		    grp = getgrnam(optarg);
 | 
			
		||||
		    if (grp) {
 | 
			
		||||
			peer_gid = (int)grp->gr_gid;
 | 
			
		||||
		    } else suicide("FATAL - Invalid gid specified.\n", NULL,
 | 
			
		||||
			    EXIT_FAILURE);
 | 
			
		||||
		} else
 | 
			
		||||
		    peer_gid = t;
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	    case 'P':
 | 
			
		||||
		t = (unsigned int) strtol(optarg, &p, 10);
 | 
			
		||||
		if (*p == '\0')
 | 
			
		||||
		    peer_pid = t;
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	    case 'i':
 | 
			
		||||
		add_permitted_if(optarg);
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (getuid())
 | 
			
		||||
	suicide("FATAL - I need root for CAP_NET_ADMIN and chroot!\n",
 | 
			
		||||
		NULL, EXIT_FAILURE);
 | 
			
		||||
 | 
			
		||||
    if (gflags_detach)
 | 
			
		||||
	if (daemon(0,0)) {
 | 
			
		||||
	    log_line("FATAL - detaching fork failed\n");
 | 
			
		||||
	    exit(EXIT_FAILURE);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    if (!file_exists(pidfile, "w")) {
 | 
			
		||||
	log_line("FATAL - cannot open pidfile for write!");
 | 
			
		||||
	exit(EXIT_FAILURE);
 | 
			
		||||
    }
 | 
			
		||||
    write_pid(pidfile);
 | 
			
		||||
 | 
			
		||||
    umask(077);
 | 
			
		||||
    fix_signals();
 | 
			
		||||
 | 
			
		||||
    /* If we are requested to update resolv.conf, preopen the fd before
 | 
			
		||||
     * we drop root privileges, making sure that if we create
 | 
			
		||||
     * resolv.conf, it will be world-readable.
 | 
			
		||||
     */
 | 
			
		||||
    if (strncmp(resolv_conf_d, "", MAX_PATH_LENGTH)) {
 | 
			
		||||
	umask(022);
 | 
			
		||||
	resolv_conf_fd = open(resolv_conf_d, O_RDWR | O_CREAT);
 | 
			
		||||
	umask(077);
 | 
			
		||||
	if (resolv_conf_fd == -1) {
 | 
			
		||||
	    suicide("FATAL - unable to open resolv.conf\n",
 | 
			
		||||
		    "main - open", EXIT_FAILURE);
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!strncmp(chrootd, "", MAX_PATH_LENGTH))
 | 
			
		||||
	suicide("FATAL - No chroot path specified.  Refusing to run.\n",
 | 
			
		||||
		NULL, EXIT_FAILURE);
 | 
			
		||||
 | 
			
		||||
    /* Note that failure cases are handled by called fns. */
 | 
			
		||||
    imprison(chrootd);
 | 
			
		||||
    drop_root(uid, gid, "cap_net_admin=ep");
 | 
			
		||||
 | 
			
		||||
    /* Cover our tracks... */
 | 
			
		||||
    memset(chrootd, '\0', sizeof(chrootd));
 | 
			
		||||
    memset(resolv_conf_d, '\0', sizeof(resolv_conf_d));
 | 
			
		||||
    memset(pidfile, '\0', sizeof(pidfile));
 | 
			
		||||
 | 
			
		||||
    dispatch_work();
 | 
			
		||||
 | 
			
		||||
    /* Explicitly freed so memory debugger output has less static. */
 | 
			
		||||
    for (c=0; c<SOCK_QUEUE; ++c) {
 | 
			
		||||
	free_strlist(head[c]);
 | 
			
		||||
	free_strlist(namesvrs[c]);
 | 
			
		||||
	free_strlist(domains[c]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    exit(EXIT_SUCCESS);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										20
									
								
								ifproto.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								ifproto.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
			
		||||
#ifndef NJK_IFPROTO_H__
 | 
			
		||||
#define NJK_IFPROTO_H__ 1
 | 
			
		||||
 | 
			
		||||
#define CMD_INTERFACE     "interface"
 | 
			
		||||
#define CMD_IP            "ip"
 | 
			
		||||
#define CMD_SUBNET        "subnet"
 | 
			
		||||
#define CMD_TIMEZONE      "timezone"
 | 
			
		||||
#define CMD_ROUTER        "router"
 | 
			
		||||
#define CMD_TIMESVR       "timesvr"
 | 
			
		||||
#define CMD_DNS           "dns"
 | 
			
		||||
#define CMD_LPRSVR        "lprsvr"
 | 
			
		||||
#define CMD_HOSTNAME      "hostname"
 | 
			
		||||
#define CMD_DOMAIN        "domain"
 | 
			
		||||
#define CMD_IPTTL         "ipttl"
 | 
			
		||||
#define CMD_MTU           "mtu"
 | 
			
		||||
#define CMD_BROADCAST     "broadcast"
 | 
			
		||||
#define CMD_NTPSRV        "ntpsrv"
 | 
			
		||||
#define CMD_WINS          "wins"
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										394
									
								
								linux.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										394
									
								
								linux.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,394 @@
 | 
			
		||||
/* linux.c - ifchd Linux-specific functions
 | 
			
		||||
 * Time-stamp: <2004-06-14 njk>
 | 
			
		||||
 *
 | 
			
		||||
 * (C) 2004 Nicholas J. Kain <njk@aerifal.cx>
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; if not, write to the Free Software
 | 
			
		||||
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#define __USE_GNU 1
 | 
			
		||||
#include <sys/socket.h>
 | 
			
		||||
#include <sys/un.h>
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <sys/capability.h>
 | 
			
		||||
#include <sys/prctl.h>
 | 
			
		||||
#include <sys/ioctl.h>
 | 
			
		||||
#include <netinet/in.h>
 | 
			
		||||
#include <arpa/inet.h>
 | 
			
		||||
#include <net/route.h>
 | 
			
		||||
#include <net/if.h>
 | 
			
		||||
#include <netpacket/packet.h>
 | 
			
		||||
#include <pwd.h>
 | 
			
		||||
#include <grp.h>
 | 
			
		||||
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
 | 
			
		||||
#include "defines.h"
 | 
			
		||||
#include "log.h"
 | 
			
		||||
#include "strlist.h"
 | 
			
		||||
#include "ifproto.h"
 | 
			
		||||
#include "nstrl.h"
 | 
			
		||||
 | 
			
		||||
/* Symbolic name of the interface associated with a connection. */
 | 
			
		||||
static char ifnam[SOCK_QUEUE][IFNAMSIZ];
 | 
			
		||||
static strlist_t *okif;
 | 
			
		||||
 | 
			
		||||
/* Clear a specified ifnam structure. */
 | 
			
		||||
void clear_if_data(int idx)
 | 
			
		||||
{
 | 
			
		||||
    memset(ifnam[idx], '\0', IFNAMSIZ);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Clear all ifnam structures. */
 | 
			
		||||
void initialize_if_data(void)
 | 
			
		||||
{
 | 
			
		||||
    int i;
 | 
			
		||||
    for (i = 0; i < SOCK_QUEUE; i++) {
 | 
			
		||||
	clear_if_data(i);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Adds to the list of interface names ifchd clients are allowed to change. */
 | 
			
		||||
void add_permitted_if(char *s)
 | 
			
		||||
{
 | 
			
		||||
    if (!s)
 | 
			
		||||
	return;
 | 
			
		||||
    add_to_strlist(s, &okif);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Checks if changes are permitted to a given interface.  1 == allowed */
 | 
			
		||||
static int is_permitted(char *name)
 | 
			
		||||
{
 | 
			
		||||
    strlist_t *p;
 | 
			
		||||
 | 
			
		||||
    /* If empty, permit all. */
 | 
			
		||||
    if (!okif)
 | 
			
		||||
	return 1;
 | 
			
		||||
 | 
			
		||||
    if (!name || strlen(name) == 0)
 | 
			
		||||
	return 0;
 | 
			
		||||
    p = okif;
 | 
			
		||||
    while (p) {
 | 
			
		||||
	if (strcmp(name, p->str) == 0)
 | 
			
		||||
	    return 1;
 | 
			
		||||
	p = p->next;
 | 
			
		||||
    }
 | 
			
		||||
    log_line("attempt to modify interface %s denied\n", name);
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Verify that peer is authorized to connect (return 1 on success). */
 | 
			
		||||
int authorized_peer(int sk, pid_t pid, uid_t uid, gid_t gid)
 | 
			
		||||
{
 | 
			
		||||
    int ret = 0;
 | 
			
		||||
    unsigned int cl;
 | 
			
		||||
    struct ucred cr;
 | 
			
		||||
 | 
			
		||||
    /* No credentials to verify. */
 | 
			
		||||
    if ( !(pid || uid || gid) )
 | 
			
		||||
	return 1;
 | 
			
		||||
 | 
			
		||||
    /* Verify that peer has authorized uid/gid/pid. */
 | 
			
		||||
    cl = sizeof(struct ucred);
 | 
			
		||||
    if (getsockopt(sk, SOL_SOCKET, SO_PEERCRED, &cr, &cl) != -1) {
 | 
			
		||||
	if ((pid == 0 || cr.pid == pid) ||
 | 
			
		||||
		(uid == 0 || cr.uid == uid) ||
 | 
			
		||||
		(gid == 0 || cr.gid == gid))
 | 
			
		||||
	    ret = 1;
 | 
			
		||||
    } else
 | 
			
		||||
	log_line("getsockopt returned an error: %s\n", strerror(errno));
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void perform_interface(int idx, char *str)
 | 
			
		||||
{
 | 
			
		||||
    if (!str)
 | 
			
		||||
	return;
 | 
			
		||||
 | 
			
		||||
    /* Update interface name. */
 | 
			
		||||
    memset(ifnam[idx], '\0', IFNAMSIZ);
 | 
			
		||||
    strlcpy(ifnam[idx], str, IFNAMSIZ);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int set_if_flag(int idx, short flag)
 | 
			
		||||
{
 | 
			
		||||
    int fd, ret = -1;
 | 
			
		||||
    struct ifreq ifrt;
 | 
			
		||||
 | 
			
		||||
    if (!is_permitted(ifnam[idx]))
 | 
			
		||||
	goto out0;
 | 
			
		||||
 | 
			
		||||
    fd = socket(PF_INET, SOCK_DGRAM, 0);
 | 
			
		||||
    if (fd == -1) {
 | 
			
		||||
	log_line("%s: (set_if_flag) failed to open interface socket: %s\n",
 | 
			
		||||
		ifnam[idx], strerror(errno));
 | 
			
		||||
	goto out0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    strlcpy(ifrt.ifr_name, ifnam[idx], IFNAMSIZ);
 | 
			
		||||
    if (ioctl(fd, SIOCGIFFLAGS, &ifrt) < 0) {
 | 
			
		||||
	log_line("%s: unknown interface: %s\n", ifnam[idx], strerror(errno));
 | 
			
		||||
	goto out1;
 | 
			
		||||
    }
 | 
			
		||||
    strlcpy(ifrt.ifr_name, ifnam[idx], IFNAMSIZ);
 | 
			
		||||
    ifrt.ifr_flags |= flag;
 | 
			
		||||
    if (ioctl(fd, SIOCSIFFLAGS, &ifrt) < 0) {
 | 
			
		||||
	log_line("%s: failed to set interface flags: %s\n",
 | 
			
		||||
		ifnam[idx], strerror(errno));
 | 
			
		||||
	goto out1;
 | 
			
		||||
    }
 | 
			
		||||
    ret = 0;
 | 
			
		||||
 | 
			
		||||
out1:
 | 
			
		||||
    close(fd);
 | 
			
		||||
out0:
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Sets IP address on an interface and brings it up. */
 | 
			
		||||
void perform_ip(int idx, char *str)
 | 
			
		||||
{
 | 
			
		||||
    int fd;
 | 
			
		||||
    struct in_addr ipaddr;
 | 
			
		||||
    struct ifreq ifrt;
 | 
			
		||||
    struct sockaddr_in sin;
 | 
			
		||||
 | 
			
		||||
    if (!str)
 | 
			
		||||
	return;
 | 
			
		||||
    if (!is_permitted(ifnam[idx]))
 | 
			
		||||
	return;
 | 
			
		||||
    if (!inet_aton(str, &ipaddr))
 | 
			
		||||
	return;
 | 
			
		||||
    if (set_if_flag(idx, (IFF_UP | IFF_RUNNING)))
 | 
			
		||||
	return;
 | 
			
		||||
 | 
			
		||||
    strlcpy(ifrt.ifr_name, ifnam[idx], IFNAMSIZ);
 | 
			
		||||
    memset(&sin, 0, sizeof(struct sockaddr));
 | 
			
		||||
    sin.sin_family = AF_INET;
 | 
			
		||||
    sin.sin_addr = ipaddr;
 | 
			
		||||
    memcpy(&ifrt.ifr_addr, &sin, sizeof(struct sockaddr));
 | 
			
		||||
 | 
			
		||||
    fd = socket(PF_INET, SOCK_DGRAM, 0);
 | 
			
		||||
    if (fd == -1) {
 | 
			
		||||
	log_line("%s: (perform_ip) failed to open interface socket: %s\n",
 | 
			
		||||
		ifnam[idx], strerror(errno));
 | 
			
		||||
	return;
 | 
			
		||||
    }
 | 
			
		||||
    if (ioctl(fd, SIOCSIFADDR, &ifrt) < 0)
 | 
			
		||||
	log_line("%s: failed to configure IP: %s\n",
 | 
			
		||||
		ifnam[idx], strerror(errno));
 | 
			
		||||
    close(fd);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Sets the subnet mask on an interface. */
 | 
			
		||||
void perform_subnet(int idx, char *str)
 | 
			
		||||
{
 | 
			
		||||
    int fd;
 | 
			
		||||
    struct in_addr subnet;
 | 
			
		||||
    struct ifreq ifrt;
 | 
			
		||||
    struct sockaddr_in sin;
 | 
			
		||||
 | 
			
		||||
    if (!str)
 | 
			
		||||
	return;
 | 
			
		||||
    if (!is_permitted(ifnam[idx]))
 | 
			
		||||
	return;
 | 
			
		||||
    if (!inet_aton(str, &subnet))
 | 
			
		||||
	return;
 | 
			
		||||
 | 
			
		||||
    strlcpy(ifrt.ifr_name, ifnam[idx], IFNAMSIZ);
 | 
			
		||||
    memset(&sin, 0, sizeof(struct sockaddr));
 | 
			
		||||
    sin.sin_family = AF_INET;
 | 
			
		||||
    sin.sin_addr = subnet;
 | 
			
		||||
    memcpy(&ifrt.ifr_addr, &sin, sizeof(struct sockaddr));
 | 
			
		||||
 | 
			
		||||
    fd = socket(PF_INET, SOCK_DGRAM, 0);
 | 
			
		||||
    if (fd == -1) {
 | 
			
		||||
	log_line("%s: (perform_ip) failed to open interface socket: %s\n",
 | 
			
		||||
		ifnam[idx], strerror(errno));
 | 
			
		||||
	return;
 | 
			
		||||
    }
 | 
			
		||||
    if (ioctl(fd, SIOCSIFNETMASK, &ifrt) < 0) {
 | 
			
		||||
	sin.sin_addr.s_addr = 0xffffffff;
 | 
			
		||||
	if (ioctl(fd, SIOCSIFNETMASK, &ifrt) < 0)
 | 
			
		||||
	    log_line("%s: failed to configure subnet: %s\n",
 | 
			
		||||
		    ifnam[idx], strerror(errno));
 | 
			
		||||
    }
 | 
			
		||||
    close(fd);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void perform_router(int idx, char *str)
 | 
			
		||||
{
 | 
			
		||||
    struct rtentry rt;
 | 
			
		||||
    struct sockaddr_in *dest;
 | 
			
		||||
    struct sockaddr_in *gateway;
 | 
			
		||||
    struct sockaddr_in *mask;
 | 
			
		||||
    struct in_addr router;
 | 
			
		||||
    int fd;
 | 
			
		||||
 | 
			
		||||
    if (!str)
 | 
			
		||||
	return;
 | 
			
		||||
    if (!is_permitted(ifnam[idx]))
 | 
			
		||||
	return;
 | 
			
		||||
    if (!inet_aton(str, &router))
 | 
			
		||||
	return;
 | 
			
		||||
 | 
			
		||||
    memset(&rt, 0, sizeof(struct rtentry));
 | 
			
		||||
    dest = (struct sockaddr_in *) &rt.rt_dst;
 | 
			
		||||
    dest->sin_family = AF_INET;
 | 
			
		||||
    dest->sin_addr.s_addr = 0x00000000;
 | 
			
		||||
    gateway = (struct sockaddr_in *) &rt.rt_gateway;
 | 
			
		||||
    gateway->sin_family = AF_INET;
 | 
			
		||||
    gateway->sin_addr = router;
 | 
			
		||||
    mask = (struct sockaddr_in *) &rt.rt_genmask;
 | 
			
		||||
    mask->sin_family = AF_INET;
 | 
			
		||||
    mask->sin_addr.s_addr = 0x00000000;
 | 
			
		||||
 | 
			
		||||
    rt.rt_flags = RTF_UP | RTF_GATEWAY;
 | 
			
		||||
    if (mask->sin_addr.s_addr == 0xffffffff) rt.rt_flags |= RTF_HOST;
 | 
			
		||||
    rt.rt_dev = ifnam[idx];
 | 
			
		||||
    rt.rt_metric = 1;
 | 
			
		||||
 | 
			
		||||
    fd = socket(PF_INET, SOCK_DGRAM, 0);
 | 
			
		||||
    if (fd == -1) {
 | 
			
		||||
	log_line("%s: (perform_router) failed to open interface socket: %s\n",
 | 
			
		||||
		ifnam[idx], strerror(errno));
 | 
			
		||||
	return;
 | 
			
		||||
    }
 | 
			
		||||
    if (ioctl(fd, SIOCADDRT, &rt))
 | 
			
		||||
	log_line("%s: failed to set route: %s\n", ifnam[idx], strerror(errno));
 | 
			
		||||
    close(fd);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void perform_mtu(int idx, char *str)
 | 
			
		||||
{
 | 
			
		||||
    int fd;
 | 
			
		||||
    unsigned int mtu;
 | 
			
		||||
    struct ifreq ifrt;
 | 
			
		||||
 | 
			
		||||
    if (!str)
 | 
			
		||||
	return;
 | 
			
		||||
    if (!is_permitted(ifnam[idx]))
 | 
			
		||||
	return;
 | 
			
		||||
 | 
			
		||||
    mtu = strtol(str, NULL, 10);
 | 
			
		||||
    ifrt.ifr_mtu = mtu;
 | 
			
		||||
    strlcpy(ifrt.ifr_name, ifnam[idx], IFNAMSIZ);
 | 
			
		||||
 | 
			
		||||
    fd = socket(PF_INET, SOCK_DGRAM, 0);
 | 
			
		||||
    if (fd == -1) {
 | 
			
		||||
	log_line("%s: (perform_mtu) failed to open interface socket: %s\n",
 | 
			
		||||
		ifnam[idx], strerror(errno));
 | 
			
		||||
	return;
 | 
			
		||||
    }
 | 
			
		||||
    if (ioctl(fd, SIOCSIFMTU, &ifrt) < 0)
 | 
			
		||||
	log_line("%s: failed to set MTU (%d): %s\n", ifnam[idx], mtu,
 | 
			
		||||
		strerror(errno));
 | 
			
		||||
    close(fd);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void perform_broadcast(int idx, char *str)
 | 
			
		||||
{
 | 
			
		||||
    int fd;
 | 
			
		||||
    struct in_addr broadcast;
 | 
			
		||||
    struct ifreq ifrt;
 | 
			
		||||
    struct sockaddr_in sin;
 | 
			
		||||
 | 
			
		||||
    if (!str)
 | 
			
		||||
	return;
 | 
			
		||||
    if (!is_permitted(ifnam[idx]))
 | 
			
		||||
	return;
 | 
			
		||||
    if (!inet_aton(str, &broadcast))
 | 
			
		||||
	return;
 | 
			
		||||
 | 
			
		||||
    strlcpy(ifrt.ifr_name, ifnam[idx], IFNAMSIZ);
 | 
			
		||||
    memset(&sin, 0, sizeof(struct sockaddr));
 | 
			
		||||
    sin.sin_family = AF_INET;
 | 
			
		||||
    sin.sin_addr = broadcast;
 | 
			
		||||
    memcpy(&ifrt.ifr_addr, &sin, sizeof(struct sockaddr));
 | 
			
		||||
 | 
			
		||||
    fd = socket(PF_INET, SOCK_DGRAM, 0);
 | 
			
		||||
    if (fd == -1) {
 | 
			
		||||
	log_line("%s: (perform_broadcast) failed to open interface socket: %s\n", ifnam[idx], strerror(errno));
 | 
			
		||||
	return;
 | 
			
		||||
    }
 | 
			
		||||
    if (ioctl(fd, SIOCSIFBRDADDR, &ifrt) < 0)
 | 
			
		||||
	log_line("%s: failed to set broadcast: %s\n",
 | 
			
		||||
		ifnam[idx], strerror(errno));
 | 
			
		||||
    close(fd);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void set_cap(uid_t uid, gid_t gid, char *captxt)
 | 
			
		||||
{
 | 
			
		||||
    cap_t caps;
 | 
			
		||||
 | 
			
		||||
    if (!captxt) {
 | 
			
		||||
	log_line("FATAL - set_cap: captxt == NULL\n");
 | 
			
		||||
	exit(EXIT_FAILURE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (prctl(PR_SET_KEEPCAPS, 1)) {
 | 
			
		||||
	log_line("FATAL - set_cap: prctl() failed\n");
 | 
			
		||||
	exit(EXIT_FAILURE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (setgroups(0, NULL) == -1) {
 | 
			
		||||
	log_line("FATAL - set_cap: setgroups() failed\n");
 | 
			
		||||
	exit(EXIT_FAILURE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (setegid(gid) == -1 || seteuid(uid) == -1) {
 | 
			
		||||
	log_line("FATAL - set_cap: seteuid() failed\n");
 | 
			
		||||
	exit(EXIT_FAILURE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    caps = cap_from_text(captxt);
 | 
			
		||||
    if (!caps) {
 | 
			
		||||
	log_line("FATAL - set_cap: cap_from_text() failed\n");
 | 
			
		||||
	exit(EXIT_FAILURE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (cap_set_proc(caps) == -1) {
 | 
			
		||||
	log_line("FATAL - set_cap: cap_set_proc() failed\n");
 | 
			
		||||
	exit(EXIT_FAILURE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    cap_free(caps);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void drop_root(uid_t uid, gid_t gid, char *captxt)
 | 
			
		||||
{
 | 
			
		||||
    if (!captxt) {
 | 
			
		||||
        log_line("FATAL - drop_root: captxt == NULL\n");
 | 
			
		||||
        exit(EXIT_FAILURE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (uid == 0 || gid == 0) {
 | 
			
		||||
        log_line("FATAL - drop_root: attempt to drop root to root?\n");
 | 
			
		||||
        exit(EXIT_FAILURE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    set_cap(uid, gid, captxt);
 | 
			
		||||
 | 
			
		||||
    if (setregid(gid, gid) == -1 || setreuid(uid, uid) == -1) {
 | 
			
		||||
        log_line("FATAL - drop_root: failed to drop root!\n");
 | 
			
		||||
        exit(EXIT_FAILURE);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										36
									
								
								linux.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								linux.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,36 @@
 | 
			
		||||
/* linux.h - ifchd Linux-specific functions include
 | 
			
		||||
 * Time-stamp: <2004-06-13 njk>
 | 
			
		||||
 *  
 | 
			
		||||
 * (C) 2004 Nicholas J. Kain <njk@aerifal.cx>
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; if not, write to the Free Software
 | 
			
		||||
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 | 
			
		||||
 * 
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef NJK_IFCHD_LINUX_H_
 | 
			
		||||
#define NJK_IFCHD_LINUX_H_ 1
 | 
			
		||||
void clear_if_data(int idx);
 | 
			
		||||
void initialize_if_data(void);
 | 
			
		||||
void add_permitted_if(char *s);
 | 
			
		||||
int authorized_peer(int sk, pid_t pid, uid_t uid, gid_t gid);
 | 
			
		||||
void perform_interface(int idx, char *str);
 | 
			
		||||
void perform_ip(int idx, char *str);
 | 
			
		||||
void perform_subnet(int idx, char *str);
 | 
			
		||||
void perform_router(int idx, char *str);
 | 
			
		||||
void perform_mtu(int idx, char *str);
 | 
			
		||||
void perform_broadcast(int idx, char *str);
 | 
			
		||||
void drop_root(uid_t uid, gid_t gid, char *captxt);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										46
									
								
								log.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								log.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,46 @@
 | 
			
		||||
/* log.c - simple logging support for ncron
 | 
			
		||||
   (C) 2003 Nicholas J. Kain <njk@aerifal.cx>
 | 
			
		||||
 | 
			
		||||
   This library is free software; you can redistribute it and/or
 | 
			
		||||
   modify it under the terms of the GNU Lesser General Public
 | 
			
		||||
   License as published by the Free Software Foundation; either
 | 
			
		||||
   version 2.1 of the License, or (at your option) any later version.
 | 
			
		||||
 | 
			
		||||
   This library is distributed in the hope that it will be useful,
 | 
			
		||||
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
			
		||||
   Lesser General Public License for more details.
 | 
			
		||||
 | 
			
		||||
   You should have received a copy of the GNU Lesser General Public
 | 
			
		||||
   License along with this library; if not, write to the Free Software
 | 
			
		||||
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <strings.h>
 | 
			
		||||
#include <syslog.h>
 | 
			
		||||
#include <stdarg.h>
 | 
			
		||||
#include "defines.h"
 | 
			
		||||
 | 
			
		||||
/* global logging flags */
 | 
			
		||||
int gflags_quiet = 0;
 | 
			
		||||
int gflags_detach = 1;
 | 
			
		||||
 | 
			
		||||
void log_line(char *format, ...) {
 | 
			
		||||
    va_list argp;
 | 
			
		||||
 | 
			
		||||
    if (format == NULL || gflags_quiet)
 | 
			
		||||
	return;
 | 
			
		||||
 | 
			
		||||
    if (gflags_detach) {
 | 
			
		||||
	openlog("ifchd", LOG_PID, LOG_DAEMON);
 | 
			
		||||
	va_start(argp, format);
 | 
			
		||||
	vsyslog(LOG_ERR | LOG_DAEMON, format, argp);
 | 
			
		||||
	va_end(argp);
 | 
			
		||||
	closelog();
 | 
			
		||||
    } else {
 | 
			
		||||
	va_start(argp, format);
 | 
			
		||||
	vfprintf(stderr, format, argp);
 | 
			
		||||
	va_end(argp);
 | 
			
		||||
    }
 | 
			
		||||
    closelog();
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										26
									
								
								log.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								log.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
			
		||||
/* log.h - simple logging support for ncron
 | 
			
		||||
   (C) 2003 Nicholas J. Kain <njk@aerifal.cx>
 | 
			
		||||
 | 
			
		||||
   This library is free software; you can redistribute it and/or
 | 
			
		||||
   modify it under the terms of the GNU Lesser General Public
 | 
			
		||||
   License as published by the Free Software Foundation; either
 | 
			
		||||
   version 2.1 of the License, or (at your option) any later version.
 | 
			
		||||
 | 
			
		||||
   This library is distributed in the hope that it will be useful,
 | 
			
		||||
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
			
		||||
   Lesser General Public License for more details.
 | 
			
		||||
 | 
			
		||||
   You should have received a copy of the GNU Lesser General Public
 | 
			
		||||
   License along with this library; if not, write to the Free Software
 | 
			
		||||
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 | 
			
		||||
 | 
			
		||||
#ifndef NJK_LOG_H_
 | 
			
		||||
#define NJK_LOG_H_ 1
 | 
			
		||||
 | 
			
		||||
extern int gflags_quiet;
 | 
			
		||||
extern int gflags_detach;
 | 
			
		||||
 | 
			
		||||
void log_line(char* format, ...);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										13
									
								
								ndhc/AUTHORS.udhcp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								ndhc/AUTHORS.udhcp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
			
		||||
udhcp server/client package
 | 
			
		||||
-----------------------
 | 
			
		||||
 | 
			
		||||
Russ Dill <Russ.Dill@asu.edu>
 | 
			
		||||
Matthew Ramsay	<matthewr@moreton.com.au>
 | 
			
		||||
Chris Trew <christ@moreton.com.au>
 | 
			
		||||
 | 
			
		||||
Other Credits:
 | 
			
		||||
--------------
 | 
			
		||||
Moreton Bay	(http://www.moretonbay.com/)
 | 
			
		||||
Lineo		(http://opensource.lineo.com)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										339
									
								
								ndhc/COPYING
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										339
									
								
								ndhc/COPYING
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,339 @@
 | 
			
		||||
		    GNU GENERAL PUBLIC LICENSE
 | 
			
		||||
		       Version 2, June 1991
 | 
			
		||||
 | 
			
		||||
 Copyright (C) 1989, 1991 Free Software Foundation, Inc.
 | 
			
		||||
                          675 Mass Ave, Cambridge, MA 02139, USA
 | 
			
		||||
 Everyone is permitted to copy and distribute verbatim copies
 | 
			
		||||
 of this license document, but changing it is not allowed.
 | 
			
		||||
 | 
			
		||||
			    Preamble
 | 
			
		||||
 | 
			
		||||
  The licenses for most software are designed to take away your
 | 
			
		||||
freedom to share and change it.  By contrast, the GNU General Public
 | 
			
		||||
License is intended to guarantee your freedom to share and change free
 | 
			
		||||
software--to make sure the software is free for all its users.  This
 | 
			
		||||
General Public License applies to most of the Free Software
 | 
			
		||||
Foundation's software and to any other program whose authors commit to
 | 
			
		||||
using it.  (Some other Free Software Foundation software is covered by
 | 
			
		||||
the GNU Library General Public License instead.)  You can apply it to
 | 
			
		||||
your programs, too.
 | 
			
		||||
 | 
			
		||||
  When we speak of free software, we are referring to freedom, not
 | 
			
		||||
price.  Our General Public Licenses are designed to make sure that you
 | 
			
		||||
have the freedom to distribute copies of free software (and charge for
 | 
			
		||||
this service if you wish), that you receive source code or can get it
 | 
			
		||||
if you want it, that you can change the software or use pieces of it
 | 
			
		||||
in new free programs; and that you know you can do these things.
 | 
			
		||||
 | 
			
		||||
  To protect your rights, we need to make restrictions that forbid
 | 
			
		||||
anyone to deny you these rights or to ask you to surrender the rights.
 | 
			
		||||
These restrictions translate to certain responsibilities for you if you
 | 
			
		||||
distribute copies of the software, or if you modify it.
 | 
			
		||||
 | 
			
		||||
  For example, if you distribute copies of such a program, whether
 | 
			
		||||
gratis or for a fee, you must give the recipients all the rights that
 | 
			
		||||
you have.  You must make sure that they, too, receive or can get the
 | 
			
		||||
source code.  And you must show them these terms so they know their
 | 
			
		||||
rights.
 | 
			
		||||
 | 
			
		||||
  We protect your rights with two steps: (1) copyright the software, and
 | 
			
		||||
(2) offer you this license which gives you legal permission to copy,
 | 
			
		||||
distribute and/or modify the software.
 | 
			
		||||
 | 
			
		||||
  Also, for each author's protection and ours, we want to make certain
 | 
			
		||||
that everyone understands that there is no warranty for this free
 | 
			
		||||
software.  If the software is modified by someone else and passed on, we
 | 
			
		||||
want its recipients to know that what they have is not the original, so
 | 
			
		||||
that any problems introduced by others will not reflect on the original
 | 
			
		||||
authors' reputations.
 | 
			
		||||
 | 
			
		||||
  Finally, any free program is threatened constantly by software
 | 
			
		||||
patents.  We wish to avoid the danger that redistributors of a free
 | 
			
		||||
program will individually obtain patent licenses, in effect making the
 | 
			
		||||
program proprietary.  To prevent this, we have made it clear that any
 | 
			
		||||
patent must be licensed for everyone's free use or not licensed at all.
 | 
			
		||||
 | 
			
		||||
  The precise terms and conditions for copying, distribution and
 | 
			
		||||
modification follow.
 | 
			
		||||
 | 
			
		||||
		    GNU GENERAL PUBLIC LICENSE
 | 
			
		||||
   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
 | 
			
		||||
 | 
			
		||||
  0. This License applies to any program or other work which contains
 | 
			
		||||
a notice placed by the copyright holder saying it may be distributed
 | 
			
		||||
under the terms of this General Public License.  The "Program", below,
 | 
			
		||||
refers to any such program or work, and a "work based on the Program"
 | 
			
		||||
means either the Program or any derivative work under copyright law:
 | 
			
		||||
that is to say, a work containing the Program or a portion of it,
 | 
			
		||||
either verbatim or with modifications and/or translated into another
 | 
			
		||||
language.  (Hereinafter, translation is included without limitation in
 | 
			
		||||
the term "modification".)  Each licensee is addressed as "you".
 | 
			
		||||
 | 
			
		||||
Activities other than copying, distribution and modification are not
 | 
			
		||||
covered by this License; they are outside its scope.  The act of
 | 
			
		||||
running the Program is not restricted, and the output from the Program
 | 
			
		||||
is covered only if its contents constitute a work based on the
 | 
			
		||||
Program (independent of having been made by running the Program).
 | 
			
		||||
Whether that is true depends on what the Program does.
 | 
			
		||||
 | 
			
		||||
  1. You may copy and distribute verbatim copies of the Program's
 | 
			
		||||
source code as you receive it, in any medium, provided that you
 | 
			
		||||
conspicuously and appropriately publish on each copy an appropriate
 | 
			
		||||
copyright notice and disclaimer of warranty; keep intact all the
 | 
			
		||||
notices that refer to this License and to the absence of any warranty;
 | 
			
		||||
and give any other recipients of the Program a copy of this License
 | 
			
		||||
along with the Program.
 | 
			
		||||
 | 
			
		||||
You may charge a fee for the physical act of transferring a copy, and
 | 
			
		||||
you may at your option offer warranty protection in exchange for a fee.
 | 
			
		||||
 | 
			
		||||
  2. You may modify your copy or copies of the Program or any portion
 | 
			
		||||
of it, thus forming a work based on the Program, and copy and
 | 
			
		||||
distribute such modifications or work under the terms of Section 1
 | 
			
		||||
above, provided that you also meet all of these conditions:
 | 
			
		||||
 | 
			
		||||
    a) You must cause the modified files to carry prominent notices
 | 
			
		||||
    stating that you changed the files and the date of any change.
 | 
			
		||||
 | 
			
		||||
    b) You must cause any work that you distribute or publish, that in
 | 
			
		||||
    whole or in part contains or is derived from the Program or any
 | 
			
		||||
    part thereof, to be licensed as a whole at no charge to all third
 | 
			
		||||
    parties under the terms of this License.
 | 
			
		||||
 | 
			
		||||
    c) If the modified program normally reads commands interactively
 | 
			
		||||
    when run, you must cause it, when started running for such
 | 
			
		||||
    interactive use in the most ordinary way, to print or display an
 | 
			
		||||
    announcement including an appropriate copyright notice and a
 | 
			
		||||
    notice that there is no warranty (or else, saying that you provide
 | 
			
		||||
    a warranty) and that users may redistribute the program under
 | 
			
		||||
    these conditions, and telling the user how to view a copy of this
 | 
			
		||||
    License.  (Exception: if the Program itself is interactive but
 | 
			
		||||
    does not normally print such an announcement, your work based on
 | 
			
		||||
    the Program is not required to print an announcement.)
 | 
			
		||||
 | 
			
		||||
These requirements apply to the modified work as a whole.  If
 | 
			
		||||
identifiable sections of that work are not derived from the Program,
 | 
			
		||||
and can be reasonably considered independent and separate works in
 | 
			
		||||
themselves, then this License, and its terms, do not apply to those
 | 
			
		||||
sections when you distribute them as separate works.  But when you
 | 
			
		||||
distribute the same sections as part of a whole which is a work based
 | 
			
		||||
on the Program, the distribution of the whole must be on the terms of
 | 
			
		||||
this License, whose permissions for other licensees extend to the
 | 
			
		||||
entire whole, and thus to each and every part regardless of who wrote it.
 | 
			
		||||
 | 
			
		||||
Thus, it is not the intent of this section to claim rights or contest
 | 
			
		||||
your rights to work written entirely by you; rather, the intent is to
 | 
			
		||||
exercise the right to control the distribution of derivative or
 | 
			
		||||
collective works based on the Program.
 | 
			
		||||
 | 
			
		||||
In addition, mere aggregation of another work not based on the Program
 | 
			
		||||
with the Program (or with a work based on the Program) on a volume of
 | 
			
		||||
a storage or distribution medium does not bring the other work under
 | 
			
		||||
the scope of this License.
 | 
			
		||||
 | 
			
		||||
  3. You may copy and distribute the Program (or a work based on it,
 | 
			
		||||
under Section 2) in object code or executable form under the terms of
 | 
			
		||||
Sections 1 and 2 above provided that you also do one of the following:
 | 
			
		||||
 | 
			
		||||
    a) Accompany it with the complete corresponding machine-readable
 | 
			
		||||
    source code, which must be distributed under the terms of Sections
 | 
			
		||||
    1 and 2 above on a medium customarily used for software interchange; or,
 | 
			
		||||
 | 
			
		||||
    b) Accompany it with a written offer, valid for at least three
 | 
			
		||||
    years, to give any third party, for a charge no more than your
 | 
			
		||||
    cost of physically performing source distribution, a complete
 | 
			
		||||
    machine-readable copy of the corresponding source code, to be
 | 
			
		||||
    distributed under the terms of Sections 1 and 2 above on a medium
 | 
			
		||||
    customarily used for software interchange; or,
 | 
			
		||||
 | 
			
		||||
    c) Accompany it with the information you received as to the offer
 | 
			
		||||
    to distribute corresponding source code.  (This alternative is
 | 
			
		||||
    allowed only for noncommercial distribution and only if you
 | 
			
		||||
    received the program in object code or executable form with such
 | 
			
		||||
    an offer, in accord with Subsection b above.)
 | 
			
		||||
 | 
			
		||||
The source code for a work means the preferred form of the work for
 | 
			
		||||
making modifications to it.  For an executable work, complete source
 | 
			
		||||
code means all the source code for all modules it contains, plus any
 | 
			
		||||
associated interface definition files, plus the scripts used to
 | 
			
		||||
control compilation and installation of the executable.  However, as a
 | 
			
		||||
special exception, the source code distributed need not include
 | 
			
		||||
anything that is normally distributed (in either source or binary
 | 
			
		||||
form) with the major components (compiler, kernel, and so on) of the
 | 
			
		||||
operating system on which the executable runs, unless that component
 | 
			
		||||
itself accompanies the executable.
 | 
			
		||||
 | 
			
		||||
If distribution of executable or object code is made by offering
 | 
			
		||||
access to copy from a designated place, then offering equivalent
 | 
			
		||||
access to copy the source code from the same place counts as
 | 
			
		||||
distribution of the source code, even though third parties are not
 | 
			
		||||
compelled to copy the source along with the object code.
 | 
			
		||||
 | 
			
		||||
  4. You may not copy, modify, sublicense, or distribute the Program
 | 
			
		||||
except as expressly provided under this License.  Any attempt
 | 
			
		||||
otherwise to copy, modify, sublicense or distribute the Program is
 | 
			
		||||
void, and will automatically terminate your rights under this License.
 | 
			
		||||
However, parties who have received copies, or rights, from you under
 | 
			
		||||
this License will not have their licenses terminated so long as such
 | 
			
		||||
parties remain in full compliance.
 | 
			
		||||
 | 
			
		||||
  5. You are not required to accept this License, since you have not
 | 
			
		||||
signed it.  However, nothing else grants you permission to modify or
 | 
			
		||||
distribute the Program or its derivative works.  These actions are
 | 
			
		||||
prohibited by law if you do not accept this License.  Therefore, by
 | 
			
		||||
modifying or distributing the Program (or any work based on the
 | 
			
		||||
Program), you indicate your acceptance of this License to do so, and
 | 
			
		||||
all its terms and conditions for copying, distributing or modifying
 | 
			
		||||
the Program or works based on it.
 | 
			
		||||
 | 
			
		||||
  6. Each time you redistribute the Program (or any work based on the
 | 
			
		||||
Program), the recipient automatically receives a license from the
 | 
			
		||||
original licensor to copy, distribute or modify the Program subject to
 | 
			
		||||
these terms and conditions.  You may not impose any further
 | 
			
		||||
restrictions on the recipients' exercise of the rights granted herein.
 | 
			
		||||
You are not responsible for enforcing compliance by third parties to
 | 
			
		||||
this License.
 | 
			
		||||
 | 
			
		||||
  7. If, as a consequence of a court judgment or allegation of patent
 | 
			
		||||
infringement or for any other reason (not limited to patent issues),
 | 
			
		||||
conditions are imposed on you (whether by court order, agreement or
 | 
			
		||||
otherwise) that contradict the conditions of this License, they do not
 | 
			
		||||
excuse you from the conditions of this License.  If you cannot
 | 
			
		||||
distribute so as to satisfy simultaneously your obligations under this
 | 
			
		||||
License and any other pertinent obligations, then as a consequence you
 | 
			
		||||
may not distribute the Program at all.  For example, if a patent
 | 
			
		||||
license would not permit royalty-free redistribution of the Program by
 | 
			
		||||
all those who receive copies directly or indirectly through you, then
 | 
			
		||||
the only way you could satisfy both it and this License would be to
 | 
			
		||||
refrain entirely from distribution of the Program.
 | 
			
		||||
 | 
			
		||||
If any portion of this section is held invalid or unenforceable under
 | 
			
		||||
any particular circumstance, the balance of the section is intended to
 | 
			
		||||
apply and the section as a whole is intended to apply in other
 | 
			
		||||
circumstances.
 | 
			
		||||
 | 
			
		||||
It is not the purpose of this section to induce you to infringe any
 | 
			
		||||
patents or other property right claims or to contest validity of any
 | 
			
		||||
such claims; this section has the sole purpose of protecting the
 | 
			
		||||
integrity of the free software distribution system, which is
 | 
			
		||||
implemented by public license practices.  Many people have made
 | 
			
		||||
generous contributions to the wide range of software distributed
 | 
			
		||||
through that system in reliance on consistent application of that
 | 
			
		||||
system; it is up to the author/donor to decide if he or she is willing
 | 
			
		||||
to distribute software through any other system and a licensee cannot
 | 
			
		||||
impose that choice.
 | 
			
		||||
 | 
			
		||||
This section is intended to make thoroughly clear what is believed to
 | 
			
		||||
be a consequence of the rest of this License.
 | 
			
		||||
 | 
			
		||||
  8. If the distribution and/or use of the Program is restricted in
 | 
			
		||||
certain countries either by patents or by copyrighted interfaces, the
 | 
			
		||||
original copyright holder who places the Program under this License
 | 
			
		||||
may add an explicit geographical distribution limitation excluding
 | 
			
		||||
those countries, so that distribution is permitted only in or among
 | 
			
		||||
countries not thus excluded.  In such case, this License incorporates
 | 
			
		||||
the limitation as if written in the body of this License.
 | 
			
		||||
 | 
			
		||||
  9. The Free Software Foundation may publish revised and/or new versions
 | 
			
		||||
of the General Public License from time to time.  Such new versions will
 | 
			
		||||
be similar in spirit to the present version, but may differ in detail to
 | 
			
		||||
address new problems or concerns.
 | 
			
		||||
 | 
			
		||||
Each version is given a distinguishing version number.  If the Program
 | 
			
		||||
specifies a version number of this License which applies to it and "any
 | 
			
		||||
later version", you have the option of following the terms and conditions
 | 
			
		||||
either of that version or of any later version published by the Free
 | 
			
		||||
Software Foundation.  If the Program does not specify a version number of
 | 
			
		||||
this License, you may choose any version ever published by the Free Software
 | 
			
		||||
Foundation.
 | 
			
		||||
 | 
			
		||||
  10. If you wish to incorporate parts of the Program into other free
 | 
			
		||||
programs whose distribution conditions are different, write to the author
 | 
			
		||||
to ask for permission.  For software which is copyrighted by the Free
 | 
			
		||||
Software Foundation, write to the Free Software Foundation; we sometimes
 | 
			
		||||
make exceptions for this.  Our decision will be guided by the two goals
 | 
			
		||||
of preserving the free status of all derivatives of our free software and
 | 
			
		||||
of promoting the sharing and reuse of software generally.
 | 
			
		||||
 | 
			
		||||
			    NO WARRANTY
 | 
			
		||||
 | 
			
		||||
  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
 | 
			
		||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
 | 
			
		||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
 | 
			
		||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
 | 
			
		||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 | 
			
		||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
 | 
			
		||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
 | 
			
		||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
 | 
			
		||||
REPAIR OR CORRECTION.
 | 
			
		||||
 | 
			
		||||
  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
 | 
			
		||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
 | 
			
		||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
 | 
			
		||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
 | 
			
		||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
 | 
			
		||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
 | 
			
		||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
 | 
			
		||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
 | 
			
		||||
POSSIBILITY OF SUCH DAMAGES.
 | 
			
		||||
 | 
			
		||||
		     END OF TERMS AND CONDITIONS
 | 
			
		||||
 | 
			
		||||
	Appendix: How to Apply These Terms to Your New Programs
 | 
			
		||||
 | 
			
		||||
  If you develop a new program, and you want it to be of the greatest
 | 
			
		||||
possible use to the public, the best way to achieve this is to make it
 | 
			
		||||
free software which everyone can redistribute and change under these terms.
 | 
			
		||||
 | 
			
		||||
  To do so, attach the following notices to the program.  It is safest
 | 
			
		||||
to attach them to the start of each source file to most effectively
 | 
			
		||||
convey the exclusion of warranty; and each file should have at least
 | 
			
		||||
the "copyright" line and a pointer to where the full notice is found.
 | 
			
		||||
 | 
			
		||||
    <one line to give the program's name and a brief idea of what it does.>
 | 
			
		||||
    Copyright (C) 19yy  <name of author>
 | 
			
		||||
 | 
			
		||||
    This program is free software; you can redistribute it and/or modify
 | 
			
		||||
    it under the terms of the GNU General Public License as published by
 | 
			
		||||
    the Free Software Foundation; either version 2 of the License, or
 | 
			
		||||
    (at your option) any later version.
 | 
			
		||||
 | 
			
		||||
    This program is distributed in the hope that it will be useful,
 | 
			
		||||
    but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
    GNU General Public License for more details.
 | 
			
		||||
 | 
			
		||||
    You should have received a copy of the GNU General Public License
 | 
			
		||||
    along with this program; if not, write to the Free Software
 | 
			
		||||
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 | 
			
		||||
 | 
			
		||||
Also add information on how to contact you by electronic and paper mail.
 | 
			
		||||
 | 
			
		||||
If the program is interactive, make it output a short notice like this
 | 
			
		||||
when it starts in an interactive mode:
 | 
			
		||||
 | 
			
		||||
    Gnomovision version 69, Copyright (C) 19yy name of author
 | 
			
		||||
    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
 | 
			
		||||
    This is free software, and you are welcome to redistribute it
 | 
			
		||||
    under certain conditions; type `show c' for details.
 | 
			
		||||
 | 
			
		||||
The hypothetical commands `show w' and `show c' should show the appropriate
 | 
			
		||||
parts of the General Public License.  Of course, the commands you use may
 | 
			
		||||
be called something other than `show w' and `show c'; they could even be
 | 
			
		||||
mouse-clicks or menu items--whatever suits your program.
 | 
			
		||||
 | 
			
		||||
You should also get your employer (if you work as a programmer) or your
 | 
			
		||||
school, if any, to sign a "copyright disclaimer" for the program, if
 | 
			
		||||
necessary.  Here is a sample; alter the names:
 | 
			
		||||
 | 
			
		||||
  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
 | 
			
		||||
  `Gnomovision' (which makes passes at compilers) written by James Hacker.
 | 
			
		||||
 | 
			
		||||
  <signature of Ty Coon>, 1 April 1989
 | 
			
		||||
  Ty Coon, President of Vice
 | 
			
		||||
 | 
			
		||||
This General Public License does not permit incorporating your program into
 | 
			
		||||
proprietary programs.  If your program is a subroutine library, you may
 | 
			
		||||
consider it more useful to permit linking proprietary applications with the
 | 
			
		||||
library.  If this is what you want to do, use the GNU Library General
 | 
			
		||||
Public License instead of this License.
 | 
			
		||||
							
								
								
									
										43
									
								
								ndhc/MODIFICATIONS
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								ndhc/MODIFICATIONS
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,43 @@
 | 
			
		||||
All modifications are to udhcp 0.9.8
 | 
			
		||||
All bugs should be blamed on Nicholas Kain, not the udhcp folks!
 | 
			
		||||
 | 
			
		||||
Great thanks go to the authors of udhcp (primarily Russ Dill), from which
 | 
			
		||||
ndhc is adapted.
 | 
			
		||||
 | 
			
		||||
CHANGES
 | 
			
		||||
-------
 | 
			
		||||
 | 
			
		||||
C99 compiler required
 | 
			
		||||
 | 
			
		||||
removed dhcp server support (use mainline udhcp)
 | 
			
		||||
removed sample scripts
 | 
			
		||||
added chroot support
 | 
			
		||||
added capability support
 | 
			
		||||
added setuid/setgid support
 | 
			
		||||
run_script now takes int argument (from enum)
 | 
			
		||||
script.c heavily modified to call ifchd
 | 
			
		||||
stripped command line option for custom script
 | 
			
		||||
bounds check all string functions
 | 
			
		||||
removed pidfile support: backgrounding model + chroot preclude it
 | 
			
		||||
manpage updated
 | 
			
		||||
removed busybox compat wrapper
 | 
			
		||||
convert all strncpy -> strlcpy
 | 
			
		||||
u_int*_t -> uint*_t (C99)
 | 
			
		||||
add_simple_option no longer does unspeakable things to the C language
 | 
			
		||||
character signedness issues fixed
 | 
			
		||||
casting bug [dhcpc.c:549 sizeof(signal) should be sizeof sig]
 | 
			
		||||
	- won't bite except on an architecture where sizeof fnptr != sizeof int
 | 
			
		||||
LOG and DEBUG are abolished - functions are used instead, see log.c/log.h
 | 
			
		||||
C99 structure initializers used exclusively (C99)
 | 
			
		||||
Linux kernel headers no longer used under any circumstances.
 | 
			
		||||
	- this is likely to break prehistoric systems running <glibc 2.1
 | 
			
		||||
exit() return codes now use EXIT_(SUCCESS|FAILURE) #defines and make more sense
 | 
			
		||||
close fd leak on failure in read_interface()
 | 
			
		||||
close fd leak on failure in kernel_packet()
 | 
			
		||||
char buffer[16] in perform_release() should not be static
 | 
			
		||||
don't bother to use a signal pipe - instead use static sig_atomic_t bools
 | 
			
		||||
convert lots of #defines to enums
 | 
			
		||||
break apart main client loop into maintainable functions
 | 
			
		||||
more discerning error handling
 | 
			
		||||
boundary check end_option()
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										69
									
								
								ndhc/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								ndhc/Makefile
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,69 @@
 | 
			
		||||
# ndhc makefile
 | 
			
		||||
 | 
			
		||||
prefix=/usr
 | 
			
		||||
SBINDIR=/sbin
 | 
			
		||||
USRSBINDIR=${prefix}/sbin
 | 
			
		||||
USRBINDIR=${prefix}/bin
 | 
			
		||||
USRSHAREDIR=${prefix}/share
 | 
			
		||||
 | 
			
		||||
# Uncomment this for extra output and to compile with debugging symbols
 | 
			
		||||
#DEBUG=1
 | 
			
		||||
 | 
			
		||||
#CROSS_COMPILE=arm-uclibc-
 | 
			
		||||
CC = $(CROSS_COMPILE)gcc
 | 
			
		||||
LD = $(CROSS_COMPILE)gcc
 | 
			
		||||
INSTALL = install
 | 
			
		||||
 | 
			
		||||
VER := 0.9.8
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
OBJS_SHARED = nstrl.o log.o options.o socket.o packet.o rootcap.o
 | 
			
		||||
DHCPC_OBJS = dhcpc.o clientpacket.o script.o
 | 
			
		||||
 | 
			
		||||
EXEC2 = ndhc
 | 
			
		||||
OBJS2 = -lcap $(DHCPC_OBJS) $(OBJS_SHARED)
 | 
			
		||||
 | 
			
		||||
BOOT_PROGRAMS = ndhc
 | 
			
		||||
 | 
			
		||||
ifdef SYSLOG
 | 
			
		||||
CFLAGS += -DSYSLOG
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
CFLAGS += -W -Wall -Wstrict-prototypes -DVERSION='"$(VER)"'
 | 
			
		||||
 | 
			
		||||
ifdef DEBUG
 | 
			
		||||
CFLAGS += -g -DDEBUG
 | 
			
		||||
STRIP=true
 | 
			
		||||
else
 | 
			
		||||
CFLAGS += -Os -fomit-frame-pointer
 | 
			
		||||
STRIP=$(CROSS_COMPILE)strip
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
all: $(EXEC2) 
 | 
			
		||||
	$(STRIP) --remove-section=.note --remove-section=.comment $(EXEC2)
 | 
			
		||||
 | 
			
		||||
$(OBJS2) $(OBJS3): *.h Makefile
 | 
			
		||||
$(EXEC2): Makefile
 | 
			
		||||
 | 
			
		||||
.c.o:
 | 
			
		||||
	$(CC) -c $(CFLAGS) $<
 | 
			
		||||
	
 | 
			
		||||
$(EXEC2): $(OBJS2)
 | 
			
		||||
	$(LD) $(LDFLAGS) $(OBJS2) -o $(EXEC2)
 | 
			
		||||
 | 
			
		||||
tags:
 | 
			
		||||
	-ctags -f tags *.[ch]
 | 
			
		||||
	-cscope -b
 | 
			
		||||
 | 
			
		||||
install: all
 | 
			
		||||
 | 
			
		||||
	$(INSTALL) $(BOOT_PROGRAMS) $(USRSBINDIR)
 | 
			
		||||
	mkdir -p $(USRSHAREDIR)/man/man8
 | 
			
		||||
	$(INSTALL) ndhc.8 ndhc.8 $(USRSHAREDIR)/man/man8
 | 
			
		||||
 | 
			
		||||
clean:
 | 
			
		||||
	-rm -f ndhc *.o core
 | 
			
		||||
 | 
			
		||||
distclean:
 | 
			
		||||
	-rm -f ndhc *.o tags cscope.out
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										54
									
								
								ndhc/README
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								ndhc/README
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,54 @@
 | 
			
		||||
ndhc client
 | 
			
		||||
--------------------
 | 
			
		||||
 | 
			
		||||
The ndhc client negotiates a lease with the DHCP server and notifies
 | 
			
		||||
ifchd when a leases is obtained or lost.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
command line options
 | 
			
		||||
-------------------
 | 
			
		||||
 | 
			
		||||
The command line options for the ndhc client are:
 | 
			
		||||
 | 
			
		||||
-c, --clientid=CLIENTID         Client identifier
 | 
			
		||||
-H, --hostname=HOSTNAME         Client hostname
 | 
			
		||||
-h,				Alias for -H
 | 
			
		||||
-f, --foreground                Do not fork after getting lease
 | 
			
		||||
-b, --background                Fork to background if lease cannot be
 | 
			
		||||
                                immediately negotiated.
 | 
			
		||||
-i, --interface=INTERFACE       Interface to use (default: eth0)
 | 
			
		||||
-n, --now                       Exit with failure if lease cannot be
 | 
			
		||||
                                immediately negotiated.
 | 
			
		||||
-q, --quit                      Quit after obtaining lease
 | 
			
		||||
-r, --request=IP                IP address to request (default: none)
 | 
			
		||||
-v, --version                   Display version
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
If the requested IP address cannot be obtained, the client accepts the
 | 
			
		||||
address that the server offers.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
note on ndhc's random seed
 | 
			
		||||
---------------------------
 | 
			
		||||
 | 
			
		||||
ndhc will seed its random number generator (used for generating xid's)
 | 
			
		||||
by reading /dev/urandom. If you have a lot of embedded systems on the same
 | 
			
		||||
network, with no entropy, you can either seed /dev/urandom by a method of
 | 
			
		||||
your own, or doing the following on startup:
 | 
			
		||||
 | 
			
		||||
ifconfig eth0 > /dev/urandom
 | 
			
		||||
 | 
			
		||||
in order to seed /dev/urandom with some data (mac address) unique to your
 | 
			
		||||
system. If reading /dev/urandom fails, ndhc will fall back to its old
 | 
			
		||||
behavior of seeding with time(0).
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
signals accepted by ndhc
 | 
			
		||||
-------------------------
 | 
			
		||||
 | 
			
		||||
ndhc also responds to SIGUSR1 and SIGUSR2. SIGUSR1 will force a renew state,
 | 
			
		||||
and SIGUSR2 will force a release of the current lease, and cause ndhc to
 | 
			
		||||
go into an inactive state (until it is killed, or receives a SIGUSR1). You do
 | 
			
		||||
not need to sleep between sending signals, as signals received are processed
 | 
			
		||||
sequencially in the order they are received.
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										7
									
								
								ndhc/TODO
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								ndhc/TODO
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
			
		||||
TODO
 | 
			
		||||
----
 | 
			
		||||
+ using time(0) breaks if the system clock changes, find a portable solution
 | 
			
		||||
+ make failure of reading functions revert to previous value, not the default
 | 
			
		||||
+ sanity code for option[OPT_LEN]
 | 
			
		||||
+ fix aliasing (ie: eth0:0)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										256
									
								
								ndhc/clientpacket.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										256
									
								
								ndhc/clientpacket.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,256 @@
 | 
			
		||||
/* clientpacket.c
 | 
			
		||||
 *
 | 
			
		||||
 * Packet generation and dispatching functions for the DHCP client.
 | 
			
		||||
 *
 | 
			
		||||
 * Russ Dill <Russ.Dill@asu.edu> July 2001
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; if not, write to the Free Software
 | 
			
		||||
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 | 
			
		||||
 */
 | 
			
		||||
 
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <sys/socket.h>
 | 
			
		||||
#include <features.h>
 | 
			
		||||
#include <netpacket/packet.h>
 | 
			
		||||
#include <net/ethernet.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <time.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <netinet/in.h>
 | 
			
		||||
#include <arpa/inet.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
 | 
			
		||||
#include "dhcpd.h"
 | 
			
		||||
#include "packet.h"
 | 
			
		||||
#include "options.h"
 | 
			
		||||
#include "dhcpc.h"
 | 
			
		||||
#include "log.h"
 | 
			
		||||
 | 
			
		||||
/* Create a random xid */
 | 
			
		||||
unsigned long random_xid(void)
 | 
			
		||||
{
 | 
			
		||||
	static int initialized;
 | 
			
		||||
	if (!initialized) {
 | 
			
		||||
		int fd;
 | 
			
		||||
		unsigned long seed;
 | 
			
		||||
 | 
			
		||||
		fd = open("/dev/urandom", O_RDONLY);
 | 
			
		||||
		if (fd == -1 || read(fd, &seed, sizeof(seed)) < 0) {
 | 
			
		||||
			log_line(LOG_WARNING, "Could not load seed from /dev/urandom: %s\n",
 | 
			
		||||
				strerror(errno));
 | 
			
		||||
			seed = time(0);
 | 
			
		||||
		}
 | 
			
		||||
		if (fd != -1)
 | 
			
		||||
			close(fd);
 | 
			
		||||
		srand(seed);
 | 
			
		||||
		initialized++;
 | 
			
		||||
	}
 | 
			
		||||
	return rand();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* initialize a packet with the proper defaults */
 | 
			
		||||
static void init_packet(struct dhcpMessage *packet, char type)
 | 
			
		||||
{
 | 
			
		||||
	struct vendor  {
 | 
			
		||||
		char vendor;
 | 
			
		||||
		char length;
 | 
			
		||||
		char str[sizeof("ndhc "VERSION)];
 | 
			
		||||
	} vendor_id = { DHCP_VENDOR,  sizeof("ndhc "VERSION) - 1, "ndhc "VERSION};
 | 
			
		||||
	
 | 
			
		||||
	init_header(packet, type);
 | 
			
		||||
	memcpy(packet->chaddr, client_config.arp, 6);
 | 
			
		||||
	add_option_string(packet->options, client_config.clientid);
 | 
			
		||||
	if (client_config.hostname)
 | 
			
		||||
		add_option_string(packet->options, client_config.hostname);
 | 
			
		||||
	add_option_string(packet->options, (unsigned char *)&vendor_id);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Add a paramater request list for stubborn DHCP servers. Pull the data
 | 
			
		||||
 * from the struct in options.c. Don't do bounds checking here because it
 | 
			
		||||
 * goes towards the head of the packet. */
 | 
			
		||||
static void add_requests(struct dhcpMessage *packet)
 | 
			
		||||
{
 | 
			
		||||
	int end = end_option(packet->options);
 | 
			
		||||
	int i, len = 0;
 | 
			
		||||
 | 
			
		||||
	packet->options[end + OPT_CODE] = DHCP_PARAM_REQ;
 | 
			
		||||
	for (i = 0; options[i].code; i++)
 | 
			
		||||
		if (options[i].flags & OPTION_REQ)
 | 
			
		||||
			packet->options[end + OPT_DATA + len++] = options[i].code;
 | 
			
		||||
	packet->options[end + OPT_LEN] = len;
 | 
			
		||||
	packet->options[end + OPT_DATA + len] = DHCP_END;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Broadcast a DHCP discover packet to the network, with an optionally
 | 
			
		||||
 * requested IP */
 | 
			
		||||
int send_discover(unsigned long xid, unsigned long requested)
 | 
			
		||||
{
 | 
			
		||||
	struct dhcpMessage packet;
 | 
			
		||||
 | 
			
		||||
	init_packet(&packet, DHCPDISCOVER);
 | 
			
		||||
	packet.xid = xid;
 | 
			
		||||
	if (requested)
 | 
			
		||||
		add_simple_option(packet.options, DHCP_REQUESTED_IP, requested);
 | 
			
		||||
 | 
			
		||||
	add_requests(&packet);
 | 
			
		||||
	log_line(LOG_DEBUG, "Sending discover...\n");
 | 
			
		||||
	return raw_packet(&packet, INADDR_ANY, CLIENT_PORT, INADDR_BROADCAST, 
 | 
			
		||||
				SERVER_PORT, MAC_BCAST_ADDR, client_config.ifindex);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Broadcasts a DHCP request message */
 | 
			
		||||
int send_selecting(unsigned long xid, unsigned long server,
 | 
			
		||||
		unsigned long requested)
 | 
			
		||||
{
 | 
			
		||||
	struct dhcpMessage packet;
 | 
			
		||||
	struct in_addr addr;
 | 
			
		||||
 | 
			
		||||
	init_packet(&packet, DHCPREQUEST);
 | 
			
		||||
	packet.xid = xid;
 | 
			
		||||
 | 
			
		||||
	add_simple_option(packet.options, DHCP_REQUESTED_IP, requested);
 | 
			
		||||
	add_simple_option(packet.options, DHCP_SERVER_ID, server);
 | 
			
		||||
	
 | 
			
		||||
	add_requests(&packet);
 | 
			
		||||
	addr.s_addr = requested;
 | 
			
		||||
	log_line(LOG_DEBUG, "Sending select for %s...\n", inet_ntoa(addr));
 | 
			
		||||
	return raw_packet(&packet, INADDR_ANY, CLIENT_PORT, INADDR_BROADCAST, 
 | 
			
		||||
				SERVER_PORT, MAC_BCAST_ADDR, client_config.ifindex);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Unicasts or broadcasts a DHCP renew message */
 | 
			
		||||
int send_renew(unsigned long xid, unsigned long server, unsigned long ciaddr)
 | 
			
		||||
{
 | 
			
		||||
	struct dhcpMessage packet;
 | 
			
		||||
	int ret = 0;
 | 
			
		||||
 | 
			
		||||
	init_packet(&packet, DHCPREQUEST);
 | 
			
		||||
	packet.xid = xid;
 | 
			
		||||
	packet.ciaddr = ciaddr;
 | 
			
		||||
 | 
			
		||||
	add_requests(&packet);
 | 
			
		||||
	log_line(LOG_DEBUG, "Sending renew...\n");
 | 
			
		||||
	if (server) 
 | 
			
		||||
		ret = kernel_packet(&packet, ciaddr, CLIENT_PORT, server, SERVER_PORT);
 | 
			
		||||
	else 
 | 
			
		||||
		ret = raw_packet(&packet, INADDR_ANY, CLIENT_PORT, INADDR_BROADCAST,
 | 
			
		||||
				SERVER_PORT, MAC_BCAST_ADDR, client_config.ifindex);
 | 
			
		||||
	return ret;
 | 
			
		||||
}	
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Unicasts a DHCP release message */
 | 
			
		||||
int send_release(unsigned long server, unsigned long ciaddr)
 | 
			
		||||
{
 | 
			
		||||
	struct dhcpMessage packet;
 | 
			
		||||
 | 
			
		||||
	init_packet(&packet, DHCPRELEASE);
 | 
			
		||||
	packet.xid = random_xid();
 | 
			
		||||
	packet.ciaddr = ciaddr;
 | 
			
		||||
	
 | 
			
		||||
	add_simple_option(packet.options, DHCP_REQUESTED_IP, ciaddr);
 | 
			
		||||
	add_simple_option(packet.options, DHCP_SERVER_ID, server);
 | 
			
		||||
 | 
			
		||||
	log_line(LOG_DEBUG, "Sending release...\n");
 | 
			
		||||
	return kernel_packet(&packet, ciaddr, CLIENT_PORT, server, SERVER_PORT);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* return -1 on errors that are fatal for the socket,
 | 
			
		||||
 * -2 for those that aren't */
 | 
			
		||||
int get_raw_packet(struct dhcpMessage *payload, int fd)
 | 
			
		||||
{
 | 
			
		||||
	int bytes;
 | 
			
		||||
	struct udp_dhcp_packet packet;
 | 
			
		||||
	uint32_t source, dest;
 | 
			
		||||
	uint16_t check;
 | 
			
		||||
 | 
			
		||||
	memset(&packet, 0, sizeof(struct udp_dhcp_packet));
 | 
			
		||||
	bytes = read(fd, &packet, sizeof(struct udp_dhcp_packet));
 | 
			
		||||
	if (bytes < 0) {
 | 
			
		||||
		debug(LOG_INFO, "couldn't read on raw listening socket -- ignoring\n");
 | 
			
		||||
		usleep(500000); /* possible down interface, looping condition */
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	if (bytes < (int) (sizeof(struct iphdr) + sizeof(struct udphdr))) {
 | 
			
		||||
		debug(LOG_INFO, "message too short, ignoring\n");
 | 
			
		||||
		return -2;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	if (bytes < ntohs(packet.ip.tot_len)) {
 | 
			
		||||
		debug(LOG_INFO, "Truncated packet\n");
 | 
			
		||||
		return -2;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	/* ignore any extra garbage bytes */
 | 
			
		||||
	bytes = ntohs(packet.ip.tot_len);
 | 
			
		||||
	
 | 
			
		||||
	/* Make sure its the right packet for us, and that it passes
 | 
			
		||||
	 * sanity checks */
 | 
			
		||||
	if (packet.ip.protocol != IPPROTO_UDP
 | 
			
		||||
			|| packet.ip.version != IPVERSION
 | 
			
		||||
			|| packet.ip.ihl != sizeof(packet.ip) >> 2
 | 
			
		||||
			|| packet.udp.dest != htons(CLIENT_PORT)
 | 
			
		||||
			|| bytes > (int)sizeof(struct udp_dhcp_packet)
 | 
			
		||||
			|| ntohs(packet.udp.len) != (short)(bytes - sizeof(packet.ip))) {
 | 
			
		||||
	    	debug(LOG_INFO, "unrelated/bogus packet\n");
 | 
			
		||||
	    	return -2;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* check IP checksum */
 | 
			
		||||
	check = packet.ip.check;
 | 
			
		||||
	packet.ip.check = 0;
 | 
			
		||||
	if (check != checksum(&(packet.ip), sizeof(packet.ip))) {
 | 
			
		||||
		debug(LOG_INFO, "bad IP header checksum, ignoring\n");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	/* verify the UDP checksum by replacing the header with a psuedo header */
 | 
			
		||||
	source = packet.ip.saddr;
 | 
			
		||||
	dest = packet.ip.daddr;
 | 
			
		||||
	check = packet.udp.check;
 | 
			
		||||
	packet.udp.check = 0;
 | 
			
		||||
	memset(&packet.ip, 0, sizeof(packet.ip));
 | 
			
		||||
 | 
			
		||||
	packet.ip.protocol = IPPROTO_UDP;
 | 
			
		||||
	packet.ip.saddr = source;
 | 
			
		||||
	packet.ip.daddr = dest;
 | 
			
		||||
	packet.ip.tot_len = packet.udp.len; /* cheat on the psuedo-header */
 | 
			
		||||
	if (check && check != checksum(&packet, bytes)) {
 | 
			
		||||
		debug(LOG_ERR, "packet with bad UDP checksum received, ignoring\n");
 | 
			
		||||
		return -2;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	memcpy(payload, &(packet.data),
 | 
			
		||||
			bytes - (sizeof(packet.ip) + sizeof(packet.udp)));
 | 
			
		||||
	
 | 
			
		||||
	if (ntohl(payload->cookie) != DHCP_MAGIC) {
 | 
			
		||||
		log_line(LOG_ERR, "received bogus message (bad magic) -- ignoring\n");
 | 
			
		||||
		return -2;
 | 
			
		||||
	}
 | 
			
		||||
	debug(LOG_INFO, "oooooh!!! got some!\n");
 | 
			
		||||
	return bytes - (sizeof(packet.ip) + sizeof(packet.udp));
 | 
			
		||||
	
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										12
									
								
								ndhc/clientpacket.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								ndhc/clientpacket.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
			
		||||
#ifndef _CLIENTPACKET_H
 | 
			
		||||
#define _CLIENTPACKET_H
 | 
			
		||||
 | 
			
		||||
unsigned long random_xid(void);
 | 
			
		||||
int send_discover(unsigned long xid, unsigned long requested);
 | 
			
		||||
int send_selecting(unsigned long xid, unsigned long server, unsigned long requested);
 | 
			
		||||
int send_renew(unsigned long xid, unsigned long server, unsigned long ciaddr);
 | 
			
		||||
int send_renew(unsigned long xid, unsigned long server, unsigned long ciaddr);
 | 
			
		||||
int send_release(unsigned long server, unsigned long ciaddr);
 | 
			
		||||
int get_raw_packet(struct dhcpMessage *payload, int fd);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										594
									
								
								ndhc/dhcpc.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										594
									
								
								ndhc/dhcpc.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,594 @@
 | 
			
		||||
/* dhcpc.c
 | 
			
		||||
 *
 | 
			
		||||
 * ndhc DHCP client
 | 
			
		||||
 *
 | 
			
		||||
 * Russ Dill <Russ.Dill@asu.edu> July 2001
 | 
			
		||||
 * Nicholas Kain <njk@-N0SPaM-.kain.us> 2004
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; if not, write to the Free Software
 | 
			
		||||
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 | 
			
		||||
 */
 | 
			
		||||
 
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <sys/time.h>
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <sys/file.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <getopt.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <sys/socket.h>
 | 
			
		||||
#include <netinet/in.h>
 | 
			
		||||
#include <arpa/inet.h>
 | 
			
		||||
#include <signal.h>
 | 
			
		||||
#include <time.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <sys/ioctl.h>
 | 
			
		||||
#include <net/if.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <sys/capability.h>
 | 
			
		||||
#include <sys/prctl.h>
 | 
			
		||||
#include <pwd.h>
 | 
			
		||||
#include <grp.h>
 | 
			
		||||
 | 
			
		||||
#include "dhcpd.h"
 | 
			
		||||
#include "dhcpc.h"
 | 
			
		||||
#include "options.h"
 | 
			
		||||
#include "clientpacket.h"
 | 
			
		||||
#include "packet.h"
 | 
			
		||||
#include "script.h"
 | 
			
		||||
#include "socket.h"
 | 
			
		||||
#include "log.h"
 | 
			
		||||
#include "rootcap.h"
 | 
			
		||||
#include "nstrl.h"
 | 
			
		||||
 | 
			
		||||
static unsigned long requested_ip, server_addr, timeout;
 | 
			
		||||
static unsigned long lease, t1, t2, xid, start;
 | 
			
		||||
static int state, packet_num, fd, listen_mode;
 | 
			
		||||
static sig_atomic_t pending_exit, pending_renew, pending_release;
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
	LISTEN_NONE,
 | 
			
		||||
	LISTEN_KERNEL,
 | 
			
		||||
	LISTEN_RAW
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct client_config_t client_config = {
 | 
			
		||||
	/* Default options. */
 | 
			
		||||
	.abort_if_no_lease = 0,
 | 
			
		||||
	.foreground = 0,
 | 
			
		||||
	.quit_after_lease = 0,
 | 
			
		||||
	.background_if_no_lease = 0,
 | 
			
		||||
	.interface = "eth0",
 | 
			
		||||
	.script = "none",
 | 
			
		||||
	.clientid = NULL,
 | 
			
		||||
	.hostname = NULL,
 | 
			
		||||
	.ifindex = 0,
 | 
			
		||||
	.arp = "\0",
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void show_usage(void)
 | 
			
		||||
{
 | 
			
		||||
	printf(
 | 
			
		||||
"Usage: ndhc [OPTIONS]\n\n"
 | 
			
		||||
"  -c, --clientid=CLIENTID         Client identifier\n"
 | 
			
		||||
"  -H, --hostname=HOSTNAME         Client hostname\n"
 | 
			
		||||
"  -h                              Alias for -H\n"
 | 
			
		||||
"  -f, --foreground                Do not fork after getting lease\n"
 | 
			
		||||
"  -b, --background                Fork to background if lease cannot be\n"
 | 
			
		||||
"                                  immediately negotiated.\n"
 | 
			
		||||
"  -i, --interface=INTERFACE       Interface to use (default: eth0)\n"
 | 
			
		||||
"  -n, --now                       Exit with failure if lease cannot be\n"
 | 
			
		||||
"                                  immediately negotiated.\n"
 | 
			
		||||
"  -q, --quit                      Quit after obtaining lease\n"
 | 
			
		||||
"  -r, --request=IP                IP address to request (default: none)\n"
 | 
			
		||||
"  -u, --user                      Change privileges to this user\n"
 | 
			
		||||
"  -C, --chroot                    Directory to which udhcp should chroot\n"
 | 
			
		||||
"  -v, --version                   Display version\n"
 | 
			
		||||
	);
 | 
			
		||||
	exit(EXIT_SUCCESS);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* just a little helper */
 | 
			
		||||
static void change_mode(int new_mode)
 | 
			
		||||
{
 | 
			
		||||
	debug(LOG_INFO, "entering %s listen mode",
 | 
			
		||||
		new_mode ? (new_mode == 1 ? "kernel" : "raw") : "none");
 | 
			
		||||
	close(fd);
 | 
			
		||||
	fd = -1;
 | 
			
		||||
	listen_mode = new_mode;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* perform a renew */
 | 
			
		||||
static void perform_renew(void)
 | 
			
		||||
{
 | 
			
		||||
	log_line(LOG_INFO, "Performing a DHCP renew...\n");
 | 
			
		||||
	switch (state) {
 | 
			
		||||
		case BOUND:
 | 
			
		||||
			change_mode(LISTEN_KERNEL);
 | 
			
		||||
		case RENEWING:
 | 
			
		||||
		case REBINDING:
 | 
			
		||||
			state = RENEW_REQUESTED;
 | 
			
		||||
			break;
 | 
			
		||||
		case RENEW_REQUESTED: /* impatient are we? fine, square 1 */
 | 
			
		||||
			run_script(NULL, SCRIPT_DECONFIG);
 | 
			
		||||
		case REQUESTING:
 | 
			
		||||
		case RELEASED:
 | 
			
		||||
			change_mode(LISTEN_RAW);
 | 
			
		||||
			state = INIT_SELECTING;
 | 
			
		||||
			break;
 | 
			
		||||
		case INIT_SELECTING:
 | 
			
		||||
			break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* start things over */
 | 
			
		||||
	packet_num = 0;
 | 
			
		||||
 | 
			
		||||
	/* Kill any timeouts because the user wants this to hurry along */
 | 
			
		||||
	timeout = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* perform a release */
 | 
			
		||||
static void perform_release(void)
 | 
			
		||||
{
 | 
			
		||||
	char buf[16];
 | 
			
		||||
	struct in_addr temp_addr;
 | 
			
		||||
 | 
			
		||||
	buf[16] = '\0';
 | 
			
		||||
	
 | 
			
		||||
	/* send release packet */
 | 
			
		||||
	if (state == BOUND || state == RENEWING || state == REBINDING) {
 | 
			
		||||
		temp_addr.s_addr = server_addr;
 | 
			
		||||
		snprintf(buf, sizeof buf, "%s", inet_ntoa(temp_addr));
 | 
			
		||||
		temp_addr.s_addr = requested_ip;
 | 
			
		||||
		log_line(LOG_INFO, "Unicasting a release of %s to %s.\n", 
 | 
			
		||||
				inet_ntoa(temp_addr), buf);
 | 
			
		||||
		send_release(server_addr, requested_ip); /* unicast */
 | 
			
		||||
		run_script(NULL, SCRIPT_DECONFIG);
 | 
			
		||||
	}
 | 
			
		||||
	log_line(LOG_INFO, "Entering released state.\n");
 | 
			
		||||
 | 
			
		||||
	change_mode(LISTEN_NONE);
 | 
			
		||||
	state = RELEASED;
 | 
			
		||||
	timeout = 0x7fffffff;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void signal_handler(int sig)
 | 
			
		||||
{
 | 
			
		||||
	switch (sig) {
 | 
			
		||||
		case SIGUSR1: 
 | 
			
		||||
			pending_renew = 1;
 | 
			
		||||
			break;
 | 
			
		||||
		case SIGUSR2:
 | 
			
		||||
			pending_release = 1;
 | 
			
		||||
			break;
 | 
			
		||||
		case SIGTERM:
 | 
			
		||||
			pending_exit = 1;
 | 
			
		||||
			break;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void background(void)
 | 
			
		||||
{
 | 
			
		||||
	if (daemon(0, 0) == -1) {
 | 
			
		||||
		perror("fork");
 | 
			
		||||
		exit(EXIT_SUCCESS);
 | 
			
		||||
	}
 | 
			
		||||
	client_config.foreground = 1; /* Do not fork again. */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_timeout(void)
 | 
			
		||||
{
 | 
			
		||||
	time_t now = time(0);
 | 
			
		||||
 | 
			
		||||
	/* timeout dropped to zero */
 | 
			
		||||
	switch (state) {
 | 
			
		||||
		case INIT_SELECTING:
 | 
			
		||||
			if (packet_num < 3) {
 | 
			
		||||
				if (packet_num == 0)
 | 
			
		||||
					xid = random_xid();
 | 
			
		||||
 | 
			
		||||
				/* send discover packet */
 | 
			
		||||
				send_discover(xid, requested_ip); /* broadcast */
 | 
			
		||||
 | 
			
		||||
				timeout = now + ((packet_num == 2) ? 4 : 2);
 | 
			
		||||
				packet_num++;
 | 
			
		||||
			} else {
 | 
			
		||||
				if (client_config.background_if_no_lease) {
 | 
			
		||||
					log_line(LOG_INFO, "No lease, going to background.\n");
 | 
			
		||||
					background();
 | 
			
		||||
				} else if (client_config.abort_if_no_lease) {
 | 
			
		||||
					log_line(LOG_INFO, "No lease, failing.\n");
 | 
			
		||||
					exit(EXIT_FAILURE);
 | 
			
		||||
				}
 | 
			
		||||
				/* wait to try again */
 | 
			
		||||
				packet_num = 0;
 | 
			
		||||
				timeout = now + 60;
 | 
			
		||||
			}
 | 
			
		||||
			break;
 | 
			
		||||
		case RENEW_REQUESTED:
 | 
			
		||||
		case REQUESTING:
 | 
			
		||||
			if (packet_num < 3) {
 | 
			
		||||
				/* send request packet */
 | 
			
		||||
				if (state == RENEW_REQUESTED)
 | 
			
		||||
					/* unicast */
 | 
			
		||||
					send_renew(xid, server_addr, requested_ip);
 | 
			
		||||
				else
 | 
			
		||||
					/* broadcast */
 | 
			
		||||
					send_selecting(xid, server_addr, requested_ip);					
 | 
			
		||||
				timeout = now + ((packet_num == 2) ? 10 : 2);
 | 
			
		||||
				packet_num++;
 | 
			
		||||
			} else {
 | 
			
		||||
				/* timed out, go back to init state */
 | 
			
		||||
				if (state == RENEW_REQUESTED)
 | 
			
		||||
					run_script(NULL, SCRIPT_DECONFIG);
 | 
			
		||||
				state = INIT_SELECTING;
 | 
			
		||||
				timeout = now;
 | 
			
		||||
				packet_num = 0;
 | 
			
		||||
				change_mode(LISTEN_RAW);
 | 
			
		||||
			}
 | 
			
		||||
			break;
 | 
			
		||||
		case BOUND:
 | 
			
		||||
			/* Lease is starting to run out, time to enter renewing state */
 | 
			
		||||
			state = RENEWING;
 | 
			
		||||
			change_mode(LISTEN_KERNEL);
 | 
			
		||||
			debug(LOG_INFO, "Entering renew state.\n");
 | 
			
		||||
			/* fall right through */
 | 
			
		||||
		case RENEWING:
 | 
			
		||||
			/* Either set a new T1, or enter REBINDING state */
 | 
			
		||||
			if ((t2 - t1) <= (lease / 14400 + 1)) {
 | 
			
		||||
				/* timed out, enter rebinding state */
 | 
			
		||||
				state = REBINDING;
 | 
			
		||||
				timeout = now + (t2 - t1);
 | 
			
		||||
				debug(LOG_INFO, "Entering rebinding state.\n");
 | 
			
		||||
			} else {
 | 
			
		||||
				/* send a request packet */
 | 
			
		||||
				send_renew(xid, server_addr, requested_ip); /* unicast */
 | 
			
		||||
 | 
			
		||||
				t1 = ((t2 - t1) >> 1) + t1;
 | 
			
		||||
				timeout = t1 + start;
 | 
			
		||||
			}
 | 
			
		||||
			break;
 | 
			
		||||
		case REBINDING:
 | 
			
		||||
			/* Either set a new T2, or enter INIT state */
 | 
			
		||||
			if ((lease - t2) <= (lease / 14400 + 1)) {
 | 
			
		||||
				/* timed out, enter init state */
 | 
			
		||||
				state = INIT_SELECTING;
 | 
			
		||||
				log_line(LOG_INFO, "Lease lost, entering init state.\n");
 | 
			
		||||
				run_script(NULL, SCRIPT_DECONFIG);
 | 
			
		||||
				timeout = now;
 | 
			
		||||
				packet_num = 0;
 | 
			
		||||
				change_mode(LISTEN_RAW);
 | 
			
		||||
			} else {
 | 
			
		||||
				/* send a request packet */
 | 
			
		||||
				send_renew(xid, 0, requested_ip); /* broadcast */
 | 
			
		||||
 | 
			
		||||
				t2 = ((lease - t2) >> 1) + t2;
 | 
			
		||||
				timeout = t2 + start;
 | 
			
		||||
			}
 | 
			
		||||
			break;
 | 
			
		||||
		case RELEASED:
 | 
			
		||||
			/* yah, I know, *you* say it would never happen */
 | 
			
		||||
			timeout = 0x7fffffff;
 | 
			
		||||
			break;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_packet(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char *temp = NULL, *message = NULL;
 | 
			
		||||
	int len;
 | 
			
		||||
	time_t now = time(0);
 | 
			
		||||
	struct in_addr temp_addr;
 | 
			
		||||
	struct dhcpMessage packet;
 | 
			
		||||
		
 | 
			
		||||
	debug(LOG_INFO, "got a packet\n");
 | 
			
		||||
 | 
			
		||||
	if (listen_mode == LISTEN_KERNEL)
 | 
			
		||||
		len = get_packet(&packet, fd);
 | 
			
		||||
	else
 | 
			
		||||
		len = get_raw_packet(&packet, fd);
 | 
			
		||||
 | 
			
		||||
	if (len == -1 && errno != EINTR) {
 | 
			
		||||
		debug(LOG_INFO, "error on read, %s, reopening socket.\n",
 | 
			
		||||
				strerror(errno));
 | 
			
		||||
		change_mode(listen_mode); /* just close and reopen */
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (len < 0)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	if (packet.xid != xid) {
 | 
			
		||||
		debug(LOG_INFO, "Ignoring XID %lx (our xid is %lx).\n",
 | 
			
		||||
				(unsigned long) packet.xid, xid);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ((message = get_option(&packet, DHCP_MESSAGE_TYPE)) == NULL) {
 | 
			
		||||
		debug(LOG_ERR, "couldnt get option from packet -- ignoring\n");
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch (state) {
 | 
			
		||||
		case INIT_SELECTING:
 | 
			
		||||
			/* Must be a DHCPOFFER to one of our xid's */
 | 
			
		||||
			if (*message == DHCPOFFER) {
 | 
			
		||||
				if ((temp = get_option(&packet, DHCP_SERVER_ID))) {
 | 
			
		||||
					memcpy(&server_addr, temp, 4);
 | 
			
		||||
					xid = packet.xid;
 | 
			
		||||
					requested_ip = packet.yiaddr;
 | 
			
		||||
 | 
			
		||||
					/* enter requesting state */
 | 
			
		||||
					state = REQUESTING;
 | 
			
		||||
					timeout = now;
 | 
			
		||||
					packet_num = 0;
 | 
			
		||||
				} else {
 | 
			
		||||
					debug(LOG_ERR, "No server ID in message\n");
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			break;
 | 
			
		||||
		case RENEW_REQUESTED:
 | 
			
		||||
		case REQUESTING:
 | 
			
		||||
		case RENEWING:
 | 
			
		||||
		case REBINDING:
 | 
			
		||||
			if (*message == DHCPACK) {
 | 
			
		||||
				if (!(temp = get_option(&packet, DHCP_LEASE_TIME))) {
 | 
			
		||||
					log_line(LOG_ERR,
 | 
			
		||||
							"No lease time received, assuming 1h.\n");
 | 
			
		||||
					lease = 60 * 60;
 | 
			
		||||
				} else {
 | 
			
		||||
					memcpy(&lease, temp, 4);
 | 
			
		||||
					lease = ntohl(lease);
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				/* enter bound state */
 | 
			
		||||
				t1 = lease >> 1;
 | 
			
		||||
 | 
			
		||||
				/* little fixed point for n * .875 */
 | 
			
		||||
				t2 = (lease * 0x7) >> 3;
 | 
			
		||||
				temp_addr.s_addr = packet.yiaddr;
 | 
			
		||||
				log_line(LOG_INFO,
 | 
			
		||||
						"Lease of %s obtained, lease time %ld.\n",
 | 
			
		||||
						inet_ntoa(temp_addr), lease);
 | 
			
		||||
				start = now;
 | 
			
		||||
				timeout = t1 + start;
 | 
			
		||||
				requested_ip = packet.yiaddr;
 | 
			
		||||
				run_script(&packet,
 | 
			
		||||
						((state == RENEWING || state == REBINDING)
 | 
			
		||||
						 ? SCRIPT_RENEW : SCRIPT_BOUND));
 | 
			
		||||
 | 
			
		||||
				state = BOUND;
 | 
			
		||||
				change_mode(LISTEN_NONE);
 | 
			
		||||
				if (client_config.quit_after_lease) 
 | 
			
		||||
					exit(EXIT_SUCCESS);
 | 
			
		||||
				if (!client_config.foreground)
 | 
			
		||||
					background();
 | 
			
		||||
 | 
			
		||||
			} else if (*message == DHCPNAK) {
 | 
			
		||||
				/* return to init state */
 | 
			
		||||
				log_line(LOG_INFO, "Received DHCP NAK.\n");
 | 
			
		||||
				run_script(&packet, SCRIPT_NAK);
 | 
			
		||||
				if (state != REQUESTING)
 | 
			
		||||
					run_script(NULL, SCRIPT_DECONFIG);
 | 
			
		||||
				state = INIT_SELECTING;
 | 
			
		||||
				timeout = now;
 | 
			
		||||
				requested_ip = 0;
 | 
			
		||||
				packet_num = 0;
 | 
			
		||||
				change_mode(LISTEN_RAW);
 | 
			
		||||
				sleep(3); /* avoid excessive network traffic */
 | 
			
		||||
			}
 | 
			
		||||
			break;
 | 
			
		||||
		case BOUND:
 | 
			
		||||
		case RELEASED:
 | 
			
		||||
		default:
 | 
			
		||||
			break;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int do_work(void)
 | 
			
		||||
{
 | 
			
		||||
	struct timeval tv;
 | 
			
		||||
	fd_set rfds;
 | 
			
		||||
	for (;;) {
 | 
			
		||||
 | 
			
		||||
		/* Handle signals asynchronously. */
 | 
			
		||||
		if (pending_renew)
 | 
			
		||||
			perform_renew();
 | 
			
		||||
		if (pending_release)
 | 
			
		||||
			perform_release();
 | 
			
		||||
		if (pending_exit) {
 | 
			
		||||
			log_line(LOG_INFO, "Received SIGTERM.  Exiting gracefully.\n");
 | 
			
		||||
			exit(EXIT_SUCCESS);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		tv.tv_sec = timeout - time(0);
 | 
			
		||||
		tv.tv_usec = 0;
 | 
			
		||||
 | 
			
		||||
		if (listen_mode != LISTEN_NONE && fd < 0) {
 | 
			
		||||
			if (listen_mode == LISTEN_KERNEL)
 | 
			
		||||
				fd = listen_socket(INADDR_ANY, CLIENT_PORT,
 | 
			
		||||
						client_config.interface);
 | 
			
		||||
			else
 | 
			
		||||
				fd = raw_socket(client_config.ifindex);
 | 
			
		||||
 | 
			
		||||
			if (fd < 0) {
 | 
			
		||||
				log_line(LOG_ERR, "FATAL: couldn't listen on socket: %s.\n",
 | 
			
		||||
						strerror(errno));
 | 
			
		||||
				exit(EXIT_FAILURE);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (tv.tv_sec <= 0) {
 | 
			
		||||
			handle_timeout();
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		FD_ZERO(&rfds);
 | 
			
		||||
		if (fd >= 0)
 | 
			
		||||
			FD_SET(fd, &rfds);
 | 
			
		||||
		debug(LOG_INFO, "Waiting on select...\n");
 | 
			
		||||
		if (select(fd + 1, &rfds, NULL, NULL, &tv) == -1) {
 | 
			
		||||
			switch (errno) {
 | 
			
		||||
				case EBADF:
 | 
			
		||||
					fd = -1;
 | 
			
		||||
				default:
 | 
			
		||||
					debug(LOG_ERR, "Error: \"%s\" on select!\n",
 | 
			
		||||
							strerror(errno));
 | 
			
		||||
				case EINTR:  /* Signal received, go back to top. */
 | 
			
		||||
					continue;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		debug(LOG_INFO, "select suceeded\n");
 | 
			
		||||
 | 
			
		||||
		if (listen_mode != LISTEN_NONE && FD_ISSET(fd, &rfds))
 | 
			
		||||
			handle_packet();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main(int argc, char **argv)
 | 
			
		||||
{
 | 
			
		||||
	char *chroot_dir = NULL;
 | 
			
		||||
	int c, len;
 | 
			
		||||
	struct passwd *pwd;
 | 
			
		||||
	uid_t uid = 0;
 | 
			
		||||
	gid_t gid = 0;
 | 
			
		||||
	static struct option arg_options[] = {
 | 
			
		||||
		{"clientid",	required_argument,	0, 'c'},
 | 
			
		||||
		{"foreground",	no_argument,		0, 'f'},
 | 
			
		||||
		{"background",	no_argument,		0, 'b'},
 | 
			
		||||
		{"hostname",	required_argument,	0, 'H'},
 | 
			
		||||
		{"hostname",    required_argument,      0, 'h'},
 | 
			
		||||
		{"interface",	required_argument,	0, 'i'},
 | 
			
		||||
		{"now", 	no_argument,		0, 'n'},
 | 
			
		||||
		{"quit",	no_argument,		0, 'q'},
 | 
			
		||||
		{"request",	required_argument,	0, 'r'},
 | 
			
		||||
		{"version",	no_argument,		0, 'v'},
 | 
			
		||||
		{"user",        required_argument,      0, 'u'},
 | 
			
		||||
		{"chroot",      required_argument,      0, 'C'},
 | 
			
		||||
		{"help",	no_argument,		0, '?'},
 | 
			
		||||
		{0, 0, 0, 0}
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	/* get options */
 | 
			
		||||
	while (1) {
 | 
			
		||||
		int option_index = 0;
 | 
			
		||||
		c = getopt_long(argc, argv, "c:fbH:h:i:np:qr:u:C:v", arg_options,
 | 
			
		||||
				&option_index);
 | 
			
		||||
		if (c == -1) break;
 | 
			
		||||
		
 | 
			
		||||
		switch (c) {
 | 
			
		||||
		case 'c':
 | 
			
		||||
			len = strlen(optarg) > 255 ? 255 : strlen(optarg);
 | 
			
		||||
			if (client_config.clientid)
 | 
			
		||||
				free(client_config.clientid);
 | 
			
		||||
			client_config.clientid = malloc(len + 2);
 | 
			
		||||
			client_config.clientid[OPT_CODE] = DHCP_CLIENT_ID;
 | 
			
		||||
			client_config.clientid[OPT_LEN] = len;
 | 
			
		||||
			client_config.clientid[OPT_DATA] = '\0';
 | 
			
		||||
			strlcpy((char *)client_config.clientid + OPT_DATA, optarg, len);
 | 
			
		||||
			break;
 | 
			
		||||
		case 'f':
 | 
			
		||||
			client_config.foreground = 1;
 | 
			
		||||
			break;
 | 
			
		||||
		case 'b':
 | 
			
		||||
			client_config.background_if_no_lease = 1;
 | 
			
		||||
			break;
 | 
			
		||||
		case 'h':
 | 
			
		||||
		case 'H':
 | 
			
		||||
			len = strlen(optarg) > 255 ? 255 : strlen(optarg);
 | 
			
		||||
			if (client_config.hostname)
 | 
			
		||||
				free(client_config.hostname);
 | 
			
		||||
			client_config.hostname = malloc(len + 2);
 | 
			
		||||
			client_config.hostname[OPT_CODE] = DHCP_HOST_NAME;
 | 
			
		||||
			client_config.hostname[OPT_LEN] = len;
 | 
			
		||||
			strlcpy((char*)client_config.hostname + 2, optarg, len);
 | 
			
		||||
			break;
 | 
			
		||||
		case 'i':
 | 
			
		||||
			client_config.interface =  optarg;
 | 
			
		||||
			break;
 | 
			
		||||
		case 'n':
 | 
			
		||||
			client_config.abort_if_no_lease = 1;
 | 
			
		||||
			break;
 | 
			
		||||
		case 'q':
 | 
			
		||||
			client_config.quit_after_lease = 1;
 | 
			
		||||
			break;
 | 
			
		||||
		case 'r':
 | 
			
		||||
			requested_ip = inet_addr(optarg);
 | 
			
		||||
			break;
 | 
			
		||||
		case 'u':
 | 
			
		||||
			pwd = getpwnam(optarg);
 | 
			
		||||
			if (pwd) {
 | 
			
		||||
				uid = (int)pwd->pw_uid;
 | 
			
		||||
				gid = (int)pwd->pw_gid;
 | 
			
		||||
			} else {
 | 
			
		||||
				printf("Bad username provided.\n");
 | 
			
		||||
				exit(EXIT_FAILURE);
 | 
			
		||||
			}
 | 
			
		||||
			break;
 | 
			
		||||
		case 'C':
 | 
			
		||||
			len = strlen(optarg) > 255 ? 255 : strlen(optarg);
 | 
			
		||||
			chroot_dir = malloc(len + 2);
 | 
			
		||||
			memset(chroot_dir, '\0', len + 2);
 | 
			
		||||
			strlcpy(chroot_dir, optarg, len);
 | 
			
		||||
			break;
 | 
			
		||||
		case 'v':
 | 
			
		||||
			printf("ndhc, version %s\n\n", VERSION);
 | 
			
		||||
			exit(EXIT_SUCCESS);
 | 
			
		||||
			break;
 | 
			
		||||
		default:
 | 
			
		||||
			show_usage();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	log_line(LOG_INFO, "ndhc client (v%s) started.\n", VERSION);
 | 
			
		||||
 | 
			
		||||
	if (read_interface(client_config.interface, &client_config.ifindex, 
 | 
			
		||||
			   NULL, client_config.arp) < 0)
 | 
			
		||||
		exit(EXIT_FAILURE);
 | 
			
		||||
		
 | 
			
		||||
	if (!client_config.clientid) {
 | 
			
		||||
		client_config.clientid = malloc(6 + 3);
 | 
			
		||||
		client_config.clientid[OPT_CODE] = DHCP_CLIENT_ID;
 | 
			
		||||
		client_config.clientid[OPT_LEN] = 7;
 | 
			
		||||
		client_config.clientid[OPT_DATA] = 1;
 | 
			
		||||
		memcpy(client_config.clientid + 3, client_config.arp, 6);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* setup signal handlers */
 | 
			
		||||
	signal(SIGUSR1, signal_handler);
 | 
			
		||||
	signal(SIGUSR2, signal_handler);
 | 
			
		||||
	signal(SIGTERM, signal_handler);
 | 
			
		||||
 | 
			
		||||
	if (chdir(chroot_dir)) {
 | 
			
		||||
		printf("Failed to chdir(%s)!\n", chroot_dir);
 | 
			
		||||
		exit(EXIT_FAILURE);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (chroot(chroot_dir)) {
 | 
			
		||||
		printf("Failed to chroot(%s)!\n", chroot_dir);
 | 
			
		||||
		exit(EXIT_FAILURE);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	drop_root(uid, gid,
 | 
			
		||||
			"cap_net_bind_service,cap_net_broadcast,cap_net_raw=ep");
 | 
			
		||||
	
 | 
			
		||||
	state = INIT_SELECTING;
 | 
			
		||||
	run_script(NULL, SCRIPT_DECONFIG);
 | 
			
		||||
	change_mode(LISTEN_RAW);
 | 
			
		||||
 | 
			
		||||
	do_work();
 | 
			
		||||
	
 | 
			
		||||
	return EXIT_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										31
									
								
								ndhc/dhcpc.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								ndhc/dhcpc.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,31 @@
 | 
			
		||||
#ifndef _DHCPC_H
 | 
			
		||||
#define _DHCPC_H
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
	INIT_SELECTING,
 | 
			
		||||
	REQUESTING,
 | 
			
		||||
	BOUND,
 | 
			
		||||
	RENEWING,
 | 
			
		||||
	REBINDING,
 | 
			
		||||
	INIT_REBOOT,
 | 
			
		||||
	RENEW_REQUESTED,
 | 
			
		||||
	RELEASED
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct client_config_t {
 | 
			
		||||
	char foreground;		/* Do not fork */
 | 
			
		||||
	char quit_after_lease;		/* Quit after obtaining lease */
 | 
			
		||||
	char abort_if_no_lease;		/* Abort if no lease */
 | 
			
		||||
	char background_if_no_lease;	/* Fork to background if no lease */
 | 
			
		||||
	char *interface;		/* The name of the interface to use */
 | 
			
		||||
	char *script;			/* User script to run at dhcp events */
 | 
			
		||||
	unsigned char *clientid;	/* Optional client id to use */
 | 
			
		||||
	unsigned char *hostname;	/* Optional hostname to use */
 | 
			
		||||
	int ifindex;			/* Index number of the interface to use */
 | 
			
		||||
	unsigned char arp[6];		/* Our arp address */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
extern struct client_config_t client_config;
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										132
									
								
								ndhc/dhcpd.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										132
									
								
								ndhc/dhcpd.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,132 @@
 | 
			
		||||
/* dhcpd.h */
 | 
			
		||||
#ifndef _DHCPD_H
 | 
			
		||||
#define _DHCPD_H
 | 
			
		||||
 | 
			
		||||
#include <netinet/ip.h>
 | 
			
		||||
#include <netinet/udp.h>
 | 
			
		||||
 | 
			
		||||
#include "leases.h"
 | 
			
		||||
 | 
			
		||||
/************************************/
 | 
			
		||||
/* Defaults _you_ may want to tweak */
 | 
			
		||||
/************************************/
 | 
			
		||||
 | 
			
		||||
/* the period of time the client is allowed to use that address */
 | 
			
		||||
#define LEASE_TIME              (60*60*24*10) /* 10 days of seconds */
 | 
			
		||||
 | 
			
		||||
/*****************************************************************/
 | 
			
		||||
/* Do not modify below here unless you know what you are doing!! */
 | 
			
		||||
/*****************************************************************/
 | 
			
		||||
 | 
			
		||||
/* DHCP protocol -- see RFC 2131 */
 | 
			
		||||
#define SERVER_PORT		67
 | 
			
		||||
#define CLIENT_PORT		68
 | 
			
		||||
 | 
			
		||||
#define DHCP_MAGIC		0x63825363
 | 
			
		||||
 | 
			
		||||
/* DHCP option codes (partial list) */
 | 
			
		||||
#define DHCP_PADDING		0x00
 | 
			
		||||
#define DHCP_SUBNET			0x01
 | 
			
		||||
#define DHCP_TIME_OFFSET	0x02
 | 
			
		||||
#define DHCP_ROUTER			0x03
 | 
			
		||||
#define DHCP_TIME_SERVER	0x04
 | 
			
		||||
#define DHCP_NAME_SERVER	0x05
 | 
			
		||||
#define DHCP_DNS_SERVER		0x06
 | 
			
		||||
#define DHCP_LOG_SERVER		0x07
 | 
			
		||||
#define DHCP_COOKIE_SERVER	0x08
 | 
			
		||||
#define DHCP_LPR_SERVER		0x09
 | 
			
		||||
#define DHCP_HOST_NAME		0x0c
 | 
			
		||||
#define DHCP_BOOT_SIZE		0x0d
 | 
			
		||||
#define DHCP_DOMAIN_NAME	0x0f
 | 
			
		||||
#define DHCP_SWAP_SERVER	0x10
 | 
			
		||||
#define DHCP_ROOT_PATH		0x11
 | 
			
		||||
#define DHCP_IP_TTL			0x17
 | 
			
		||||
#define DHCP_MTU			0x1a
 | 
			
		||||
#define DHCP_BROADCAST		0x1c
 | 
			
		||||
#define DHCP_NTP_SERVER		0x2a
 | 
			
		||||
#define DHCP_WINS_SERVER	0x2c
 | 
			
		||||
#define DHCP_REQUESTED_IP	0x32
 | 
			
		||||
#define DHCP_LEASE_TIME		0x33
 | 
			
		||||
#define DHCP_OPTION_OVER	0x34
 | 
			
		||||
#define DHCP_MESSAGE_TYPE	0x35
 | 
			
		||||
#define DHCP_SERVER_ID		0x36
 | 
			
		||||
#define DHCP_PARAM_REQ		0x37
 | 
			
		||||
#define DHCP_MESSAGE		0x38
 | 
			
		||||
#define DHCP_MAX_SIZE		0x39
 | 
			
		||||
#define DHCP_T1				0x3a
 | 
			
		||||
#define DHCP_T2				0x3b
 | 
			
		||||
#define DHCP_VENDOR			0x3c
 | 
			
		||||
#define DHCP_CLIENT_ID		0x3d
 | 
			
		||||
#define DHCP_END			0xFF
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
	BOOTREQUEST = 1,
 | 
			
		||||
	BOOTREPLY = 2
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define ETH_10MB		1
 | 
			
		||||
#define ETH_10MB_LEN	6
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
	DHCPDISCOVER = 1,
 | 
			
		||||
	DHCPOFFER = 2,
 | 
			
		||||
	DHCPREQUEST = 3,
 | 
			
		||||
	DHCPDECLINE = 4,
 | 
			
		||||
	DHCPACK = 5,
 | 
			
		||||
	DHCPNAK = 6,
 | 
			
		||||
	DHCPRELEASE = 7,
 | 
			
		||||
	DHCPINFORM = 8
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define BROADCAST_FLAG		0x8000
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
	OPTION_FIELD = 0,
 | 
			
		||||
	FILE_FIELD = 1,
 | 
			
		||||
	SNAME_FIELD = 2
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define MAC_BCAST_ADDR		(unsigned char *) "\xff\xff\xff\xff\xff\xff"
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
	OPT_CODE = 0,
 | 
			
		||||
	OPT_LEN = 1,
 | 
			
		||||
	OPT_DATA = 2
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct option_set {
 | 
			
		||||
	unsigned char *data;
 | 
			
		||||
	struct option_set *next;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct server_config_t {
 | 
			
		||||
	uint32_t server;		/* Our IP, in network order */
 | 
			
		||||
	uint32_t start;		/* Start address of leases, network order */
 | 
			
		||||
	uint32_t end;			/* End of leases, network order */
 | 
			
		||||
	struct option_set *options;	/* List of DHCP options loaded from the config file */
 | 
			
		||||
	char *interface;		/* The name of the interface to use */
 | 
			
		||||
	int ifindex;			/* Index number of the interface to use */
 | 
			
		||||
	unsigned char arp[6];		/* Our arp address */
 | 
			
		||||
	unsigned long lease;		/* lease time in seconds (host order) */
 | 
			
		||||
	unsigned long max_leases; 	/* maximum number of leases (including reserved address) */
 | 
			
		||||
	char remaining; 		/* should the lease file be interpreted as lease time remaining, or
 | 
			
		||||
			 		 * as the time the lease expires */
 | 
			
		||||
	unsigned long auto_time; 	/* how long should udhcpd wait before writing a config file.
 | 
			
		||||
					 * if this is zero, it will only write one on SIGUSR1 */
 | 
			
		||||
	unsigned long decline_time; 	/* how long an address is reserved if a client returns a
 | 
			
		||||
				    	 * decline message */
 | 
			
		||||
	unsigned long conflict_time; 	/* how long an arp conflict offender is leased for */
 | 
			
		||||
	unsigned long offer_time; 	/* how long an offered address is reserved */
 | 
			
		||||
	unsigned long min_lease; 	/* minimum lease a client can request*/
 | 
			
		||||
	char *lease_file;
 | 
			
		||||
	char *notify_file;		/* What to run whenever leases are written */
 | 
			
		||||
	uint32_t siaddr;		/* next server bootp option */
 | 
			
		||||
	char *sname;			/* bootp server name */
 | 
			
		||||
	char *boot_file;		/* bootp boot file option */
 | 
			
		||||
};	
 | 
			
		||||
 | 
			
		||||
extern struct server_config_t server_config;
 | 
			
		||||
extern struct dhcpOfferedAddr *leases;
 | 
			
		||||
		
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										24
									
								
								ndhc/leases.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								ndhc/leases.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
			
		||||
/* leases.h */
 | 
			
		||||
#ifndef _LEASES_H
 | 
			
		||||
#define _LEASES_H
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct dhcpOfferedAddr {
 | 
			
		||||
	uint8_t chaddr[16];
 | 
			
		||||
	uint32_t yiaddr;	/* network order */
 | 
			
		||||
	uint32_t expires;	/* host order */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
extern unsigned char blank_chaddr[];
 | 
			
		||||
 | 
			
		||||
void clear_lease(uint8_t *chaddr, uint32_t yiaddr);
 | 
			
		||||
struct dhcpOfferedAddr *add_lease(uint8_t *chaddr, uint32_t yiaddr, unsigned long lease);
 | 
			
		||||
int lease_expired(struct dhcpOfferedAddr *lease);
 | 
			
		||||
struct dhcpOfferedAddr *oldest_expired_lease(void);
 | 
			
		||||
struct dhcpOfferedAddr *find_lease_by_chaddr(uint8_t *chaddr);
 | 
			
		||||
struct dhcpOfferedAddr *find_lease_by_yiaddr(uint32_t yiaddr);
 | 
			
		||||
uint32_t find_address(int check_expired);
 | 
			
		||||
int check_ip(uint32_t addr);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										20
									
								
								ndhc/log.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								ndhc/log.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <strings.h>
 | 
			
		||||
#include <stdarg.h>
 | 
			
		||||
#include <syslog.h>
 | 
			
		||||
 | 
			
		||||
void log_line(int level, char *format, ...) {
 | 
			
		||||
	va_list argp;
 | 
			
		||||
 | 
			
		||||
	if (format == NULL) return;
 | 
			
		||||
 | 
			
		||||
		va_start(argp, format);
 | 
			
		||||
		vfprintf(stderr, format, argp);
 | 
			
		||||
		va_end(argp);
 | 
			
		||||
		openlog("ndhc", 0, 0);
 | 
			
		||||
		va_start(argp, format);
 | 
			
		||||
		vsyslog(level, format, argp);
 | 
			
		||||
		va_end(argp);
 | 
			
		||||
		closelog();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										11
									
								
								ndhc/log.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								ndhc/log.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
			
		||||
#ifndef H_LOG_H__
 | 
			
		||||
#define H_LOG_H__
 | 
			
		||||
#include <syslog.h>
 | 
			
		||||
void log_line(int level, char *format, ...); 
 | 
			
		||||
#ifdef DEBUG
 | 
			
		||||
#define debug log_line
 | 
			
		||||
#else
 | 
			
		||||
#define debug(...) 
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										56
									
								
								ndhc/ndhc.8
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								ndhc/ndhc.8
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,56 @@
 | 
			
		||||
.TH NDHC 8 2004-02-25 Linux "Linux Administrator's Manual"
 | 
			
		||||
.SH NAME
 | 
			
		||||
ndhc \- secure DHCP client
 | 
			
		||||
.SH SYNOPSIS
 | 
			
		||||
.B ndhc
 | 
			
		||||
.RI [ OPTION ]...
 | 
			
		||||
.SH DESCRIPTION
 | 
			
		||||
The ndhc client negotiates a lease with the DHCP server and
 | 
			
		||||
informs ifchd of the change when it is obtained or lost.
 | 
			
		||||
.SH OPTIONS
 | 
			
		||||
.TP
 | 
			
		||||
.BI \-c\  CLIENTID ,\ \-\-clientid= CLIENTID
 | 
			
		||||
Send the client identifier
 | 
			
		||||
.IR CLIENTID .
 | 
			
		||||
.TP
 | 
			
		||||
.BR -f ,\  \-\-foreground
 | 
			
		||||
Do not fork after obtaining a lease.
 | 
			
		||||
.TP
 | 
			
		||||
.BI \-H\  HOSTNAME ,\ \-\-hostname= HOSTNAME
 | 
			
		||||
Send the client hostname
 | 
			
		||||
.IR HOSTNAME .
 | 
			
		||||
.TP
 | 
			
		||||
.BI \-h\  HOSTNAME
 | 
			
		||||
Alias for -H
 | 
			
		||||
.IR HOSTNAME .
 | 
			
		||||
.TP
 | 
			
		||||
.BI \-i\  INTERFACE ,\ \-\-interface= INTERFACE
 | 
			
		||||
Configure
 | 
			
		||||
.IR INTERFACE .
 | 
			
		||||
.TP
 | 
			
		||||
.BR -n ,\  \-\-now
 | 
			
		||||
Exit with failure if a lease cannot be obtained.
 | 
			
		||||
.TP
 | 
			
		||||
.BR -q ,\  \-\-quit
 | 
			
		||||
Exit after obtaining a lease.
 | 
			
		||||
.TP
 | 
			
		||||
.BI \-r\  ADDRESS ,\ \-\-request= ADDRESS
 | 
			
		||||
Request IP address
 | 
			
		||||
.IR ADDRESS .
 | 
			
		||||
.TP
 | 
			
		||||
.BR -v ,\  \-\-version
 | 
			
		||||
Display version.
 | 
			
		||||
.SH NOTES
 | 
			
		||||
.B ndhc
 | 
			
		||||
responds to the following signals:
 | 
			
		||||
.TP
 | 
			
		||||
.B SIGUSR1
 | 
			
		||||
This signal causes
 | 
			
		||||
.B ndhc
 | 
			
		||||
to renew the current lease or, if it does not have one, obtain a
 | 
			
		||||
new lease.
 | 
			
		||||
.TP
 | 
			
		||||
.B SIGUSR2
 | 
			
		||||
This signal caused
 | 
			
		||||
.B ndhc
 | 
			
		||||
to release the current lease.
 | 
			
		||||
							
								
								
									
										48
									
								
								ndhc/nstrl.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								ndhc/nstrl.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,48 @@
 | 
			
		||||
/* nstrl.c - strlcpy/strlcat implementation
 | 
			
		||||
   Time-stamp: <2003-05-28 02:35:13 njk>
 | 
			
		||||
   
 | 
			
		||||
   (C) 2003 Nicholas Jay Kain <njk@aerifal.cx>
 | 
			
		||||
 | 
			
		||||
   This library is free software; you can redistribute it and/or
 | 
			
		||||
   modify it under the terms of the GNU Lesser General Public
 | 
			
		||||
   License as published by the Free Software Foundation; either
 | 
			
		||||
   version 2.1 of the License, or (at your option) any later version.
 | 
			
		||||
   
 | 
			
		||||
   This library is distributed in the hope that it will be useful,
 | 
			
		||||
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
			
		||||
   Lesser General Public License for more details.
 | 
			
		||||
   
 | 
			
		||||
   You should have received a copy of the GNU Lesser General Public
 | 
			
		||||
   License along with this library; if not, write to the Free Software
 | 
			
		||||
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 | 
			
		||||
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
 | 
			
		||||
#ifndef HAVE_STRLCPY
 | 
			
		||||
 | 
			
		||||
size_t strlcpy (char *dest, char *src, size_t size) 
 | 
			
		||||
{
 | 
			
		||||
   register char *d = dest, *s = src;
 | 
			
		||||
   
 | 
			
		||||
   for (; *s != '\0' && size > 0; size--, d++, s++)
 | 
			
		||||
      *d = *s;
 | 
			
		||||
 | 
			
		||||
   *d = '\0';
 | 
			
		||||
   return (d - dest) + (s - src);   
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t strlcat (char *dest, char *src, size_t size)
 | 
			
		||||
{
 | 
			
		||||
   register char *d = dest, *s = src;
 | 
			
		||||
   
 | 
			
		||||
   for (; size > 0 && *d != '\0'; size--, d++);
 | 
			
		||||
 | 
			
		||||
   for (; *s != '\0' && size > 0; size--, d++, s++)
 | 
			
		||||
      *d = *s;
 | 
			
		||||
 | 
			
		||||
   *d = '\0';
 | 
			
		||||
   return (d - dest) + (s - src);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										25
									
								
								ndhc/nstrl.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								ndhc/nstrl.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
			
		||||
/* nstrl.h - header file for strlcpy/strlcat implementation
 | 
			
		||||
   Time-stamp: <2003-05-28 02:34:47 njk>
 | 
			
		||||
   
 | 
			
		||||
   (C) 2003 Nicholas Jay Kain <njk@aerifal.cx>
 | 
			
		||||
 | 
			
		||||
   This library is free software; you can redistribute it and/or
 | 
			
		||||
   modify it under the terms of the GNU Lesser General Public
 | 
			
		||||
   License as published by the Free Software Foundation; either
 | 
			
		||||
   version 2.1 of the License, or (at your option) any later version.
 | 
			
		||||
   
 | 
			
		||||
   This library is distributed in the hope that it will be useful,
 | 
			
		||||
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
			
		||||
   Lesser General Public License for more details.
 | 
			
		||||
   
 | 
			
		||||
   You should have received a copy of the GNU Lesser General Public
 | 
			
		||||
   License along with this library; if not, write to the Free Software
 | 
			
		||||
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 | 
			
		||||
 | 
			
		||||
#ifndef NJK_HAVE_STRL_
 | 
			
		||||
size_t strlcpy (char *dest, char *src, size_t size);
 | 
			
		||||
size_t strlcat (char *dest, char *src, size_t size);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define NJK_HAVE_STRL_ 1
 | 
			
		||||
							
								
								
									
										228
									
								
								ndhc/options.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										228
									
								
								ndhc/options.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,228 @@
 | 
			
		||||
/* 
 | 
			
		||||
 * options.c -- DHCP server option packet tools 
 | 
			
		||||
 * Rewrite by Russ Dill <Russ.Dill@asu.edu> July 2001
 | 
			
		||||
 * Fixes and hardening: Nicholas Kain <njk@-n0xZpam-.kain.us>
 | 
			
		||||
 */
 | 
			
		||||
 
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
#include "log.h"
 | 
			
		||||
#include "dhcpd.h"
 | 
			
		||||
#include "options.h"
 | 
			
		||||
#include "leases.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* supported options are easily added here */
 | 
			
		||||
struct dhcp_option options[] = {
 | 
			
		||||
	/* name[10]	flags					code */
 | 
			
		||||
	{"subnet",	OPTION_IP | OPTION_REQ,			0x01},
 | 
			
		||||
	{"timezone",	OPTION_S32,				0x02},
 | 
			
		||||
	{"router",	OPTION_IP | OPTION_LIST | OPTION_REQ,	0x03},
 | 
			
		||||
	{"timesvr",	OPTION_IP | OPTION_LIST,		0x04},
 | 
			
		||||
	{"namesvr",	OPTION_IP | OPTION_LIST,		0x05},
 | 
			
		||||
	{"dns",		OPTION_IP | OPTION_LIST | OPTION_REQ,	0x06},
 | 
			
		||||
	{"logsvr",	OPTION_IP | OPTION_LIST,		0x07},
 | 
			
		||||
	{"cookiesvr",	OPTION_IP | OPTION_LIST,		0x08},
 | 
			
		||||
	{"lprsvr",	OPTION_IP | OPTION_LIST,		0x09},
 | 
			
		||||
	{"hostname",	OPTION_STRING | OPTION_REQ,		0x0c},
 | 
			
		||||
	{"bootsize",	OPTION_U16,				0x0d},
 | 
			
		||||
	{"domain",	OPTION_STRING | OPTION_REQ,		0x0f},
 | 
			
		||||
	{"swapsvr",	OPTION_IP,				0x10},
 | 
			
		||||
	{"rootpath",	OPTION_STRING,				0x11},
 | 
			
		||||
	{"ipttl",	OPTION_U8,				0x17},
 | 
			
		||||
	{"mtu",		OPTION_U16,				0x1a},
 | 
			
		||||
	{"broadcast",	OPTION_IP | OPTION_REQ,			0x1c},
 | 
			
		||||
	{"ntpsrv",	OPTION_IP | OPTION_LIST,		0x2a},
 | 
			
		||||
	{"wins",	OPTION_IP | OPTION_LIST,		0x2c},
 | 
			
		||||
	{"requestip",	OPTION_IP,				0x32},
 | 
			
		||||
	{"lease",	OPTION_U32,				0x33},
 | 
			
		||||
	{"dhcptype",	OPTION_U8,				0x35},
 | 
			
		||||
	{"serverid",	OPTION_IP,				0x36},
 | 
			
		||||
	{"message",	OPTION_STRING,				0x38},
 | 
			
		||||
	{"tftp",	OPTION_STRING,				0x42},
 | 
			
		||||
	{"bootfile",	OPTION_STRING,				0x43},
 | 
			
		||||
	{"",		0x00,				0x00}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Lengths of the different option types */
 | 
			
		||||
int option_lengths[] = {
 | 
			
		||||
	[OPTION_IP] =		4,
 | 
			
		||||
	[OPTION_IP_PAIR] =	8,
 | 
			
		||||
	[OPTION_BOOLEAN] =	1,
 | 
			
		||||
	[OPTION_STRING] =	1,
 | 
			
		||||
	[OPTION_U8] =		1,
 | 
			
		||||
	[OPTION_U16] =		2,
 | 
			
		||||
	[OPTION_S16] =		2,
 | 
			
		||||
	[OPTION_U32] =		4,
 | 
			
		||||
	[OPTION_S32] =		4
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* get an option with bounds checking (warning, not aligned). */
 | 
			
		||||
unsigned char *get_option(struct dhcpMessage *packet, int code)
 | 
			
		||||
{
 | 
			
		||||
	int i = 0, length = 308;
 | 
			
		||||
	unsigned char *optionptr;
 | 
			
		||||
	int over = 0, done = 0, curr = OPTION_FIELD;
 | 
			
		||||
	
 | 
			
		||||
	optionptr = packet->options;
 | 
			
		||||
	while (!done) {
 | 
			
		||||
		if (i >= length) {
 | 
			
		||||
			log_line(LOG_WARNING, "bogus packet, option fields too long.\n");
 | 
			
		||||
			return NULL;
 | 
			
		||||
		}
 | 
			
		||||
		if (optionptr[i + OPT_CODE] == code) {
 | 
			
		||||
			if (i + 1 + optionptr[i + OPT_LEN] >= length) {
 | 
			
		||||
				log_line(LOG_WARNING, "bogus packet, option fields too long.\n");
 | 
			
		||||
				return NULL;
 | 
			
		||||
			}
 | 
			
		||||
			return optionptr + i + 2;
 | 
			
		||||
		}			
 | 
			
		||||
		switch (optionptr[i + OPT_CODE]) {
 | 
			
		||||
			case DHCP_PADDING:
 | 
			
		||||
				i++;
 | 
			
		||||
				break;
 | 
			
		||||
			case DHCP_OPTION_OVER:
 | 
			
		||||
				if (i + 1 + optionptr[i + OPT_LEN] >= length) {
 | 
			
		||||
					log_line(LOG_WARNING,
 | 
			
		||||
							"bogus packet, option fields too long.\n");
 | 
			
		||||
					return NULL;
 | 
			
		||||
				}
 | 
			
		||||
				over = optionptr[i + 3];
 | 
			
		||||
				i += optionptr[OPT_LEN] + 2;
 | 
			
		||||
				break;
 | 
			
		||||
			case DHCP_END:
 | 
			
		||||
				if (curr == OPTION_FIELD && over & FILE_FIELD) {
 | 
			
		||||
					optionptr = packet->file;
 | 
			
		||||
					i = 0;
 | 
			
		||||
					length = 128;
 | 
			
		||||
					curr = FILE_FIELD;
 | 
			
		||||
				} else if (curr == FILE_FIELD && over & SNAME_FIELD) {
 | 
			
		||||
					optionptr = packet->sname;
 | 
			
		||||
					i = 0;
 | 
			
		||||
					length = 64;
 | 
			
		||||
					curr = SNAME_FIELD;
 | 
			
		||||
				} else done = 1;
 | 
			
		||||
				break;
 | 
			
		||||
			default:
 | 
			
		||||
				i += optionptr[OPT_LEN + i] + 2;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* return the position of the 'end' option */
 | 
			
		||||
int end_option(unsigned char *optionptr) 
 | 
			
		||||
{
 | 
			
		||||
	int i = 0;
 | 
			
		||||
 | 
			
		||||
	while (i < 308 && optionptr[i] != DHCP_END) {
 | 
			
		||||
		if (optionptr[i] == DHCP_PADDING)
 | 
			
		||||
			++i;
 | 
			
		||||
		else
 | 
			
		||||
			i += optionptr[i + OPT_LEN] + 2;
 | 
			
		||||
	}
 | 
			
		||||
	return (i < 308 ? i : 308);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* add an option string to the options (an option string contains an option
 | 
			
		||||
 * code, length, then data) */
 | 
			
		||||
int add_option_string(unsigned char *optionptr, unsigned char *string)
 | 
			
		||||
{
 | 
			
		||||
	int end = end_option(optionptr);
 | 
			
		||||
	
 | 
			
		||||
	/* end position + string length + option code/length + end option */
 | 
			
		||||
	if (end + string[OPT_LEN] + 2 + 1 >= 308) {
 | 
			
		||||
		log_line(LOG_ERR, "Option 0x%02x did not fit into the packet!\n",
 | 
			
		||||
				string[OPT_CODE]);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
	debug(LOG_INFO, "adding option 0x%02x\n", string[OPT_CODE]);
 | 
			
		||||
	memcpy(optionptr + end, string, string[OPT_LEN] + 2);
 | 
			
		||||
	optionptr[end + string[OPT_LEN] + 2] = DHCP_END;
 | 
			
		||||
	return string[OPT_LEN] + 2;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int add_simple_option(unsigned char *optionptr, unsigned char code,
 | 
			
		||||
		uint32_t data)
 | 
			
		||||
{
 | 
			
		||||
	int i, length = 0;
 | 
			
		||||
	unsigned char option[2 + 4];
 | 
			
		||||
	
 | 
			
		||||
	for (i = 0; options[i].code; i++)
 | 
			
		||||
		if (options[i].code == code) {
 | 
			
		||||
			length = option_lengths[options[i].flags & TYPE_MASK];
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
	option[OPT_CODE] = code;
 | 
			
		||||
	option[OPT_LEN] = (unsigned char)length;
 | 
			
		||||
 | 
			
		||||
	if (!length) {
 | 
			
		||||
		debug(LOG_ERR, "Could not add option 0x%02x\n", code);
 | 
			
		||||
		return 0;
 | 
			
		||||
	} else if (length == 1) {
 | 
			
		||||
		uint8_t t = (uint8_t)data;
 | 
			
		||||
		memcpy(option + 2, &t, 1);
 | 
			
		||||
	} else if (length == 2) {
 | 
			
		||||
		uint16_t t = (uint16_t)data;
 | 
			
		||||
		memcpy(option + 2, &t, 2);
 | 
			
		||||
	} else if (length == 4) {
 | 
			
		||||
		uint32_t t = (uint32_t)data;
 | 
			
		||||
		memcpy(option + 2, &t, 4);
 | 
			
		||||
	}
 | 
			
		||||
	return add_option_string(optionptr, option);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* find option 'code' in opt_list */
 | 
			
		||||
struct option_set *find_option(struct option_set *opt_list, char code)
 | 
			
		||||
{
 | 
			
		||||
	while (opt_list && opt_list->data[OPT_CODE] < code)
 | 
			
		||||
		opt_list = opt_list->next;
 | 
			
		||||
 | 
			
		||||
	if (opt_list && opt_list->data[OPT_CODE] == code) return opt_list;
 | 
			
		||||
	else return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* add an option to the opt_list */
 | 
			
		||||
void attach_option(struct option_set **opt_list, struct dhcp_option *option,
 | 
			
		||||
		char *buffer, int length)
 | 
			
		||||
{
 | 
			
		||||
	struct option_set *existing, *new, **curr;
 | 
			
		||||
 | 
			
		||||
	/* add it to an existing option */
 | 
			
		||||
	if ((existing = find_option(*opt_list, option->code))) {
 | 
			
		||||
		debug(LOG_INFO, "Attaching option %s to existing member of list\n",
 | 
			
		||||
				option->name);
 | 
			
		||||
		if (option->flags & OPTION_LIST) {
 | 
			
		||||
			if (existing->data[OPT_LEN] + length <= 255) {
 | 
			
		||||
				existing->data = realloc(existing->data, 
 | 
			
		||||
						existing->data[OPT_LEN] + length + 2);
 | 
			
		||||
				memcpy(existing->data + existing->data[OPT_LEN] + 2, buffer,
 | 
			
		||||
						length);
 | 
			
		||||
				existing->data[OPT_LEN] += length;
 | 
			
		||||
			} /* else, ignore the data; we could put this in a second option
 | 
			
		||||
				 in the future */
 | 
			
		||||
		} /* else, ignore the new data */
 | 
			
		||||
	} else {
 | 
			
		||||
		debug(LOG_INFO, "Attaching option %s to list\n", option->name);
 | 
			
		||||
		
 | 
			
		||||
		/* make a new option */
 | 
			
		||||
		new = malloc(sizeof(struct option_set));
 | 
			
		||||
		new->data = malloc(length + 2);
 | 
			
		||||
		new->data[OPT_CODE] = option->code;
 | 
			
		||||
		new->data[OPT_LEN] = length;
 | 
			
		||||
		memcpy(new->data + 2, buffer, length);
 | 
			
		||||
		
 | 
			
		||||
		curr = opt_list;
 | 
			
		||||
		while (*curr && (*curr)->data[OPT_CODE] < option->code)
 | 
			
		||||
			curr = &(*curr)->next;
 | 
			
		||||
			
 | 
			
		||||
		new->next = *curr;
 | 
			
		||||
		*curr = new;		
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										40
									
								
								ndhc/options.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								ndhc/options.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,40 @@
 | 
			
		||||
/* options.h */
 | 
			
		||||
#ifndef _OPTIONS_H
 | 
			
		||||
#define _OPTIONS_H
 | 
			
		||||
 | 
			
		||||
#include "packet.h"
 | 
			
		||||
 | 
			
		||||
#define TYPE_MASK	0x0F
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
	OPTION_IP=1,
 | 
			
		||||
	OPTION_IP_PAIR,
 | 
			
		||||
	OPTION_STRING,
 | 
			
		||||
	OPTION_BOOLEAN,
 | 
			
		||||
	OPTION_U8,
 | 
			
		||||
	OPTION_U16,
 | 
			
		||||
	OPTION_S16,
 | 
			
		||||
	OPTION_U32,
 | 
			
		||||
	OPTION_S32
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define OPTION_REQ	0x10 /* have the client request this option */
 | 
			
		||||
#define OPTION_LIST	0x20 /* There can be a list of 1 or more of these */
 | 
			
		||||
 | 
			
		||||
struct dhcp_option {
 | 
			
		||||
	char name[10];
 | 
			
		||||
	char flags;
 | 
			
		||||
	unsigned char code;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
extern struct dhcp_option options[];
 | 
			
		||||
extern int option_lengths[];
 | 
			
		||||
 | 
			
		||||
unsigned char *get_option(struct dhcpMessage *packet, int code);
 | 
			
		||||
int end_option(unsigned char *optionptr);
 | 
			
		||||
int add_option_string(unsigned char *optionptr, unsigned char *string);
 | 
			
		||||
int add_simple_option(unsigned char *optionptr, unsigned char code, uint32_t data);
 | 
			
		||||
struct option_set *find_option(struct option_set *opt_list, char code);
 | 
			
		||||
void attach_option(struct option_set **opt_list, struct dhcp_option *option, char *buffer, int length);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										203
									
								
								ndhc/packet.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										203
									
								
								ndhc/packet.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,203 @@
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <netinet/in.h>
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <sys/socket.h>
 | 
			
		||||
#include <features.h>
 | 
			
		||||
#include <netpacket/packet.h>
 | 
			
		||||
#include <net/ethernet.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
 | 
			
		||||
#include "packet.h"
 | 
			
		||||
#include "log.h"
 | 
			
		||||
#include "dhcpd.h"
 | 
			
		||||
#include "options.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void init_header(struct dhcpMessage *packet, char type)
 | 
			
		||||
{
 | 
			
		||||
	memset(packet, 0, sizeof(struct dhcpMessage));
 | 
			
		||||
	switch (type) {
 | 
			
		||||
	case DHCPDISCOVER:
 | 
			
		||||
	case DHCPREQUEST:
 | 
			
		||||
	case DHCPRELEASE:
 | 
			
		||||
	case DHCPINFORM:
 | 
			
		||||
		packet->op = BOOTREQUEST;
 | 
			
		||||
		break;
 | 
			
		||||
	case DHCPOFFER:
 | 
			
		||||
	case DHCPACK:
 | 
			
		||||
	case DHCPNAK:
 | 
			
		||||
		packet->op = BOOTREPLY;
 | 
			
		||||
	}
 | 
			
		||||
	packet->htype = ETH_10MB;
 | 
			
		||||
	packet->hlen = ETH_10MB_LEN;
 | 
			
		||||
	packet->cookie = htonl(DHCP_MAGIC);
 | 
			
		||||
	packet->options[0] = DHCP_END;
 | 
			
		||||
	add_simple_option(packet->options, DHCP_MESSAGE_TYPE, type);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* read a packet from socket fd, return -1 on read error, -2 on packet error */
 | 
			
		||||
int get_packet(struct dhcpMessage *packet, int fd)
 | 
			
		||||
{
 | 
			
		||||
	int bytes;
 | 
			
		||||
	int i;
 | 
			
		||||
	const char broken_vendors[][8] = {
 | 
			
		||||
		"MSFT 98",
 | 
			
		||||
		""
 | 
			
		||||
	};
 | 
			
		||||
	unsigned char *vendor;
 | 
			
		||||
 | 
			
		||||
	memset(packet, 0, sizeof(struct dhcpMessage));
 | 
			
		||||
	bytes = read(fd, packet, sizeof(struct dhcpMessage));
 | 
			
		||||
	if (bytes < 0) {
 | 
			
		||||
		debug(LOG_INFO, "couldn't read on listening socket, ignoring\n");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (ntohl(packet->cookie) != DHCP_MAGIC) {
 | 
			
		||||
		log_line(LOG_ERR, "received bogus message, ignoring.\n");
 | 
			
		||||
		return -2;
 | 
			
		||||
	}
 | 
			
		||||
	debug(LOG_INFO, "Received a packet\n");
 | 
			
		||||
	
 | 
			
		||||
	if (packet->op == BOOTREQUEST
 | 
			
		||||
			&& (vendor = get_option(packet, DHCP_VENDOR)))
 | 
			
		||||
	{
 | 
			
		||||
		for (i = 0; broken_vendors[i][0]; i++) {
 | 
			
		||||
			if (vendor[OPT_LEN - 2] == (unsigned char)strlen(broken_vendors[i])
 | 
			
		||||
					&& !strncmp((char *)vendor, broken_vendors[i],
 | 
			
		||||
						vendor[OPT_LEN - 2]))
 | 
			
		||||
			{
 | 
			
		||||
			    	debug(LOG_INFO, "broken client (%s), forcing broadcast\n",
 | 
			
		||||
			    		broken_vendors[i]);
 | 
			
		||||
			    	packet->flags |= htons(BROADCAST_FLAG);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return bytes;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint16_t checksum(void *addr, int count)
 | 
			
		||||
{
 | 
			
		||||
	/* Compute Internet Checksum for "count" bytes
 | 
			
		||||
	 *         beginning at location "addr".
 | 
			
		||||
	 */
 | 
			
		||||
	register int32_t sum = 0;
 | 
			
		||||
	uint16_t *source = (uint16_t *)addr;
 | 
			
		||||
 | 
			
		||||
	while (count > 1)  {
 | 
			
		||||
		sum += *source++;
 | 
			
		||||
		count -= 2;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*  Add left-over byte, if any */
 | 
			
		||||
	if (count > 0) {
 | 
			
		||||
		/* Make sure that the left-over byte is added correctly both
 | 
			
		||||
		 * with little and big endian hosts */
 | 
			
		||||
		uint16_t tmp = 0;
 | 
			
		||||
		*(unsigned char *) (&tmp) = * (unsigned char *) source;
 | 
			
		||||
		sum += tmp;
 | 
			
		||||
	}
 | 
			
		||||
	/*  Fold 32-bit sum to 16 bits */
 | 
			
		||||
	while (sum >> 16)
 | 
			
		||||
		sum = (sum & 0xffff) + (sum >> 16);
 | 
			
		||||
 | 
			
		||||
	return ~sum;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Constuct a ip/udp header for a packet, and specify the source and dest
 | 
			
		||||
 * hardware address */
 | 
			
		||||
int raw_packet(struct dhcpMessage *payload, uint32_t source_ip,
 | 
			
		||||
		int source_port, uint32_t dest_ip, int dest_port,
 | 
			
		||||
		unsigned char *dest_arp, int ifindex)
 | 
			
		||||
{
 | 
			
		||||
	int fd, result = -1;
 | 
			
		||||
	struct sockaddr_ll dest;
 | 
			
		||||
	struct udp_dhcp_packet packet;
 | 
			
		||||
 | 
			
		||||
	if ((fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))) < 0) {
 | 
			
		||||
		debug(LOG_ERR, "socket call failed: %s\n", strerror(errno));
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	memset(&dest, 0, sizeof(dest));
 | 
			
		||||
	memset(&packet, 0, sizeof(packet));
 | 
			
		||||
	
 | 
			
		||||
	dest.sll_family = AF_PACKET;
 | 
			
		||||
	dest.sll_protocol = htons(ETH_P_IP);
 | 
			
		||||
	dest.sll_ifindex = ifindex;
 | 
			
		||||
	dest.sll_halen = 6;
 | 
			
		||||
	memcpy(dest.sll_addr, dest_arp, 6);
 | 
			
		||||
	if (bind(fd, (struct sockaddr *)&dest, sizeof(struct sockaddr_ll)) < 0) {
 | 
			
		||||
		debug(LOG_ERR, "bind call failed: %s\n", strerror(errno));
 | 
			
		||||
		goto out_fd;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	packet.ip.protocol = IPPROTO_UDP;
 | 
			
		||||
	packet.ip.saddr = source_ip;
 | 
			
		||||
	packet.ip.daddr = dest_ip;
 | 
			
		||||
	packet.udp.source = htons(source_port);
 | 
			
		||||
	packet.udp.dest = htons(dest_port);
 | 
			
		||||
	/* cheat on the psuedo-header */
 | 
			
		||||
	packet.udp.len = htons(sizeof(packet.udp) + sizeof(struct dhcpMessage));
 | 
			
		||||
	packet.ip.tot_len = packet.udp.len;
 | 
			
		||||
	memcpy(&(packet.data), payload, sizeof(struct dhcpMessage));
 | 
			
		||||
	packet.udp.check = checksum(&packet, sizeof(struct udp_dhcp_packet));
 | 
			
		||||
	
 | 
			
		||||
	packet.ip.tot_len = htons(sizeof(struct udp_dhcp_packet));
 | 
			
		||||
	packet.ip.ihl = sizeof(packet.ip) >> 2;
 | 
			
		||||
	packet.ip.version = IPVERSION;
 | 
			
		||||
	packet.ip.ttl = IPDEFTTL;
 | 
			
		||||
	packet.ip.check = checksum(&(packet.ip), sizeof(packet.ip));
 | 
			
		||||
 | 
			
		||||
	result = sendto(fd, &packet, sizeof(struct udp_dhcp_packet), 0,
 | 
			
		||||
			(struct sockaddr *)&dest, sizeof dest);
 | 
			
		||||
	if (result <= 0) {
 | 
			
		||||
		debug(LOG_ERR, "write on socket failed: %s\n",
 | 
			
		||||
				strerror(errno));
 | 
			
		||||
	}
 | 
			
		||||
out_fd:
 | 
			
		||||
	close(fd);
 | 
			
		||||
out:
 | 
			
		||||
	return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Let the kernel do all the work for packet generation */
 | 
			
		||||
int kernel_packet(struct dhcpMessage *payload, uint32_t source_ip,
 | 
			
		||||
		int source_port, uint32_t dest_ip, int dest_port)
 | 
			
		||||
{
 | 
			
		||||
	int n = 1, fd, result = -1;
 | 
			
		||||
	struct sockaddr_in client;
 | 
			
		||||
	
 | 
			
		||||
	if ((fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
 | 
			
		||||
		goto out;
 | 
			
		||||
	
 | 
			
		||||
	if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &n, sizeof(n)) == -1)
 | 
			
		||||
		goto out_fd;
 | 
			
		||||
 | 
			
		||||
	memset(&client, 0, sizeof(client));
 | 
			
		||||
	client.sin_family = AF_INET;
 | 
			
		||||
	client.sin_port = htons(source_port);
 | 
			
		||||
	client.sin_addr.s_addr = source_ip;
 | 
			
		||||
 | 
			
		||||
	if (bind(fd, (struct sockaddr *)&client, sizeof(struct sockaddr)) == -1)
 | 
			
		||||
		goto out_fd;
 | 
			
		||||
 | 
			
		||||
	memset(&client, 0, sizeof(client));
 | 
			
		||||
	client.sin_family = AF_INET;
 | 
			
		||||
	client.sin_port = htons(dest_port);
 | 
			
		||||
	client.sin_addr.s_addr = dest_ip; 
 | 
			
		||||
 | 
			
		||||
	if (connect(fd, (struct sockaddr *)&client, sizeof(struct sockaddr)) == -1)
 | 
			
		||||
		goto out_fd;
 | 
			
		||||
 | 
			
		||||
	result = write(fd, payload, sizeof(struct dhcpMessage));
 | 
			
		||||
out_fd:
 | 
			
		||||
	close(fd);
 | 
			
		||||
out:
 | 
			
		||||
	return result;
 | 
			
		||||
}	
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										41
									
								
								ndhc/packet.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								ndhc/packet.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,41 @@
 | 
			
		||||
#ifndef _PACKET_H
 | 
			
		||||
#define _PACKET_H
 | 
			
		||||
 | 
			
		||||
#include <netinet/udp.h>
 | 
			
		||||
#include <netinet/ip.h>
 | 
			
		||||
 | 
			
		||||
struct dhcpMessage {
 | 
			
		||||
	uint8_t op;
 | 
			
		||||
	uint8_t htype;
 | 
			
		||||
	uint8_t hlen;
 | 
			
		||||
	uint8_t hops;
 | 
			
		||||
	uint32_t xid;
 | 
			
		||||
	uint16_t secs;
 | 
			
		||||
	uint16_t flags;
 | 
			
		||||
	uint32_t ciaddr;
 | 
			
		||||
	uint32_t yiaddr;
 | 
			
		||||
	uint32_t siaddr;
 | 
			
		||||
	uint32_t giaddr;
 | 
			
		||||
	uint8_t chaddr[16];
 | 
			
		||||
	uint8_t sname[64];
 | 
			
		||||
	uint8_t file[128];
 | 
			
		||||
	uint32_t cookie;
 | 
			
		||||
	uint8_t options[308]; /* 312 - cookie */ 
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct udp_dhcp_packet {
 | 
			
		||||
	struct iphdr ip;
 | 
			
		||||
	struct udphdr udp;
 | 
			
		||||
	struct dhcpMessage data;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void init_header(struct dhcpMessage *packet, char type);
 | 
			
		||||
int get_packet(struct dhcpMessage *packet, int fd);
 | 
			
		||||
uint16_t checksum(void *addr, int count);
 | 
			
		||||
int raw_packet(struct dhcpMessage *payload, uint32_t source_ip, int source_port,
 | 
			
		||||
		   uint32_t dest_ip, int dest_port, unsigned char *dest_arp, int ifindex);
 | 
			
		||||
int kernel_packet(struct dhcpMessage *payload, uint32_t source_ip, int source_port,
 | 
			
		||||
		   uint32_t dest_ip, int dest_port);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										67
									
								
								ndhc/rootcap.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								ndhc/rootcap.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,67 @@
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <sys/capability.h>
 | 
			
		||||
#include <sys/prctl.h>
 | 
			
		||||
#include <grp.h>
 | 
			
		||||
 | 
			
		||||
#include "log.h"
 | 
			
		||||
 | 
			
		||||
static void set_cap(uid_t uid, gid_t gid, char *captxt) 
 | 
			
		||||
{
 | 
			
		||||
    cap_t caps;
 | 
			
		||||
 | 
			
		||||
    if (!captxt) {
 | 
			
		||||
        log_line(LOG_ERR, "FATAL - set_cap: captxt == NULL\n");
 | 
			
		||||
        exit(EXIT_FAILURE);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    if (prctl(PR_SET_KEEPCAPS, 1)) {
 | 
			
		||||
        log_line(LOG_ERR, "FATAL - set_cap: prctl() failed\n");
 | 
			
		||||
        exit(EXIT_FAILURE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (setgroups(0, NULL) == -1) {
 | 
			
		||||
	    log_line(LOG_ERR, "FATAL - set_cap: setgroups() failed\n");
 | 
			
		||||
	    exit(EXIT_FAILURE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (setegid(gid) == -1 || seteuid(uid) == -1) {
 | 
			
		||||
	    log_line(LOG_ERR, "FATAL - set_cap: seteuid() failed\n");
 | 
			
		||||
	    exit(EXIT_FAILURE);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    caps = cap_from_text(captxt);
 | 
			
		||||
    if (!caps) {
 | 
			
		||||
        log_line(LOG_ERR, "FATAL - set_cap: cap_from_text() failed\n");
 | 
			
		||||
        exit(EXIT_FAILURE);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    if (cap_set_proc(caps) == -1) {
 | 
			
		||||
        log_line(LOG_ERR, "FATAL - set_cap: cap_set_proc() failed\n");
 | 
			
		||||
        exit(EXIT_FAILURE);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    cap_free(caps);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void drop_root(uid_t uid, gid_t gid, char *captxt) 
 | 
			
		||||
{
 | 
			
		||||
    if (!captxt) {
 | 
			
		||||
        log_line(LOG_ERR, "FATAL - drop_root: captxt == NULL\n");
 | 
			
		||||
        exit(EXIT_FAILURE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (uid == 0 || gid == 0) {
 | 
			
		||||
        log_line(LOG_ERR, "FATAL - drop_root: attempt to drop root to root?\n");
 | 
			
		||||
        exit(EXIT_FAILURE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    set_cap(uid, gid, captxt);
 | 
			
		||||
 | 
			
		||||
    if (setregid(gid, gid) == -1 || setreuid(uid, uid) == -1) {
 | 
			
		||||
        log_line(LOG_ERR, "FATAL - drop_root: failed to drop root!\n");
 | 
			
		||||
        exit(EXIT_FAILURE);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										2
									
								
								ndhc/rootcap.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								ndhc/rootcap.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,2 @@
 | 
			
		||||
void drop_root(uid_t uid, gid_t gid, char *captxt);
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										258
									
								
								ndhc/script.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										258
									
								
								ndhc/script.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,258 @@
 | 
			
		||||
/* script.c
 | 
			
		||||
 *
 | 
			
		||||
 * Functions to call the interface change daemon
 | 
			
		||||
 *
 | 
			
		||||
 * Russ Dill <Russ.Dill@asu.edu> July 2001
 | 
			
		||||
 * Nicholas Kain <njk@nozspamz.aerifal.cx> 2004
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; if not, write to the Free Software
 | 
			
		||||
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <sys/socket.h>
 | 
			
		||||
#include <netinet/in.h>
 | 
			
		||||
#include <arpa/inet.h>
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <sys/un.h>
 | 
			
		||||
#include <sys/wait.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
 | 
			
		||||
#include "options.h"
 | 
			
		||||
#include "dhcpd.h"
 | 
			
		||||
#include "dhcpc.h"
 | 
			
		||||
#include "packet.h"
 | 
			
		||||
#include "options.h"
 | 
			
		||||
#include "log.h"
 | 
			
		||||
#include "script.h"
 | 
			
		||||
 | 
			
		||||
static int snprintip(char *dest, size_t size, unsigned char *ip) {
 | 
			
		||||
	if (!dest) return -1;
 | 
			
		||||
	return snprintf(dest, size, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int sprintip(char *dest, size_t size, char *pre, unsigned char *ip) {
 | 
			
		||||
	if (!dest) return -1;
 | 
			
		||||
	return snprintf(dest, size, "%s%d.%d.%d.%d", pre, ip[0], ip[1], ip[2], ip[3]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Fill dest with the text of option 'option'. */
 | 
			
		||||
static void fill_options(char *dest, unsigned char *option, struct dhcp_option *type_p, unsigned int maxlen)
 | 
			
		||||
{
 | 
			
		||||
	int type, optlen;
 | 
			
		||||
	uint16_t val_u16;
 | 
			
		||||
	int16_t val_s16;
 | 
			
		||||
	uint32_t val_u32;
 | 
			
		||||
	int32_t val_s32;
 | 
			
		||||
	int len = option[OPT_LEN - 2];
 | 
			
		||||
	char *odest;
 | 
			
		||||
	
 | 
			
		||||
	odest = dest;
 | 
			
		||||
	
 | 
			
		||||
	dest += snprintf(dest, maxlen, "%s=", type_p->name);
 | 
			
		||||
 | 
			
		||||
	type = type_p->flags & TYPE_MASK;
 | 
			
		||||
	optlen = option_lengths[type];
 | 
			
		||||
	for(;;) {
 | 
			
		||||
		switch (type) {
 | 
			
		||||
		case OPTION_IP_PAIR:
 | 
			
		||||
			dest += sprintip(dest, maxlen - (dest - odest), "", option);
 | 
			
		||||
			*(dest++) = '/';
 | 
			
		||||
			option += 4;
 | 
			
		||||
			optlen = 4;
 | 
			
		||||
		case OPTION_IP:	/* Works regardless of host byte order. */
 | 
			
		||||
			dest += sprintip(dest, maxlen - (dest - odest), "", option);
 | 
			
		||||
 			break;
 | 
			
		||||
		case OPTION_BOOLEAN:
 | 
			
		||||
			dest += snprintf(dest, maxlen - (dest - odest), *option ? "yes " : "no ");
 | 
			
		||||
			break;
 | 
			
		||||
		case OPTION_U8:
 | 
			
		||||
			dest += snprintf(dest, maxlen - (dest - odest), "%u ", *option);
 | 
			
		||||
			break;
 | 
			
		||||
		case OPTION_U16:
 | 
			
		||||
			memcpy(&val_u16, option, 2);
 | 
			
		||||
			dest += snprintf(dest, maxlen - (dest - odest), "%u ", ntohs(val_u16));
 | 
			
		||||
			break;
 | 
			
		||||
		case OPTION_S16:
 | 
			
		||||
			memcpy(&val_s16, option, 2);
 | 
			
		||||
			dest += snprintf(dest, maxlen - (dest - odest), "%d ", ntohs(val_s16));
 | 
			
		||||
			break;
 | 
			
		||||
		case OPTION_U32:
 | 
			
		||||
			memcpy(&val_u32, option, 4);
 | 
			
		||||
			dest += snprintf(dest, maxlen - (dest - odest), "%lu ", (unsigned long) ntohl(val_u32));
 | 
			
		||||
			break;
 | 
			
		||||
		case OPTION_S32:
 | 
			
		||||
			memcpy(&val_s32, option, 4);
 | 
			
		||||
			dest += snprintf(dest, maxlen - (dest - odest), "%ld ", (long) ntohl(val_s32));
 | 
			
		||||
			break;
 | 
			
		||||
		case OPTION_STRING:
 | 
			
		||||
			if ( (maxlen - (dest - odest)) < (unsigned)len) return;
 | 
			
		||||
			memcpy(dest, option, len);
 | 
			
		||||
			dest[len] = '\0';
 | 
			
		||||
			return;	 /* Short circuit this case */
 | 
			
		||||
		}
 | 
			
		||||
		option += optlen;
 | 
			
		||||
		len -= optlen;
 | 
			
		||||
		if (len <= 0) break;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int open_ifch(void) {
 | 
			
		||||
	int sockfd, ret;
 | 
			
		||||
	struct sockaddr_un address = 
 | 
			
		||||
	{
 | 
			
		||||
		.sun_family = AF_UNIX,
 | 
			
		||||
		.sun_path = "ifchange"
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
 | 
			
		||||
	ret = connect(sockfd, (struct sockaddr *)&address, sizeof(address));
 | 
			
		||||
 | 
			
		||||
	if (ret == -1) {
 | 
			
		||||
		log_line(LOG_ERR, "unable to connect to ifchd!\n");
 | 
			
		||||
		exit(EXIT_FAILURE);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return sockfd;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void sockwrite(int fd, const void *buf, size_t count)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
sockwrite_again:
 | 
			
		||||
	ret = write(fd, buf, count);
 | 
			
		||||
	if (ret == -1) {
 | 
			
		||||
		if (errno == EAGAIN)
 | 
			
		||||
			goto sockwrite_again;
 | 
			
		||||
		log_line(LOG_ERR, "error while writing to unix socket!\n");
 | 
			
		||||
		exit(EXIT_FAILURE);
 | 
			
		||||
	}
 | 
			
		||||
	if (ret < 0) ret = 0;
 | 
			
		||||
	if ((unsigned int)ret < strlen(buf)) {
 | 
			
		||||
		log_line(LOG_ERR, "incomplete write!\n");
 | 
			
		||||
	}
 | 
			
		||||
	debug(LOG_INFO, "writing: %s\n", (char *)buf);
 | 
			
		||||
}			
 | 
			
		||||
 | 
			
		||||
static void deconfig_if(void)
 | 
			
		||||
{
 | 
			
		||||
	int sockfd;
 | 
			
		||||
	char buf[256];
 | 
			
		||||
	
 | 
			
		||||
	memset(buf, '\0', sizeof buf);
 | 
			
		||||
	
 | 
			
		||||
	sockfd = open_ifch();
 | 
			
		||||
	
 | 
			
		||||
	snprintf(buf, sizeof buf, "interface:%s:",
 | 
			
		||||
		       client_config.interface);
 | 
			
		||||
	sockwrite(sockfd, buf, strlen(buf));
 | 
			
		||||
 | 
			
		||||
	snprintf(buf, sizeof buf, "ip:0.0.0.0:");
 | 
			
		||||
	sockwrite(sockfd, buf, strlen(buf));
 | 
			
		||||
	
 | 
			
		||||
	close(sockfd);
 | 
			
		||||
	exit(EXIT_SUCCESS);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void translate_option(int sockfd, struct dhcpMessage *packet, int opt) {
 | 
			
		||||
	char buf[256], buf2[256];
 | 
			
		||||
	unsigned char *p;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	if (!packet) return;
 | 
			
		||||
 | 
			
		||||
	memset(buf, '\0', sizeof(buf));
 | 
			
		||||
	memset(buf2, '\0', sizeof(buf2));
 | 
			
		||||
	
 | 
			
		||||
	p = get_option(packet, options[opt].code);
 | 
			
		||||
	fill_options(buf2, p, &options[opt], sizeof(buf2) - 1);
 | 
			
		||||
	snprintf(buf, sizeof buf, "%s:", buf2);
 | 
			
		||||
	for (i=0; i<256; i++) {
 | 
			
		||||
		if (buf[i] == '\0') break;
 | 
			
		||||
		if (buf[i] == '=') {
 | 
			
		||||
			buf[i] = ':';
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	sockwrite(sockfd, buf, strlen(buf));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void bound_if(struct dhcpMessage *packet)
 | 
			
		||||
{
 | 
			
		||||
	int sockfd;
 | 
			
		||||
	char buf[256], buf2[256];
 | 
			
		||||
	char ip[32];
 | 
			
		||||
	
 | 
			
		||||
	if (!packet) return;
 | 
			
		||||
	
 | 
			
		||||
	memset(buf, '\0', sizeof(buf));
 | 
			
		||||
	memset(ip, '\0', sizeof(ip));
 | 
			
		||||
	memset(buf2, '\0', sizeof(buf2));
 | 
			
		||||
	
 | 
			
		||||
	sockfd = open_ifch();
 | 
			
		||||
 | 
			
		||||
	snprintf(buf, sizeof buf, "interface:%s:", client_config.interface);
 | 
			
		||||
	sockwrite(sockfd, buf, strlen(buf));
 | 
			
		||||
 | 
			
		||||
	snprintip(ip, sizeof ip, (unsigned char *) &packet->yiaddr);
 | 
			
		||||
	snprintf(buf, sizeof buf, "ip:%s:", ip);
 | 
			
		||||
	sockwrite(sockfd, buf, strlen(buf));
 | 
			
		||||
	
 | 
			
		||||
	translate_option(sockfd, packet, 0);
 | 
			
		||||
	translate_option(sockfd, packet, 2);
 | 
			
		||||
	translate_option(sockfd, packet, 5);
 | 
			
		||||
	translate_option(sockfd, packet, 9);
 | 
			
		||||
	translate_option(sockfd, packet, 11);
 | 
			
		||||
	translate_option(sockfd, packet, 15);
 | 
			
		||||
	translate_option(sockfd, packet, 16);
 | 
			
		||||
	translate_option(sockfd, packet, 17);
 | 
			
		||||
	
 | 
			
		||||
	close(sockfd);
 | 
			
		||||
	exit(EXIT_SUCCESS);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void run_script(struct dhcpMessage *packet, int mode)
 | 
			
		||||
{
 | 
			
		||||
	int pid;
 | 
			
		||||
	
 | 
			
		||||
	pid = fork();
 | 
			
		||||
	if (pid) {
 | 
			
		||||
		waitpid(pid, NULL, 0);
 | 
			
		||||
		return;
 | 
			
		||||
	} else if (pid == 0) {
 | 
			
		||||
		switch (mode) {
 | 
			
		||||
			case SCRIPT_DECONFIG:
 | 
			
		||||
				deconfig_if();
 | 
			
		||||
				break;
 | 
			
		||||
			case SCRIPT_BOUND:
 | 
			
		||||
				bound_if(packet);
 | 
			
		||||
				break;
 | 
			
		||||
			case SCRIPT_RENEW:
 | 
			
		||||
				bound_if(packet);
 | 
			
		||||
				break;
 | 
			
		||||
			case SCRIPT_NAK:
 | 
			
		||||
				deconfig_if();
 | 
			
		||||
				break;
 | 
			
		||||
			default:
 | 
			
		||||
				break;
 | 
			
		||||
		}
 | 
			
		||||
		log_line(LOG_ERR, "invalid script mode: %d\n", mode);
 | 
			
		||||
		exit(EXIT_FAILURE);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										13
									
								
								ndhc/script.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								ndhc/script.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
			
		||||
#ifndef _SCRIPT_H
 | 
			
		||||
#define _SCRIPT_H
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
	SCRIPT_DECONFIG = 0,
 | 
			
		||||
	SCRIPT_BOUND = 1,
 | 
			
		||||
	SCRIPT_RENEW = 2,
 | 
			
		||||
	SCRIPT_NAK = 4
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void run_script(struct dhcpMessage *packet, int mode);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										155
									
								
								ndhc/socket.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										155
									
								
								ndhc/socket.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,155 @@
 | 
			
		||||
/*
 | 
			
		||||
 * socket.c -- DHCP server client/server socket creation
 | 
			
		||||
 *
 | 
			
		||||
 * udhcp client/server
 | 
			
		||||
 * Copyright (C) 1999 Matthew Ramsay <matthewr@moreton.com.au>
 | 
			
		||||
 *			Chris Trew <ctrew@moreton.com.au>
 | 
			
		||||
 *
 | 
			
		||||
 * Rewrite by Russ Dill <Russ.Dill@asu.edu> July 2001
 | 
			
		||||
 *
 | 
			
		||||
 * Cleanup and fixes, Nicholas Kain <njk@n0sPaM.kain.us> 2004
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; if not, write to the Free Software
 | 
			
		||||
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <sys/socket.h>
 | 
			
		||||
#include <sys/ioctl.h>
 | 
			
		||||
#include <netinet/in.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <arpa/inet.h>
 | 
			
		||||
#include <net/if.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <features.h>
 | 
			
		||||
#include <netpacket/packet.h>
 | 
			
		||||
#include <net/ethernet.h>
 | 
			
		||||
#include "log.h"
 | 
			
		||||
#include "nstrl.h"
 | 
			
		||||
 | 
			
		||||
int read_interface(char *interface, int *ifindex, uint32_t *addr,
 | 
			
		||||
		unsigned char *arp)
 | 
			
		||||
{
 | 
			
		||||
	int fd, ret = -1;
 | 
			
		||||
	struct ifreq ifr;
 | 
			
		||||
	struct sockaddr_in *our_ip;
 | 
			
		||||
 | 
			
		||||
	memset(&ifr, 0, sizeof(struct ifreq));
 | 
			
		||||
	if((fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) == -1) {
 | 
			
		||||
		log_line(LOG_ERR, "socket failed!: %s\n", strerror(errno));
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ifr.ifr_addr.sa_family = AF_INET;
 | 
			
		||||
	strlcpy(ifr.ifr_name, interface, IFNAMSIZ);
 | 
			
		||||
 | 
			
		||||
	if (addr) { 
 | 
			
		||||
		if (ioctl(fd, SIOCGIFADDR, &ifr)) {
 | 
			
		||||
			log_line(LOG_ERR, "Couldn't get IP for %s.\n", strerror(errno));
 | 
			
		||||
			goto out_fd;
 | 
			
		||||
		}
 | 
			
		||||
		our_ip = (struct sockaddr_in *) &ifr.ifr_addr;
 | 
			
		||||
		*addr = our_ip->sin_addr.s_addr;
 | 
			
		||||
		debug(LOG_INFO, "%s (our ip) = %s\n", ifr.ifr_name,
 | 
			
		||||
				inet_ntoa(our_ip->sin_addr));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (ioctl(fd, SIOCGIFINDEX, &ifr)) {
 | 
			
		||||
		log_line(LOG_ERR, "SIOCGIFINDEX failed!: %s\n", strerror(errno));
 | 
			
		||||
		goto out_fd;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	debug(LOG_INFO, "adapter index %d\n", ifr.ifr_ifindex);
 | 
			
		||||
	*ifindex = ifr.ifr_ifindex;
 | 
			
		||||
 | 
			
		||||
	if (ioctl(fd, SIOCGIFHWADDR, &ifr)) {
 | 
			
		||||
		log_line(LOG_ERR, "Couldn't get MAC for %s\n", strerror(errno));
 | 
			
		||||
		goto out_fd;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	memcpy(arp, ifr.ifr_hwaddr.sa_data, 6);
 | 
			
		||||
	debug(LOG_INFO, "adapter hardware address %02x:%02x:%02x:%02x:%02x:%02x\n",
 | 
			
		||||
			arp[0], arp[1], arp[2], arp[3], arp[4], arp[5]);
 | 
			
		||||
	ret = 0;
 | 
			
		||||
out_fd:
 | 
			
		||||
	close(fd);
 | 
			
		||||
out:
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int listen_socket(unsigned int ip, int port, char *inf)
 | 
			
		||||
{
 | 
			
		||||
	struct ifreq interface;
 | 
			
		||||
	int fd;
 | 
			
		||||
	struct sockaddr_in addr;
 | 
			
		||||
	int n = 1;
 | 
			
		||||
 | 
			
		||||
	debug(LOG_INFO, "Opening listen socket on 0x%08x:%d %s\n", ip, port, inf);
 | 
			
		||||
	if ((fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
 | 
			
		||||
		debug(LOG_ERR, "socket call failed: %s\n", strerror(errno));
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	memset(&addr, 0, sizeof(addr));
 | 
			
		||||
	addr.sin_family = AF_INET;
 | 
			
		||||
	addr.sin_port = htons(port);
 | 
			
		||||
	addr.sin_addr.s_addr = ip;
 | 
			
		||||
 | 
			
		||||
	if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&n, sizeof n) == -1)
 | 
			
		||||
		goto out_fd;
 | 
			
		||||
	if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (char *)&n, sizeof n) == -1)
 | 
			
		||||
		goto out_fd;
 | 
			
		||||
 | 
			
		||||
	strlcpy(interface.ifr_ifrn.ifrn_name, inf, IFNAMSIZ);
 | 
			
		||||
	if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE,
 | 
			
		||||
				(char *)&interface, sizeof interface) < 0)
 | 
			
		||||
		goto out_fd;
 | 
			
		||||
	
 | 
			
		||||
	if (bind(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr)) == -1)
 | 
			
		||||
		goto out_fd;
 | 
			
		||||
		
 | 
			
		||||
	return fd;
 | 
			
		||||
out_fd:
 | 
			
		||||
	close(fd);
 | 
			
		||||
out:
 | 
			
		||||
	return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int raw_socket(int ifindex)
 | 
			
		||||
{
 | 
			
		||||
	int fd;
 | 
			
		||||
	struct sockaddr_ll sock;
 | 
			
		||||
 | 
			
		||||
	debug(LOG_INFO, "Opening raw socket on ifindex %d\n", ifindex);
 | 
			
		||||
	if ((fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))) < 0) {
 | 
			
		||||
		debug(LOG_ERR, "socket call failed: %s\n", strerror(errno));
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	sock.sll_family = AF_PACKET;
 | 
			
		||||
	sock.sll_protocol = htons(ETH_P_IP);
 | 
			
		||||
	sock.sll_ifindex = ifindex;
 | 
			
		||||
	if (bind(fd, (struct sockaddr *) &sock, sizeof(sock)) < 0) {
 | 
			
		||||
		debug(LOG_ERR, "bind call failed: %s\n", strerror(errno));
 | 
			
		||||
		goto out_fd;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return fd;
 | 
			
		||||
out_fd:
 | 
			
		||||
	close(fd);
 | 
			
		||||
out:
 | 
			
		||||
	return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										9
									
								
								ndhc/socket.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								ndhc/socket.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
			
		||||
/* socket.h */
 | 
			
		||||
#ifndef _SOCKET_H
 | 
			
		||||
#define _SOCKET_H
 | 
			
		||||
 | 
			
		||||
int read_interface(char *interface, int *ifindex, uint32_t *addr, unsigned char *arp);
 | 
			
		||||
int listen_socket(unsigned int ip, int port, char *inf);
 | 
			
		||||
int raw_socket(int ifindex);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										46
									
								
								nstrl.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								nstrl.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,46 @@
 | 
			
		||||
/* nstrl.c - strlcpy/strlcat implementation
 | 
			
		||||
   (C) 2003 Nicholas J. Kain <njk@aerifal.cx>
 | 
			
		||||
 | 
			
		||||
   This library is free software; you can redistribute it and/or
 | 
			
		||||
   modify it under the terms of the GNU Lesser General Public
 | 
			
		||||
   License as published by the Free Software Foundation; either
 | 
			
		||||
   version 2.1 of the License, or (at your option) any later version.
 | 
			
		||||
 | 
			
		||||
   This library is distributed in the hope that it will be useful,
 | 
			
		||||
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
			
		||||
   Lesser General Public License for more details.
 | 
			
		||||
 | 
			
		||||
   You should have received a copy of the GNU Lesser General Public
 | 
			
		||||
   License along with this library; if not, write to the Free Software
 | 
			
		||||
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 | 
			
		||||
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
 | 
			
		||||
#ifndef HAVE_STRLCPY
 | 
			
		||||
 | 
			
		||||
size_t strlcpy (char *dest, char *src, size_t size)
 | 
			
		||||
{
 | 
			
		||||
    register char *d = dest, *s = src;
 | 
			
		||||
 | 
			
		||||
    for (; *s != '\0' && size > 0; size--, d++, s++)
 | 
			
		||||
	*d = *s;
 | 
			
		||||
 | 
			
		||||
    *d = '\0';
 | 
			
		||||
    return (d - dest) + (s - src);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t strlcat (char *dest, char *src, size_t size)
 | 
			
		||||
{
 | 
			
		||||
    register char *d = dest, *s = src;
 | 
			
		||||
 | 
			
		||||
    for (; size > 0 && *d != '\0'; size--, d++);
 | 
			
		||||
 | 
			
		||||
    for (; *s != '\0' && size > 0; size--, d++, s++)
 | 
			
		||||
	*d = *s;
 | 
			
		||||
 | 
			
		||||
    *d = '\0';
 | 
			
		||||
    return (d - dest) + (s - src);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										23
									
								
								nstrl.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								nstrl.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,23 @@
 | 
			
		||||
/* nstrl.h - header file for strlcpy/strlcat implementation
 | 
			
		||||
   (C) 2003 Nicholas J. Kain <njk@aerifal.cx>
 | 
			
		||||
 | 
			
		||||
   This library is free software; you can redistribute it and/or
 | 
			
		||||
   modify it under the terms of the GNU Lesser General Public
 | 
			
		||||
   License as published by the Free Software Foundation; either
 | 
			
		||||
   version 2.1 of the License, or (at your option) any later version.
 | 
			
		||||
 | 
			
		||||
   This library is distributed in the hope that it will be useful,
 | 
			
		||||
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
			
		||||
   Lesser General Public License for more details.
 | 
			
		||||
 | 
			
		||||
   You should have received a copy of the GNU Lesser General Public
 | 
			
		||||
   License along with this library; if not, write to the Free Software
 | 
			
		||||
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 | 
			
		||||
 | 
			
		||||
#ifndef NJK_HAVE_STRL_
 | 
			
		||||
#define NJK_HAVE_STRL_ 1
 | 
			
		||||
size_t strlcpy (char *dest, char *src, size_t size);
 | 
			
		||||
size_t strlcat (char *dest, char *src, size_t size);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										45
									
								
								pidfile.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								pidfile.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,45 @@
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
#include "defines.h"
 | 
			
		||||
#include "log.h"
 | 
			
		||||
 | 
			
		||||
void write_pid(char *file) {
 | 
			
		||||
    FILE *f;
 | 
			
		||||
    char buf[MAXLINE];
 | 
			
		||||
 | 
			
		||||
    if (!file)
 | 
			
		||||
	return;
 | 
			
		||||
 | 
			
		||||
    f = fopen(file, "w");
 | 
			
		||||
    if (f == NULL) {
 | 
			
		||||
	log_line("FATAL - failed to open pid file \"%s\"!\n", file);
 | 
			
		||||
	exit(EXIT_FAILURE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    snprintf(buf, sizeof buf, "%i", (unsigned int)getpid());
 | 
			
		||||
    fwrite(buf, sizeof (char), strlen(buf), f);
 | 
			
		||||
 | 
			
		||||
    if (fclose(f) != 0) {
 | 
			
		||||
	log_line("FATAL - failed to close pid file \"%s\"!\n", file);
 | 
			
		||||
	exit(EXIT_FAILURE);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Return 0 on success, -1 on failure. */
 | 
			
		||||
int file_exists(char *file, char *mode) {
 | 
			
		||||
    FILE *f;
 | 
			
		||||
 | 
			
		||||
    if (file == NULL || mode == NULL)
 | 
			
		||||
	return -1;
 | 
			
		||||
 | 
			
		||||
    f = fopen(file, mode);
 | 
			
		||||
    if (f == NULL)
 | 
			
		||||
	return -1;
 | 
			
		||||
    fclose(f);
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										6
									
								
								pidfile.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								pidfile.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
			
		||||
#ifndef NJK_PIDFILE_H_
 | 
			
		||||
#define NJK_PIDFILE_H_ 1
 | 
			
		||||
void write_pid(char *file);
 | 
			
		||||
int file_exists(char *file, char *mode);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										46
									
								
								signals.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								signals.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,46 @@
 | 
			
		||||
/* signals.c - abstracts signal handling
 | 
			
		||||
   (C) 2004 Nicholas J. Kain <njk@aerifal.cx>
 | 
			
		||||
 | 
			
		||||
   This library is free software; you can redistribute it and/or
 | 
			
		||||
   modify it under the terms of the GNU Lesser General Public
 | 
			
		||||
   License as published by the Free Software Foundation; either
 | 
			
		||||
   version 2.1 of the License, or (at your option) any later version.
 | 
			
		||||
 | 
			
		||||
   This library is distributed in the hope that it will be useful,
 | 
			
		||||
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
			
		||||
   Lesser General Public License for more details.
 | 
			
		||||
 | 
			
		||||
   You should have received a copy of the GNU Lesser General Public
 | 
			
		||||
   License along with this library; if not, write to the Free Software
 | 
			
		||||
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 | 
			
		||||
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <signal.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include "log.h"
 | 
			
		||||
 | 
			
		||||
void hook_signal(int signum, void (*fn)(int), int flags) {
 | 
			
		||||
    struct sigaction new_action;
 | 
			
		||||
 | 
			
		||||
    new_action.sa_handler = fn;
 | 
			
		||||
    sigemptyset(&new_action.sa_mask);
 | 
			
		||||
    new_action.sa_flags = flags;
 | 
			
		||||
 | 
			
		||||
    if (sigaction(signum, &new_action, NULL)) {
 | 
			
		||||
	log_line("FATAL - failed to hook signal %i\n", signum);
 | 
			
		||||
	exit(EXIT_FAILURE);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void disable_signal(int signum) {
 | 
			
		||||
    struct sigaction new_action;
 | 
			
		||||
 | 
			
		||||
    new_action.sa_handler = SIG_IGN;
 | 
			
		||||
    sigemptyset(&new_action.sa_mask);
 | 
			
		||||
 | 
			
		||||
    if (sigaction(signum, &new_action, NULL)) {
 | 
			
		||||
	log_line("FATAL - failed to ignore signal %i\n", signum);
 | 
			
		||||
	exit(EXIT_FAILURE);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										6
									
								
								signals.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								signals.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
			
		||||
#ifndef NJK_SIGNALS_H_
 | 
			
		||||
#define NJK_SIGNALS_H_ 1
 | 
			
		||||
void hook_signal(int signum, void (*fn)(int), int flags);
 | 
			
		||||
void disable_signal(int signum);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										71
									
								
								strlist.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								strlist.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,71 @@
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <malloc.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
#include "nstrl.h"
 | 
			
		||||
#include "strlist.h"
 | 
			
		||||
 | 
			
		||||
void add_to_strlist(char *name, strlist_t **list)
 | 
			
		||||
{
 | 
			
		||||
    strlist_t *item, *t;
 | 
			
		||||
    char *s;
 | 
			
		||||
    unsigned int len;
 | 
			
		||||
 | 
			
		||||
    if (!list || !name)
 | 
			
		||||
	return;
 | 
			
		||||
 | 
			
		||||
    len = strlen(name);
 | 
			
		||||
    if (!len)
 | 
			
		||||
	return;
 | 
			
		||||
    s = malloc(len + 1);
 | 
			
		||||
    if (!s)
 | 
			
		||||
	return;
 | 
			
		||||
    strlcpy(s, name, len + 1);
 | 
			
		||||
 | 
			
		||||
    item = malloc(sizeof (strlist_t));
 | 
			
		||||
    if (!item)
 | 
			
		||||
	goto out0;
 | 
			
		||||
    item->str = s;
 | 
			
		||||
    item->next = NULL;
 | 
			
		||||
 | 
			
		||||
    if (!*list) {
 | 
			
		||||
	*list = item;
 | 
			
		||||
	return;
 | 
			
		||||
    }
 | 
			
		||||
    for (t = *list; t->next; t = t->next)
 | 
			
		||||
	if (!t->next) {
 | 
			
		||||
	    t->next = item;
 | 
			
		||||
	    return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    free(item); /* should be impossible, but hey */
 | 
			
		||||
out0:
 | 
			
		||||
    free(s);
 | 
			
		||||
    return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void free_strlist(strlist_t *head)
 | 
			
		||||
{
 | 
			
		||||
    strlist_t *p = head, *q = NULL;
 | 
			
		||||
 | 
			
		||||
    while (p != NULL) {
 | 
			
		||||
	free(p->str);
 | 
			
		||||
	q = p;
 | 
			
		||||
	p = q->next;
 | 
			
		||||
	free(q);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void free_stritem(strlist_t **p)
 | 
			
		||||
{
 | 
			
		||||
    strlist_t *q;
 | 
			
		||||
 | 
			
		||||
    if (!p || !*p)
 | 
			
		||||
	return;
 | 
			
		||||
 | 
			
		||||
    q = (*p)->next;
 | 
			
		||||
    free((*p)->str);
 | 
			
		||||
    free(*p);
 | 
			
		||||
    *p = q;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user