#include "../_pwdb_internal.h"
/* _pwdb_dup_string and _pwdb_delete_string */
#include "../pwdb/pwdb_public.h" 

#define SHADOWTYPE_SUN  1
#define SHADOWTYPE_DEC  2

static int nis_bound;
static char *nis_domain;
static char shadow_pwdbuf[BUFSIZ];

struct __pwdb_passwd  *__pwdb_decnis_check_password_adjunct(const char *tname, 
	     struct __pwdb_passwd *nispwd);



/**********************************************************
 * These are defines for NIS update code ... 
 **********************************************************/
#define YPPASSWDPROG ((u_long)100009)
#define YPPASSWDVERS ((u_long)1)
#define YPPASSWDPROC_UPDATE ((u_long)1)
/* 
 * The updated password information, plus the old password.
 */
struct __pwdb_yppasswd {
        char *oldpass;
        struct __pwdb_passwd newpw;
};

/*
 * bind_nis - bind to NIS server
 */
static int __pwdb_decnis_bind_nis (void)
{
       nis_bound = 0;
       nis_domain = NULL;
   
       if (yp_get_default_domain (&nis_domain))
             return -1;
       nis_bound = 1;
       return 0;
}

/*
 * getpwuid - locate the password entry for a given UID
 *
 * getpwuid() locates the first password file entry for the given UID.
 */

struct __pwdb_passwd * __pwdb_decnis_getpwuid (uid_t uid)
{
  struct __pwdb_passwd *apwd, *bpwd;
  
  /* we first use the plain NIS routines to get the record + create
   * the passwd structure */
  apwd = __pwdbNIS_getpwuid(uid);

  if (apwd == NULL) {
      /* failed to find record in passwd.byname */
      return NULL;
  }
   
   /* now we check the adjunct password entries */
   bpwd = __pwdb_decnis_check_password_adjunct(apwd->pw_name,apwd);
   
   if (bpwd == NULL) {
          return apwd;
   } else {
          return bpwd;
   }
   
}

/*
 * getpwnam - locate the password entry for a given name
 *
 * getpwnam() locates the first password file entry for the given name.
 * If there is a valid DBM file, the DBM files are queried first for
 * the entry.  Otherwise, a linear search is begun of the password file
 * searching for an entry which matches the provided name.
 */

struct __pwdb_passwd * __pwdb_decnis_getpwnam (const char * name)
{
   struct __pwdb_passwd *apwd, *bpwd;
   
   apwd = __pwdbNIS_getpwnam(name);
 
   if (apwd == NULL) {
      /* failed to find record in passwd.byname */
      return NULL;
   }
      
   bpwd = __pwdb_decnis_check_password_adjunct(name,apwd);
   
   if (bpwd == NULL) {
          return apwd;
   } else {
          return bpwd;
   }
   
}

/*
 * __pwdbNIS_update
 * Updates a NIS entry for an user.
 * Updating (changing) the user login name, uid and/or gid is not
 * currently supported. (I think that some yppasswdd daemons will
 * allow for uid/gid change, but I don't think changing the login
 * name is supported by any of them...
 *
 * Thanks & credit to:
 *     Theo de Raadt <deraadt@fsa.ca> and
 *     Olaf Kirch <okir@monad.swb.de>
 * as this procedure is based on the skeleton provided by their
 * yppasswd program. -- Cristian Gafton
 *
 * Return: 0 means okay...
 */
int __pwdb_decnis_update (const char *oldpass, const struct __pwdb_passwd *pwd)
{
  return __pwdbNIS_update (oldpass, pwd);
}

      
struct __pwdb_passwd  *__pwdb_decnis_check_password_adjunct(
	     const char *tname, 
	     struct __pwdb_passwd *nispwd)
{
   /* first check for the sunos passwd.adjunct tokens */
   /*  Code for sunos password.adjunct based on code in libc5 */
   /*  Code for DEC UNIX prpasswd based on patches for libc4/libc5 by atp */
   /*  TODO:
    *        use information in the NIS map to deduce the type of 
    *        the server. Use this to set a variable which allows speedier 
    *        lookups second round */
   
   char *pw_ptr, *pw_ptr_too;
   int  result_len, clen;
   char *result;
   struct __pwdb_passwd *return_pwd;
   
   /* we reuse the same structure */
   return_pwd = nispwd;
   
   /* we have to know the nisdomain name for the subsequent calls 
    * to yp_match, hence repeated code from __pwdbNIS_getpwnam.
    * Either that or we interfere with the static variables in nis/password.c */
   
   /* this is our copy of nis_bound */
   if (!nis_bound) __pwdb_decnis_bind_nis ();
   if (!nis_bound) return NULL;  

   if (!nispwd) return NULL;
      
   /* check for passwd.adjunct first  */
   
   if ( !strncmp(nispwd->pw_passwd,"##\0",2) ){
      /* This looks like a sunos style shadowed password entry */
      /*  -- we have already checked the nis_bound variable above */
      
      if (yp_match(nis_domain, "passwd.adjunct.byname", tname, strlen(tname),
			&result, &result_len) != 0) {

	 return return_pwd;
      
      } /* match did not return a result */
      
      /* locate the passwd entry */ 
      
      pw_ptr = strchr(result,':');
      if (pw_ptr == NULL) return NULL;

      pw_ptr_too = strchr(pw_ptr+1,':');
      if (pw_ptr_too == NULL) return NULL;
     
   } /* sunos style shadowed password */
    else 
   {
      /* default to a DEC shadowed NIS entry */
      if (yp_match(nis_domain, "prpasswd", tname, strlen(tname),
			&result, &result_len) != 0) {
	 
	 return return_pwd;
      }

      /* locate the u_pwd entry */
       pw_ptr = strstr(result,"u_pwd=");

       if (pw_ptr == NULL ) return NULL;
      
       pw_ptr+=5; /* skip the "u_pwd=" */ 
      
       pw_ptr_too = strchr(pw_ptr, ':'); 
       if (pw_ptr_too == NULL ) return NULL;

   } /* dec type shadow password */

   /* fill static buffer & repoint the pw_passwd entry to it */
   memset(shadow_pwdbuf,0,BUFSIZ);

   clen = pw_ptr_too - pw_ptr; 
   if ((clen >= BUFSIZ) || (clen <= 0)) return NULL;

   /* skip the initial ':' or '=' (pw_ptr+1), and last ':' (clen-1) */ 
   strncpy (shadow_pwdbuf, pw_ptr+1, clen-1);
   return_pwd->pw_passwd = shadow_pwdbuf;
         
   return return_pwd;

} /* __pwdbNIS_check_password_adjunct */

#ifdef TEST_DECNIS 
#include <stdio.h>

int main(int argc, char *argv[])
{
   struct __pwdb_passwd *tpwd;
   
   if (argc < 2) {printf("testit username\n"); exit(-1);}
   printf("looking up username %s\n", argv[1]);
   
   tpwd = __pwdb_decnis_getpwnam (argv[1]);
   
   if (tpwd == NULL) {
      printf ("user does not exist\n");
      exit(0);
   }
   
   printf("pwd->pw_name, |%s|\npwd->pw_passwd, |%s|\n",tpwd->pw_name,tpwd->pw_passwd);
   printf("pwd->uid, %d\npwd->gid, %d\n",tpwd->pw_uid, tpwd->pw_gid);
   printf("pwd->gecos, |%s|\npwd->home, %s\n",tpwd->pw_gecos, tpwd->pw_dir);
   printf("pwd->shell, |%s|\n",tpwd->pw_shell);
   
   printf("\naddr pw_name, 0x%xp, addr pw_passwd, 0x%xp, addr pw_uid 0x%xp\n",
	  tpwd->pw_name,tpwd->pw_passwd,&tpwd->pw_uid);
   
}
#endif


   
