/**********************************************************************
 *  passwd.c -- add/remove user from passwd file
 *
 * Copyright 1994 by the Massachusetts Institute of Technology
 * For copying and distribution information, please see the file
 * <mit-copyright.h>.
 **********************************************************************/
#include <mit-copyright.h>

#include <AL/AL.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#ifdef SOLARIS
#include <shadow.h>
#endif

#ifdef BSD4_4
#include <paths.h>
#define PATH_PASSWD		_PATH_MASTERPASSWD
#else
#define PATH_PASSWD		"/etc/passwd"
#endif

#ifdef SOLARIS
#define SHADOW_PASSWORDS
#define PATH_SHADOW		"/etc/shadow"
#endif

#define PATH_PASSWD_LOCK	"/etc/ptmp"

/* XXX nocrack */
int PWaddPasswdEntry(struct passwd *pwd)
{
    char line[1024], prefix[128], *passwd;

    sprintf(prefix, "%s:", pwd->pw_name);
#ifdef SHADOW_PASSWORDS
    sprintf(line, "%s:%s:%ld::::::", pwd->pw_name, pwd->pw_passwd,
	    (long) pwd->pw_uid);
    ALchangeFile(PATH_SHADOW, PATH_PASSWD_LOCK, prefix, line, 0);
#endif

#ifdef BSD4_4
    sprintf(line, "%s:%s:%ld:%ld::0:0:%s:%s:%s", pwd->pw_name, pwd->pw_passwd,
	    (long) pwd->pw_uid, (long) pwd->pw_gid, pwd->pw_gecos, pwd->pw_dir,
	    pwd->pw_shell);
#else
    sprintf(line, "%s:*:%ld:%ld:%s:%s:%s", pwd->pw_name, (long) pwd->pw_uid,
	    (long) pwd->pw_gid, pwd->pw_gecos, pwd->pw_dir, pwd->pw_shell);
#endif
    return ALchangeFile(PATH_PASSWD, PATH_PASSWD_LOCK, prefix, line, 1);
}

int PWremovePasswdEntry(struct passwd *pwd)
{
    char prefix[128];

    sprintf(prefix, "%s:", pwd->pw_name);
#ifdef SHADOW_PASSWORDS
    ALchangeFile(PATH_SHADOW, PATH_PASSWD_LOCK, prefix, NULL, 1);
#endif
    return ALchangeFile(PATH_PASSWD, PATH_PASSWD_LOCK, prefix, NULL, 1);
}

/* XXX do reference count */
long ALincRefCount(ALsession session)
{ return 0L; }

/* set error context to contents of a file */
void
ALgetErrorContextFromFile(ALsession session, char *filename)
{
  int fd, cnt;

  fd = open(filename, O_RDONLY);
  if (fd < 0)
    {
      ALcontext(session)[0]='\0';
    }
  else
    {
      /* put contents of NOCREATE file in error context */
      cnt = read(fd, ALcontext(session), ALlengthErrContext);

      /* null-terminate the string */
      if (cnt < ALlengthErrContext) ALcontext(session)[cnt] = '\0';
      else ALcontext(session)[ALlengthErrContext] = '\0';
    }
  return;
}

long ALaddPasswdEntry(ALsession session)
{
  long code;
  FILE *pfile;
  int cnt, fd;
#ifdef SOLARIS
  long lastchg = DAY_NOW;
#endif

  /* inc refcount */
  if ((code=ALincRefCount(session)) != 0L) return(code);

  /* if we didn't find user via hesiod, we're done */
  if (!ALisTrue(session, ALdidGetHesiodPasswd)) return 0L;

  /* if NOCREATE is set, return an error */
  if (ALisTrue(session, ALhaveNOCREATE))
    {
      ALgetErrorContextFromFile(session, ALfileNOCREATE);
      return(ALerrNOCREATE);
    }

  if (ALisTrue(session, ALisRemoteSession) && ALisTrue(session, ALhaveNOREMOTE))
    {
      ALgetErrorContextFromFile(session, ALfileNOREMOTE);
      return(ALerrNOREMOTE);
    }

  if (PWaddPasswdEntry(&session->pwd) < 0)
    ALreturnError(session, ALerrUpdateFail, "passwd update failed");

  return 0;
}

long ALremovePasswdEntry(ALsession session)
{
  /* XXX should decrement refcount */
  /* if we didn't find user via hesiod, we're done */
  if (!ALisTrue(session, ALdidGetHesiodPasswd)) return 0L;

  if (PWremovePasswdEntry(&session->pwd) < 0)
      ALreturnError(session, ALerrUpdateFail, "passwd update failed");

  return 0;
}

long ALupdatePasswdEntry(ALsession session)
{
  if (PWaddPasswdEntry(&session->pwd) < 0)
    ALreturnError(session, ALerrUpdateFail, "passwd update failed");

  return 0;
}

