/* Copyright (C) 1998, 1999 Thorsten Kukuk
   Author: Thorsten Kukuk <kukuk@suse.de>

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2, or (at your option)
   any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software Foundation,
   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */

#if defined(HAVE_CONFIG_H)
#include "config.h"
#endif

#define _GNU_SOURCE

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <shadow.h>
#include <rpcsvc/nis.h>
#include "nispasswd.h"

#define NISENTRYVAL(idx,col,res) \
        ((res)->objects.objects_val[(idx)].zo_data.objdata_u.en_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val)

#define NISENTRYLEN(idx,col,res) \
        ((res)->objects.objects_val[(idx)].zo_data.objdata_u.en_data.en_cols.en_cols_val[(col)].ec_value.ec_value_len)

/* Solaris defines this in shadow.h */
#ifndef DAY
#define DAY (24L*3600L)
#endif

#ifdef ITI_AGING
#define SCALE 1
#else
#define SCALE DAY
#endif

static int parse_spent (unsigned long nr, nis_result *result, struct spwd *sp);

static char *
date_to_str (time_t t)
{
  static char buf[80];
  struct tm *tm;

  tm = gmtime (&t);
  strftime (buf, sizeof buf, "%m/%d/%Y", tm);
  return buf;
}

static const char *
pw_status (const char *pass)
{
  if (*pass == '*' || *pass == '!' || *pass == 'x')
    return "LK";
  if (*pass == '\0')
    return "NP";
  return "PS";
}

/* We couldn't use getspnam here, because we don't know from which
   domain getspnam will get the data, it could the wrong one if the
   use is in more then one domain or if the domain is not in the
   local NIS+ searchpath */
void
npd_display (char *domainname, int all, char *username)
{
  unsigned long i;
  nis_result *res;

  if (all)
    {
      if (strlen (domainname) == 0)
	res = nis_list ("passwd.org_dir", EXPAND_NAME, NULL, NULL);
      else
	{
	  char buf[strlen (domainname) + 20];

	  sprintf (buf, "passwd.org_dir.%s", domainname);
	  res = nis_list (buf, EXPAND_NAME, NULL, NULL);
	}
    }
  else if (username)		/* Show a special user */
    {
      if (strlen (domainname) == 0)
	{
	  char buf[strlen (username) + 30];

	  sprintf (buf, "[cname=%s],passwd.org_dir", username);
	  res = nis_list (buf, EXPAND_NAME, NULL, NULL);
	}
      else
	{
	  char buf[strlen (username) + strlen (domainname) + 30];

	  sprintf (buf, "[cname=%s],passwd.org_dir.%s", username,
		   domainname);
	  res = nis_list (buf, EXPAND_NAME, NULL, NULL);
	}
    }
  else
    /* Show the current user data */
    {
      if (strlen (domainname) == 0)
	{
	  char buf[60];

	  sprintf (buf, "[uid=%d],passwd.org_dir", getuid ());
	  res = nis_list (buf, EXPAND_NAME, NULL, NULL);
	}
      else
	{
	  char buf[strlen (domainname) + 60];

	  sprintf (buf, "[uid=%d],passwd.org_dir.%s", getuid (),
		   domainname);
	  res = nis_list (buf, EXPAND_NAME, NULL, NULL);
	}
    }

  if (res == NULL || res->status != NIS_SUCCESS)
    {
      if (res == NULL)
	fprintf (stderr, "NIS+ not running ?\n");
      else
	nis_perror (res->status, "nispasswd");
      nis_freeresult (res);
      exit (3);
    }

  if (res->objects.objects_val[0].zo_data.zo_type != NIS_ENTRY_OBJ ||
      strcmp (res->objects.objects_val[0].zo_data.objdata_u.en_data.en_type,
	      "passwd_tbl") != 0 ||
      res->objects.objects_val[0].zo_data.objdata_u.en_data.en_cols.en_cols_len < 7)
    exit (3);

  for (i = 0; i < res->objects.objects_len; ++i)
    {
      struct spwd sp;

      if (parse_spent (i, res, &sp))
	{
	  if (sp.sp_lstchg <= 0)
	    printf ("%s %s\n",
		    sp.sp_namp,
		    pw_status (sp.sp_pwdp));
	  else
	    printf ("%s %s %s %ld %ld %ld %ld\n",
		    sp.sp_namp,
		    pw_status (sp.sp_pwdp),
		    date_to_str (sp.sp_lstchg * SCALE),
		    (sp.sp_min * SCALE) / DAY,
		    (sp.sp_max * SCALE) / DAY,
		    (sp.sp_warn * SCALE) / DAY,
		    (sp.sp_inact * SCALE) / DAY);
	}
    }
}

static int
parse_spent (unsigned long nr, nis_result *result, struct spwd *sp)
{
  char *line, *cp;

  sp->sp_namp = malloc (NISENTRYLEN (nr, 0, result) + 1);
  strncpy (sp->sp_namp, NISENTRYVAL (nr, 0, result),
	   NISENTRYLEN (nr, 0, result));
  sp->sp_pwdp = malloc (NISENTRYLEN (nr, 1, result) + 1);
  strncpy (sp->sp_pwdp, NISENTRYVAL (nr, 1, result),
	   NISENTRYLEN (nr, 1, result));

  sp->sp_lstchg = sp->sp_min = sp->sp_max = sp->sp_warn = sp->sp_inact =
    sp->sp_expire = sp->sp_flag = -1;

  if (result->objects.objects_val[nr].zo_data.objdata_u.en_data.en_cols.en_cols_len > 7
      && NISENTRYLEN (nr, 7, result) > 0)
    {
      line = NISENTRYVAL (nr, 7, result);
      cp = strchr (line, ':');
      if (cp == NULL)
	return 0;
      *cp++ = '\0';
      sp->sp_lstchg = atol (line);

      line = cp;
      cp = strchr (line, ':');
      if (cp == NULL)
	return 0;
      *cp++ = '\0';
      sp->sp_min = atol (line);

      line = cp;
      cp = strchr (line, ':');
      if (cp == NULL)
	return 0;
      *cp++ = '\0';
      sp->sp_max = atol (line);

      line = cp;
      cp = strchr (line, ':');
      if (cp == NULL)
	return 0;
      *cp++ = '\0';
      sp->sp_warn = atol (line);

      line = cp;
      cp = strchr (line, ':');
      if (cp == NULL)
	return 0;
      *cp++ = '\0';
      sp->sp_inact = atol (line);

      line = cp;
      cp = strchr (line, ':');
      if (cp == NULL)
	return 0;
      *cp++ = '\0';
      sp->sp_expire = atol (line);

      line = cp;
      if (line == NULL)
	return 0;
      sp->sp_flag = atol (line);
    }

  return 1;
}
