RCS_ID_C "$Id: getpasswdent.c,v 1.3 1993/10/15 01:16:22 ppessi Exp $";
/*
 * getpasswdent.c - getpwd*() for network library
 *
 * This file is part of the AmiTCP/IP Network Library.
 *
 * Author: ppessi <Pekka.Pessi@hut.fi>
 * Copyright © 1993 AmiTCP/IP Group, <AmiTCP@snakemail.hut.fi>
 *                  Helsinki University of Technology, Finland.
 *
 * Created      : Sun Jun 20 17:52:37 1993 ppessi
 * Last modified: Thu Oct 14 19:24:28 1993 ppessi
 */

#include <exec/memory.h>
#include <dos/dos.h>

#include <string.h>
#include <sys/errno.h>

#include "pwd.h"

#if !NETLIB			/* is this static or */
#error "Shared Library features are unimplemented"
#else
#include <proto/dos.h>

#include <errno.h>
#define SetNetErr(x) (errno=(x))

static BPTR pwdfh = NULL;

#define INTERNAL static

#endif

/*
 * Parsing function
 */
int do_parse(UBYTE *str, int n, UBYTE **array);

/* End reading passwd entities */
INTERNAL void EndPasswdEnt(void)
{
  if (pwdfh) Close(pwdfh), pwdfh = NULL;
}

/* Restart reading passwd entities */
INTERNAL void SetPasswdEnt(void)
{
  if (pwdfh) EndPasswdEnt();
  
  if (!(pwdfh = Open(_PATH_PASSWD, MODE_OLDFILE))) 
    return (void)SetNetErr(ENOENT);
#if 0
  atexit(EndPasswdEnt);
#endif
}

/* Read a next entry from the passwd-file database */
INTERNAL struct passwd *GetPasswd(struct passwd *pwd, ULONG size)
{
  UBYTE *buffer = (UBYTE *)pwd;
  int err = 0;

  if (size - sizeof(struct passwd) < 0) {
    err = ENOBUFS;
    goto bad;
  }

  memset(buffer, sizeof(struct passwd), 0);
  size   -= sizeof(struct passwd) + 1; 
  buffer += sizeof(struct passwd);
  /* fix a bug in the FGetS routine */
  buffer[size] = '\0';

  /* Open file? */
  if (!pwdfh) 
    SetPasswdEnt();

  if (!pwdfh || !FGets(pwdfh, buffer, size)) {
    err = EIO;
    goto bad;
  }

  if (err = do_parse(buffer, 7, (UBYTE **)pwd))
    goto bad;

  /* Parse the UID field */
  if (StrToLong((UBYTE*)pwd->pw_uid, &pwd->pw_uid) <= 0 ||
      /* Parse the GID field */
      StrToLong((UBYTE*)pwd->pw_gid, &pwd->pw_gid) <= 0) {
    err = EFTYPE;
    goto bad;
  }

  return pwd;

 bad:
  SetNetErr(err);
  EndPasswdEnt();
  return (struct passwd*)NULL;
}

/* Search for an entry with a matching user ID */
INTERNAL struct passwd *GetPasswdUID(ULONG uid, 
			    struct passwd *p, 
			    ULONG size)
{
  while ((p = GetPasswd(p, size)) && (p->pw_uid != uid))
    ;
  EndPasswdEnt();
  return p;
}

/* Search for an entry with a matching login name */
INTERNAL struct passwd *GetPasswdName(const UBYTE *name, 
			     struct passwd *p, 
			     ULONG size)
{
  while ((p = GetPasswd(p, size)) && strcmp(p->pw_name, name))
    ;
  EndPasswdEnt();
  return p;
}

#if NETLIB

#include <stdlib.h>

/*
 * A global structure for POSIX compatible functions
 */
#define PSTORE_SIZE 256
static struct passwd * pstore = NULL;

static struct passwd * alloc_pstore(void)
{
  return pstore = (struct passwd *)malloc(PSTORE_SIZE);
}
#endif

/* 
 * Unix compatible getgrgid()
 */
struct passwd *getpwuid(uid_t uid)
{
  if (!pstore && !alloc_pstore()) {
    return NULL;
  }

  return GetPasswdUID((ULONG) uid, pstore, PSTORE_SIZE);
}

/*
 * Unix compatible getpwnam
 */
struct passwd *getpwnam(const char *name)
{
  if (!pstore && !alloc_pstore()) {
    return NULL;
  }
  return GetPasswdName((UBYTE *) name, pstore, PSTORE_SIZE);
}

