History log of /freebsd-9.3-release/usr.sbin/ypserv/yp_server.c
Revision Date Author Comments
(<<< Hide modified files)
(Show modified files >>>)
# 267654 19-Jun-2014 gjb

Copy stable/9 to releng/9.3 as part of the 9.3-RELEASE cycle.

Approved by: re (implicit)
Sponsored by: The FreeBSD Foundation

# 225736 22-Sep-2011 kensmith

Copy head to stable/9 as part of 9.0-RELEASE release cycle.

Approved by: re (implicit)


# 200100 04-Dec-2009 kuriyama

- In ypproc_all_2_svc(), yp_fork() is called only when !debug case.
So _exit() in the bottom of this function should be called with the
same case.


# 159461 09-Jun-2006 maxim

o Re-arrange parentheses and fix a conition logic for !do_dns case.

PR: bin/98625
MFC after: 1 month


# 145793 02-May-2005 ume

fix typo in previos commit.


# 145792 02-May-2005 ume

teach IPv6 to async DNS resolver in ypserv:
- query AAAA RR on ipnodes.byname query.
- query .ip6.arpa. on ipnodes.byaddr query.


# 114601 03-May-2003 obrien

Use __FBSDID over rcsid[]. Protect copyright[] where needed.


# 95658 28-Apr-2002 des

Spell void * as void * rather than caddr_t. This is complicated by the
fact that caddr_t is often misspelled as char *.

Sponsored by: DARPA, NAI Labs


# 90298 06-Feb-2002 des

ANSIfy and remove some dead code.

Sponsored by: DARPA, NAI Labs


# 90297 06-Feb-2002 des

Apply the following mechanical transformations in preparation for
ansification and constification:

s{\s+__P\((\(.*?\))\)}{$1}g;
s{\(\s+}{\(}g;
s{\s+\)}{\)}g;
s{\s+,}{,}g;
s{(\s+)(for|if|switch|while)\(}{$1$2 \(}g;
s{return ([^\(].*?);}{return ($1);}g;
s{([\w\)])([!=+/\*-]?=)([\w\(+-])}{$1 $2 $3}g;
s{\s+$}{\n};g

Also add $FreeBSD$ where needed.

MFC after: 1 week


# 80184 23-Jul-2001 kris

sprintf -> snprintf


# 79452 09-Jul-2001 brian

Fix the type of the NULL arg to execl()

Idea from: Theo de Raadt <deraadt@openbsd.org>


# 50479 27-Aug-1999 peter

$Id$ -> $FreeBSD$


# 46207 30-Apr-1999 wpaul

Close PR #10971: flush the database cache after forking in ypproc_all_2_svc()
so that parent and child don't share DB handles.


# 46205 30-Apr-1999 wpaul

Close PR #10970: exit at the end of ypproc_all_2_svc() instead of returning.
This really fixes the condition where a child creates children of its own.
I'm leaving the previous sanity tests in though, since they shouldn't hurt,
and will give an indication if this ever happens again.


# 46186 29-Apr-1999 wpaul

Add some extra checks to make sure that a child ypserv process doesn't
try to fork() a child of its own, which could result in several children
ypservs running at once. I'm still not sure exactly what leads to this
condition, but these fixes should stop it from causing trouble. A new
function, yp_fork() checks to see if the current process is already a
child of the parent ypserv, and returns failure (and logs an error message)
rather than spawning another child.


# 43847 10-Feb-1999 wpaul

Add some tweaks to hopefully fix a problem I've started to notice recently.
Under certain conditions (possibly associated with heavy load), ypserv will
fork() child processes that don't exit like they're supposed to. I think
this is because of some suspect logic in the ypproc_all procedure. I updated
it to use what I hope is a more bulletproof approach.

Also tweaked yp_svc_run() a little so that the 'are we a child?' test happens
at every pass through the for(;;) loop, not just immediately after returning
from svc_getreqset2().


# 33250 11-Feb-1998 wpaul

Fix a bug in the database handle caching. This has to do with the way the
underlying database code works. When dealing with first/next queries, you
have the notion of a database 'cursor,' which is essentially a file pointer
for the database. To select the first entry, you do a fetch with the
R_FIRST flag set, then you can use the R_NEXT flag to enumerate the other
entries in the database. Unfortunately, doing a direct fetch with no flag
does _not_ set the 'cursor,' so you can't do a direct fetch and then
enumerate the table from there.

The bug is that cached handles generated as the result of a YPPROC_MATCH
were being treated as though they were the same as handles generated by
a YPPROC_FIRST, which is not the case. The manifestation is that if you
do a 'ypmatch first-key-in-map map' followed by a yp_first()/yp_next()
pair, the yp_first() and yp_next() both return the first key in the
table, which makes the entry appear to be duplicated.

A couple smaller things since I'm here:

- yp_main.c and yp_error.c both have a global 'int debug' in them.
For some reason, our cc/ld doesn't flag this as a multiply defined
symbol even though it should. Removed the declaration from yp_main.c;
we want the one in yp_error.c.

- The Makefile wasn't installing ypinit in the right place.


# 30827 29-Oct-1997 charnier

Typos in man page. Cosmetics in error strings.


# 28042 10-Aug-1997 wpaul

Don't initialize structures from other variables; gcc -ansi -pedantic
doesn't allow it. Use proper constants instead.


# 27589 21-Jul-1997 wpaul

Fix a very stupid heap corruption bug: in ypproc_match_2_svc(), when
we decide to do a DNS lookup, we NUL terminate the key string provided
by the client before passing it into the DNS lookup module. This is
actually wrong. Assume the key is 'foo.com'. In this case, key.keydat_val
will be "foo.com" and key.keydat_len will be 7 (seven characters; the
string is not NUL-terminated so it is not 8 as you might expect).
The string "foo.com" is actually allocated by the XDR routines when the
RPC request is decoded; exactly 7 bytes are allocated. By adding a NUL,
the string becomes "foo.com\0", but the '\0' goes into an 8th byte which
was never allocated for this string and which could be anywhere. The result
is that while the initial request may succeed, we could trash other
dynamically allocated structures (like, oh, I dunno, the circular map
cache queue?) and SEGV later. This is in fact what happens.

The fix is to copy the string into a larger local buffer and NUL-terminate
that buffer instead.

Crash first reported by: Ricky Chan <ricky@come.net.uk>
Bug finally located with: Electric Fence 2.0.5


# 25254 28-Apr-1997 wpaul

Back out one of my paranoia tests from the last commit here; yp_access()
already deals with it appropriately. (You know you've been working too
hard when you forget how your own code works.)


# 24780 10-Apr-1997 wpaul

Add a sanity test to ypproc_xfr_2_svc(): check that the map and domain
in the transfer request actually exist. Technically ypxfr can do this too,
but why waste the cycles getting ypxfr off the ground for a transfer we
already know is going to fail.

Also apply stricter access control rules; ypproc_xfr_2_svc() is in a
different class than the normal map access procedures procedures.


# 22997 22-Feb-1997 peter

Revert $FreeBSD$ to $Id$


# 22321 06-Feb-1997 wpaul

Close PR# 2645: add curly braces where my fevered brain in collusion
with my frantic fingers forgot to put them.


# 21673 14-Jan-1997 jkh

Make the long-awaited change from $Id$ to $FreeBSD$

This will make a number of things easier in the future, as well as (finally!)
avoiding the Id-smashing problem which has plagued developers for so long.

Boy, I'm glad we're not using sup anymore. This update would have been
insane otherwise.


# 21389 07-Jan-1997 wpaul

yp_server.c:
- Fail YPPROC_ALL requests when we hit the child process limit. This
is a little harsh, but it helps prevent the parent from blocking
and causing other requests to time out.

yp_dnslookup.c:
- Check for duplicate RPC transaction IDs that indicate duplicate
requests sent due to RPC retransmissions. We don't want to send
a second DNS request for the same data while an existing request
is in progress.

- Fix small formatting bogon in snprintf() in yp_async_lookup_addr().


# 20907 25-Dec-1996 wpaul

More async resolver refinements:

- yp_main.c: Always add the resolver socket to the set of fds
monitored by select(). It can happen that pending == 0 but we
still have some data in the socket buffer from an old query.
This way, the data will be flushed in a timely manner.

- yp_extern.h: remove proto for yp_dns_pending() since we don't need
it anynmore.

- yp_server.c: call yp_async_lookup_name()/yp_async_lookup_addr()
functions with the svc_req pointer as an arg instead of the xprt.
(The svc_req struct includes a pointer to the transport handle,
and it also has the service version number which the async DNS
code will need. (see below))

- yp_dnslookup.c:

o Nuke yp_dns_pending() since we don't need it anymore.
o In yp_run_dnsq(), swallow up and ignore replies if no requests
are pending or the ID doesn't match any of the IDs in the queue.
o In yp_send_dns_reply(), we assume that we will always be
replying to an NIS v2 client. While this will probably always
be the case, we do support the v1 'match' procedure, and it
has a different result struct than v2. For completeness,
support replying to both NIS v1 and v2 clients.
o Update the queue entry structure to include a member to
keep track of the NIS version number.
o Have yp_async_lookup_name/addr() extract the version number
from the svc_req structure and save it with the queue entry
for yp_send_dns_reply() to inspect later.
o Add some comments.


# 20818 22-Dec-1996 wpaul

Big round o changes:

- yp_dblookup.c: Create non-DB specific database access functions.
Using these allows access to the underlying database functions without
needing explicit knowledge of Berkeley DB. (These are used only
when DB_CACHE is #defined. Other programs that use the non-caching
functions (yp_mkdb, ypxfr, yppush, rpc.yppasswdd) shouldn't notice
the difference.)

- yp_dnslookup: Implement async DNS lookups. We send our own DNS
requests using UDP and put the request in a queue. When the response
arrives, we use the ID in the header to find the corresponsing queue
entry and then send the response to the client. We can go about our
business and handle other YP requests in the meantime. This way, we
can deal with time consuming DNS requests without blocking and without
forking.

- yp_server.c: Convert to using new non-DB-specific database access
functions. This simplifies the code a bit and removes the need for
this module to know anything about Berkeley DB. Also convert the
ypproc_match_2_svc() function to use the async DNS lookup routines.

- yp_main.c: tweak yp_svc_run() to add the resolver socket to the
set of descriptors monitored in the select() loop. Also add a
timeout to select(); we may get stale DNS requests stuck in the
queue which we want to invalidate after a while. If the timeout
hits, we decrement the ttl on all pending DNS requests and nuke
those requests that aren't handled before ttl hits zero.

- yp_extern.h: Add prototypes for new stuff.

- yp_svc_udp.c (new file): The async resolver code needs to be able
to rummage around inside the RPC UDP transport handle in order to
work correcty. There's basically one transport handle, and each time
a request comes in, the transaction ID in the handle is changed.
This means that if we queue a DNS request, then we handle some other
unrelated requests, we will be unable to send the DNS response because
the transaction ID and remote address of the client that made the DNS
request will have been lost. What we need to do is save the client
address and transaction ID in the queue entry for the DNS request,
then put the transaction ID and address back in the transport handle
when we're ready to reply. (And then we have to undo the change so
as not to confuse any other part of the server.) The trouble is that
the transaction ID is hidden in an opaque part of the transport handle,
and only the code in the svc_udp module in the RPC library knows how
to handle it. This file contains a couple of functions that let us
read and set the transaction ID in spite of this. This is really a
dirty trick and I should be taken out and shot for even thinking about
it, but there's no other way to get this stuff to work.

- Makefile: add yp_svc_udp.c to SRCS.


# 20100 03-Dec-1996 wpaul

Back out the non-forking YPPROC_ALL stuff. Whatever drugs I was doing
when I came up with this idea weren't strong enough to help me see it
through. If this was a self-contained application and I had complete
control over what data got sent through what socket and when, I might
be able to get everything to work right without blocking, but instead
I have RPC/XDR in between me and the socket layer, and they have their
own ideas about what to do.

Maybe one day I'll go totally mad and figure out the right way to do
this; in the meantime this mess goes on the back burner.


# 20053 30-Nov-1996 wpaul

This commit changes the YPPROC_ALL procecdure so that it handles requests
_without_ using fork().

The problem with YPPROC_ALL is that it transmits an entire map through
a TCP pipe as the result of a single RPC call. First of all, this requires
certain hackery in the XDR filter. Second, if the map being sent is
large, the server can end up spending lots of time in the XDR filter
sending to just the one client, while requests for other clients will
go unanswered.

My original solution for this was to fork() the request into a child
process which terminates after the map has been transmitted (or the
transfer is interrupted due to an error). This leaves the parent free
to handle other requests. But this solution is kind of lame: fork()
is relatively expensive, and we have to keep a cap on the number of
child processes to keep from swamping the system.

What we do now is grab control of the service transport handle and XDR
handle from the RPC library and send the records one at a time ourselves
instead of letting the RPC library do it. We send a record, then go
back to the svc_run() loop and select() on the socket. If select() says
we can still write data, we send the next record. Then we call
svc_getreqset() and handle other RPCs and loop around again. This way,
we can handle other RPCs between records.

We manage multiple YPPROC_ALL requests using a circular queue. When a
request is done, we dequeue it and destroy the handle. We also tag
each request with a ttl which is decremented whevever we run the queue
and a handle isn't serviced. This lets us nuke requests that have sat
idle for too long (if we didn't do this, we might run out of socket
descriptors.)

Now all I have to do is come up with an async resolver, and ypserv
won't need to fork() at all. :)

Note: these changes should not go into 2.2 unless they get a very
throrough shakedown before the final cutoff date.


# 19161 24-Oct-1996 wpaul

Add support for handling the YP_SECURE and YP_INTERDOMAIN keys from
any maps that may have them. If the YP_SECURE key is present, ypserv
will only allow access to the map from clients on reserved ports.
If the YP_INTERDOMAIN key is present, the server will do DNS lookups
for hostnames that it can't find in hosts.byname or hosts.byaddr.
This is the same as the -d flag (which is retained for backwards
compatibility) but it can be set on a per-map/per-domain basis.

Also modified /var/yp/Makefile to add YP_INTERDOMAIN to the hosts.*
maps and YP_SECURE to master.passwd.* maps by default.


# 19131 23-Oct-1996 wpaul

In ypxfr_callback(), the failure to create an RPC CLIENT * handle for
the callback is a fatal error for this function; return immediatlely if
this happens. Also make the "failed to establish callback handle" error
mesaage print the IP address of the target callback host.


# 16044 31-May-1996 wpaul

Small touch-ups -- no functional changes.

Fix some comments to reflect reality (in some cases I made changes
to code but not to the comments).

Change some instances of 'inline' to '__inline' to pacify
gcc -ansi -pedantic.

Use rcsid strings more consistently.

Make 'oldaddr' static in yp_access().

Use strcpy()/strcat() in yp_open_db_cache() instead of snprintf().
(Seems to be a little faster this way.)


# 15426 28-Apr-1996 wpaul

Performance enhancements (I hope) and new stuff:

yp_dblookup.c:

- Implement database handle caching. What this means is that instead
of opening and closing map databases for each request, we open a
database and save the handle (and, if requested, the key index)
in an array. This saves a bit of overhead on things like repeated
YPPROC_NEXT calls, such as you'd get from getpwent(). Normally,
each YPPROC_NEXT would require open()ing the database, seeking
to the location supplied by the caller (which is time consuming with
hash databases as the R_CURSOR flag doesn't work), reading the
data, close()ing the database and then shipping the data off to
the caller. The system call overhead is prohibitive, especially
with very large maps. By caching the handle to an open database,
we elimitate at least the open()/close() system calls, as well
as the associated DB setup and tear-down operations, for a large
percentage of the time. This improves performance substantially at
the cost of consuming a little more memory than before.

Note that all the caching support is surrounded by #ifdef DB_CACHE
so that this same source module can still be used by other programs
that don't need it.

- Make yp_open_db() call yp_validdomain(). Doing it here saves cycles
when caching is enabled since a hit on the map cache list by
definition means that the domain being referenced is valid.

- Also make yp_open_db() check for exhaustion of file descriptors,
just in case.

yp_server.c:

- Reorganize things a little to take advantage of the database
handle caching. Add a call to yp_flush_all() in ypproc_clear_2_svc().

- Remove calls to yp_validdomain() from some of the service procedures.
yp_validdomain() is called inside yp_open_db() now, so procedures that
call into the database package don't need to use yp_validdomain()
themselves.

- Fix a bogosity in ypproc_maplist_2_svc(): don't summarily initiallize
the result.maps pointer to NULL. This causes yp_maplist_free()
to fail and leaks memory.

- Make ypproc_master_2_svc() copy the string it gets from the database
package into a private static buffer before trying to NUL terminate it.
This is necessary with the DB handle caching: stuffing a NUL into the
data returned by DB package will goof it up internally.

yp_main.c:

- Stuff for DB handle caching: call yp_init_dbs() to clear the
handle array and add call to yp_flush_all() to the SIGHUP
signal handler.

Makefile.yp:

- Reorganize to deal with database caching. yp_mkdb(8) can now be used
to send a YPPROC_CLEAR signal to ypserv(8). Call it after each map
is created to refresh ypserv's cache.

- Add support for mail.alias map.
Contributed by Mike Murphy (mrm@sceard.com).

- Make default location for the netgroups source file be /var/yp/netgroup
instead of /etc/netgroup.

mkaliases:

- New file: script to generate mail.alias map.
Contributed by Mike Murphy (mrm@sceard.com).

Makefile:

- Install Makefile.yp as /var/yp/Makefile.dist and link it to
/var/yp/Makefile only if /var/yp/Makefile doesn't already exist.
Suggested by Peter Wemm.

- Install new mkaliases script in /usr/libexec along with mknetid.

- Use somewhat saner approach to generating rpcgen-dependent files
as suggested by Garrett Wollman.


# 14304 01-Mar-1996 wpaul

Initialize a few more 'result' members in a few places (both in the v2
and v2 service procedures). Also fixed the formatting in a few places
to keep everything under 80 columns.


# 14303 29-Feb-1996 wpaul

In ypproc_master_2_svc(), don't leave result.peer uninitialized when
returning an error.


# 14262 26-Feb-1996 wpaul

Add support for NIS v1 client procedures. The following procedures
are currently implemented:

YPOLDPROC_NULL
YPOLDPROC_DOMAIN
YPOLDPROC_DOMAIN_NONACK
YPOLDPROC_FIRST
YPOLDPROC_NEXT
YPOLDPROC_MATCH
YPOLDPROC_POLL

These are all implemented as wrappers around their v2 counterparts.

The YPOLDPROC_PUSH, PULL and GET procedures are not implemented since
a) I couldn't figure out exactly what to have them do, and b) I
suspect they're used for doing map transfers between master and
slave servers, which we already do using the v2 protocol anyway.
This means we can server NIS v1 clients but can't be a master or
slave with NIS v1-only servers. I think I'll get over it. :)

The -k (sunos_4_kludge) flag and associated code has been removed
since it is no longer needed.

Also tweaked yp_access() to handle both sets of procedures and
updated the man page.


# 14240 24-Feb-1996 wpaul

Add real securenets support. By default, ypserv now uses /var/yp/securenets
in the same was as the SunOS ypserv (same format, described in ypserv man
page). If the user wants tcpwrapper style access control, they can
recompile ypserv to use that instead. This way we get securenets without
having to ship libwrap.a and tcpd.h with core FreeBSD distribution.

If /var/yp/securenets doesn't exist, ypserv allows all connections.


# 13800 31-Jan-1996 wpaul

Found an instance of yp_error() in yp_maplist_create() that had two %s
tokens but only one argument; fixed by putting in missing argument.


# 13375 10-Jan-1996 wpaul

More changes brought about by testing of yppush (which is almost finished):

In yp_server.c:

- Modify ypproc_xfr_2_svc() so that it sends both a return status and
a yppush callback (if necessary: normally ypxfr is supposed to send the
callback once it's done transfering a map, but if we can't get ypxfr
off the ground for some reason, we have to send it here instead) and
do it in the right order: have to send the reply to the ypproc_xfr
request first, then send callback. This requires us to cheat a bit:
you're supposed to just return() and let the RPC dispatcher send
the reply for you, but we wouldn't be able to send the callback message
if we did that, so we have to call svc_sendreply() ourselves, then
send the callback, and then return NULL so that the RPC dispatcher
won't call svc_sendreply() itself.

- Also modify ypproc_xfr_2_svc() so that it doesn't invoke ypxfr with
the -f flag: this overrides the order number checks, which prevents
us from ever refusing maps that aren't newer than then ones we already
have.

In yp_access.c:

- Fix a typo in the TCP_WRAPPER support code (which is #ifdef'ed out
by default): a close paren somehow vanished into the ether.


# 12997 23-Dec-1995 wpaul

A few small tweaks related to ypxfr:

- Add a ypxfr_callback() function that we can use to signal failure to
yppush(8) in the event that we can't fork()/exec() ypxfr(8). yppush
only checks the return status from YPPROC_XFR enough to determine
that the RPC succeded: it relies on its callback service to figure
out whether or not the transfer actually worked.

- Give yp_dblookup.c its own debug variable (ypdb_debug) so that DB
access debugging messages can be turned on or off independent of the
program's global debug messages.

- Have the Makefile rpcgen the ypushresp_xfr_1() client stub for us and
nuke the unneeded rule for yp_xdr.c that I left in by mistake (the XDR
filters live in libc now).


# 12892 16-Dec-1995 wpaul

This commit was generated by cvs2svn to compensate for changes in r12891,
which included commits to RCS files with non-trunk default branches.


# 12891 16-Dec-1995 wpaul

Import the new, non-GPL ypserv, written by yours truly. Functionally
equivalent to the old ypserv, except that it doesn't support the
-p [port] option to force the server to use a particular port.

The server stubs and yp.h header file are auto-generated from the yp.x
protocol definition file. The auto-generated XDR routines in libc/yp
are also used. The database access code has been broken out into a
seperate module so that other NIS utilities (ypxfr in particular)
can use it.

Note that the old mknetid script is being temporarily moved here; it
will be replaced by an mknetid program which will eventually have
a home under /usr/src/libexec. (The existing script is actually
somewhat broken -- it doesn't handle hosts -- but this isn't a big
deal at this point since the netid.byname map is really only useful
fopr Secure RPC, which we don't have yet.)