/* pwdgrp.cc: Request account information

   Copyright 2014, 2015 Red Hat, Inc.

This file is part of Cygwin.

This software is a copyrighted work licensed under the terms of the
Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
details. */

#ifdef __OUTSIDE_CYGWIN__
#include "woutsup.h"

#include <stdio.h>
#include <errno.h>
#include <pwd.h>
#include <grp.h>
#include <sys/cygwin.h>

#include "cygserver.h"
#include "process.h"
#include "transport.h"

#include "cygserver_pwdgrp.h"

#include <sddl.h>

client_request_pwdgrp::client_request_pwdgrp ()
  : client_request (CYGSERVER_REQUEST_PWDGRP,
		    &_parameters, sizeof (_parameters))
{ 
}

void
client_request_pwdgrp::pwd_serve ()
{
  struct passwd *pwd = NULL;

  switch (_parameters.in.type)
    {
    case SID_arg:
      pwd = (struct passwd *) cygwin_internal (CW_GETPWSID, 0,
					      &_parameters.in.arg.sid);
      break;
    case NAME_arg:
      pwd = getpwnam (_parameters.in.arg.name);
      break;
    case ID_arg:
      pwd = getpwuid (_parameters.in.arg.id);
      break;
    default:
      break;
    }
  if (pwd)
    msglen (snprintf (_parameters.out.line, sizeof _parameters.out.line,
		      "%s:%s:%u:%u:%s:%s:%s",
		      pwd->pw_name ?: "",
		      pwd->pw_passwd ?: "",
		      (uint32_t) pwd->pw_uid,
		      (uint32_t) pwd->pw_gid,
		      pwd->pw_gecos ?: "",
		      pwd->pw_dir ?: "",
		      pwd->pw_shell ?: "") + 1);
  else
    {
      switch (_parameters.in.type)
	{
	case SID_arg:
	  {
	    char *str;
	    if (ConvertSidToStringSid (&_parameters.in.arg.sid, &str))
	      {
		debug_printf ("User <%s> failed", str);
		LocalFree (str);
	      }
	  }
	  break;
	case NAME_arg:
	  debug_printf ("User <%s> failed", _parameters.in.arg.name);
	  break;
	case ID_arg:
	  debug_printf ("User <%u> failed", _parameters.in.arg.id);
	  break;
	default:
	  break;
	}
      _parameters.out.line[0] = '\0';
      msglen (0);
      error_code (ENOENT);
    }
}

void
client_request_pwdgrp::grp_serve ()
{
  struct group *grp = NULL;

  switch (_parameters.in.type)
    {
    case SID_arg:
      grp = (struct group *) cygwin_internal (CW_GETGRSID, 0,
					      &_parameters.in.arg.sid);
      break;
    case NAME_arg:
      grp = getgrnam (_parameters.in.arg.name);
      break;
    case ID_arg:
      grp = getgrgid (_parameters.in.arg.id);
      break;
    default:
      break;
    }
  if (grp)
    msglen (snprintf (_parameters.out.line, sizeof _parameters.out.line,
		      "%s:%s:%u:",
		      grp->gr_name ?: "",
		      grp->gr_passwd ?: "",
		      (uint32_t) grp->gr_gid) + 1);
  else
    {
      switch (_parameters.in.type)
	{
	case SID_arg:
	  {
	    char *str;
	    if (ConvertSidToStringSid (&_parameters.in.arg.sid, &str))
	      {
		debug_printf ("Group <%s> failed", str);
		LocalFree (str);
	      }
	  }
	  break;
	case NAME_arg:
	  debug_printf ("Group <%s> failed", _parameters.in.arg.name);
	  break;
	case ID_arg:
	  debug_printf ("Group <%u> failed", _parameters.in.arg.id);
	  break;
	default:
	  break;
	}
      _parameters.out.line[0] = '\0';
      msglen (0);
      error_code (ENOENT);
    }
}

void
client_request_pwdgrp::serve (transport_layer_base *const conn,
			      process_cache *const cache)
{
  debug_printf ("Request account information");
  if (msglen () < __builtin_offsetof (struct _pwdgrp_param_t::_pwdgrp_in_t, arg)
		  + sizeof (uint32_t)
      || msglen () > sizeof (_parameters.in))
    {
      syscall_printf ("bad request body length: got %lu", msglen ());
      error_code (EINVAL);
      msglen (0);
      return;
    }
  error_code (0);
  if (_parameters.in.group)
    grp_serve ();
  else
    pwd_serve ();
  debug_printf ("Request account information returns <%s> error %d", _parameters.out.line, error_code ());
}
#endif /* __OUTSIDE_CYGWIN__ */
