/* SPDX-License-Identifier: LGPL-2.1+
 *
 * Copyright (C) 2018 Collabora ltd.
 * @author Sjoerd Simons <sjoerd.simons@collabora.co.uk>
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>


#include <nss.h>
#include <pwd.h>
#include <stddef.h>

#define UNKNOWN_USER_GECOS "Unknown user"
#define UNKNOWN_USER_PASSWD "*"
#define UNKNOWN_USER_DIR "/"
#define UNKNOWN_USER_SHELL "/sbin/nologin"

#define NOGROUP 65534

#define UNKNOWN_FORMAT "uid-%d"

static char * determine_homedir (uid_t uid, char *buffer, size_t buflen)
{
  char *home;

  if (uid != getuid())
    return UNKNOWN_USER_DIR;

  home = getenv ("NSS_UNKNOWN_HOME");

  if (home == NULL)
    home = getenv ("HOME");

  if (home == NULL)
    return UNKNOWN_USER_DIR;

  strncpy (buffer, home, buflen);
  return buffer;
}

enum nss_status _nss_unknown_getpwnam_r (const char *name,
                                        struct passwd *pwd,
                                        char *buffer,
                                        size_t buflen,
                                        int *errnop)
{
  uid_t uid = 0;
  size_t n;

  if (sscanf (name, UNKNOWN_FORMAT, &uid) != 1)
    return NSS_STATUS_NOTFOUND;

  strncpy (buffer, name, buflen);

  pwd->pw_name = buffer;

  n = strlen (name) + 1;
  buffer += n;
  buflen -= n;
  pwd->pw_dir = determine_homedir (uid, buffer, buflen);

  pwd->pw_uid = uid;
  pwd->pw_gid = NOGROUP;
  pwd->pw_gecos = UNKNOWN_USER_GECOS;
  pwd->pw_passwd = UNKNOWN_USER_PASSWD;
  pwd->pw_shell = UNKNOWN_USER_SHELL;

  return NSS_STATUS_SUCCESS;
}

enum nss_status _nss_unknown_getpwuid_r (uid_t uid,
                                         struct passwd *pwd,
                                         char *buffer,
                                         size_t buflen,
                                         int *errnop)
{
  size_t n;

  snprintf (buffer, buflen, UNKNOWN_FORMAT, uid);

  pwd->pw_name = buffer;

  n = strlen (buffer) + 1;
  buffer += n;
  buflen -= n;
  pwd->pw_dir = determine_homedir (uid, buffer, buflen);

  pwd->pw_uid = uid;
  pwd->pw_gid = NOGROUP;
  pwd->pw_gecos = UNKNOWN_USER_GECOS;
  pwd->pw_passwd = UNKNOWN_USER_PASSWD;
  pwd->pw_shell = UNKNOWN_USER_SHELL;

	return NSS_STATUS_SUCCESS;
}
