Wednesday, October 16, 2013

Custom NIS maps

Interestingly, what makes NIS so dumb and insecure, is also makes it very flexible and simple. In particular, it's a piece of cake to create any custom NIS map to be distributed by the NIS service infrastructure. NIS maps are rather, if not completely, opaque to both NIS servers (ypserv) and NIS clients (ypbind), except for keys and values, that define the concept of map.

The extremely easy part is to device a custom map.
For instance, imagine a sort of phonebook map, such as:

# cat /var/nis/general/phonebook
#
# This is the Phonebook map of business.corp
# It contains all the internal public phones.
#

# A comment line both preceded and followed by blank lines.

user1 (99)98881-8881                # No extensions.
user2 (99)98882-8882 (200,201)
user3 (99)98883-8883 (300,301,302)

...

Beyond the per-line key & value entries (keys were highlighted on the previous example), the map's source format is pretty relaxed as long as the associated make target commands fully stripe-out all the extra stuff in the map's source, such as the comments and blank lines, validating the input to makedbm.

Now, for the easy part, on the NIS master, edit the /var/yp/Makefile  changing it as follows (for readability I won't highlight every line under the phonebook.time make target):

# cat /var/yp/Makefile
...

all: passwd ageing group netid \
    project netgroup aliases publickey \
    hosts ipnodes ethers networks netmasks \

    rpc services protocols \
    auto.master auto.home \
    auth.attr exec.attr prof.attr user.attr \

    phonebook

...

phonebook.time: $(DIR)/phonebook
    -@if [ -f $(DIR)/phonebook ]; then                    \

        #                                                ;\
        # Join continued lines.                          ;\
        (                                                 \

        while read L                                     ;\
            do echo "$$L"                                ;\
        done                                              \
        < $(DIR)/phonebook                                \
        $(CHKPIPE)) |                                     \
        #                                                ;\
        # Normalize the input to makedbm.                ;\
        # Stripe-out comments, then delete blank lines ;\
        (sed -e "[`echo '\t'` ]*s/#.*$$//" -e "/^ *$$/d"  \
        $(CHKPIPE)) |                                     \
        #                                                ;\
        # Rebuild the map for the updates.               ;\
        $(MAKEDBM) - $(YPDBDIR)/$(DOM)/phonebook         ;\

        #                                                ;\
        # Finish housekeeping.                           ;\
        touch phonebook.time                             ;\
        echo "updated phonebook"                         ;\

        #                                                ;\
        # Push the updated map to slaves?                ;\
        if [ ! $(NOPUSH) ]; then                          \
            $(YPPUSH) phonebook                          ;\
            echo "pushed phonebook"                      ;\
        fi                                                \

    else                                                  \
        echo "couldn't find $(DIR)/phonebook"            ;\
    fi

 
...

phonebook: phonebook.time

Despite having no intent on mastering make, its enlightening to know the following tricks that are present on the previous excerpt:

  • Every command under a make target must be indented with a TAB.
     
  •  An @ character as the first (with exceptions such as when following a -) non-TAB character, prevents printing the command line being executed.
      
  • The - character as the first non-TAB character, prevents a non-zero return-code from a command line from aborting make.

If all is correct, then it lasts building and testing:

# cd /var/yp
# make
updated phonebook
pushed phonebook

# ypcat -k phonebook | cat -etv
...
user3 (99)98883-8883 (300,301,302)$
user2 (99)98882-8882 (200,201)$
user1 (99)98881-8881$