/*
 * nis_check_domain
 *
 * This plugin is distributed under the GPL
 */


#include <includes.h>
#ifdef HAVE_RPC_RPC_H
#include <rpc/rpc.h>
#include <rpc/pmap_clnt.h>
#include <rpcsvc/yp_prot.h>
#endif

#define NAME "NIS check domain"
#define DESC "\
This plugin attempts to guess the remote NIS domain name.\n\
To do so, it retrieves the index of the remote NIS maps of\n\
the target.\n\
If it is successful, it means that you have incorrectly chosen\n\
your NIS domain name, and this is a problem since it allows remote\n\
attackers to get your NIS maps easily -- especially your passwd\n\
map.\n\n\
Risk factor : High"
#define SUMMARY "attempts to get the remote NIS maps using the internet domain name"
#define COPYRIGHT "code from Dan Farmer (zen@death.corp.sun.com) and Casper Dik (casper@fwi.uva.nl). "

PlugExport int plugin_init(struct arglist * desc);
PlugExport int plugin_init(struct arglist * desc)
{
  plug_set_name(desc, NAME);
  plug_set_description(desc, DESC);
  plug_set_summary(desc, SUMMARY);
  plug_set_copyright(desc, COPYRIGHT);
  plug_set_category(desc, ACT_ATTACK);
  plug_set_family(desc, "NIS");
  plug_set_timeout(desc, 30);
  return(0);
}

char * guess_domain_name(char * name);
struct ypmaplist * get_yp_maplist(char *, char *);


PlugExport int plugin_run(struct arglist * env);
PlugExport int plugin_run(struct arglist * env)
{
 char * hostname = (char *)plug_get_hostname(env);
 int success = 0;
 struct ypmaplist * list = NULL;
 int port;
  if(plug_get_key(env, "rpc/portmapper")&&
     (strlen(plug_get_key(env, "rpc/portmapper"))<3))return(0);
 /* 
  * If our host name is an IP address, don't try
  * to guess its domain name...
  */
 if(inet_addr(hostname)!=0xffffffff)return(0);
 
 if(callrpc(hostname, YPPROG, YPVERS, YPPROC_NULL, xdr_void, 0,xdr_void, 0)!=
 	RPC_SUCCESS){
         	
                return(0);
                }              
                
 hostname = strchr(hostname, '.');
 if(hostname)hostname++;
 else return(0); /* a single hostname won't help us... */


 while(hostname && (!success))
 {
  list = get_yp_maplist((char *)plug_get_hostname(env), hostname);
  if(list)success++;
  else hostname = guess_domain_name(hostname);
 }
 if(success)
 { 
  char * report = emalloc(512);
  int size = 512;
  if(((int)plug_get_key(env, "nis/domain"))==-1)
   plug_set_key(env,"nis/domain", ARG_STRING, hostname);
  sprintf(report, "\
The remote host has a poor chosen domain name (%s)\n\
If an attacker guesses it, he will be able to get your\n\
NIS maps, such as your passwd map\n\
Solution : change your NIS domain and filter incoming\n\
connections to port 111", hostname);
 port = getrpcport(plug_get_hostname(env), YPPROG, YPVERS, IPPROTO_UDP);
 if(!port)port = -1;
 post_hole_udp(env, port,report);
 efree(&report); 
 }
 return(0);
}


struct ypmaplist * get_yp_maplist(server, domain)
char *server, *domain;
{
    bool_t yesno = FALSE;
    extern void timeout();
    struct ypmaplist *mpl;
    enum clnt_stat errcode;
    struct ypresp_maplist maplist;

   errcode = callrpc(server, YPPROG, YPVERS, YPPROC_DOMAIN,
                xdr_wrapstring, (caddr_t) &domain, xdr_bool,
                (caddr_t) &yesno);
    if(errcode != RPC_SUCCESS)return(NULL);
    if (yesno == FALSE)return(NULL);
    maplist.list = (struct ypmaplist *) NULL;
    errcode = callrpc(server, YPPROG, YPVERS, YPPROC_MAPLIST,
                xdr_wrapstring, (caddr_t) &domain,
                xdr_ypresp_maplist, &maplist);
    if(errcode != RPC_SUCCESS)return(NULL);
    if (maplist.status != YP_TRUE)return(NULL);
    return(maplist.list);
}




char * guess_domain_name(char * hname)
{
 char * name = strrchr(hname, '.');
 if(name)name[0] = 0;
 else return(NULL);
 return(hname);
}
