/* 
   Unix SMB/Netbios implementation.
   Version 1.9.
   Copyright (C) Andrew Tridgell 1994-1997

   This file is part of the port to OpenVMS
   Privileged code
   Copyright (C) Eckart Meyer 1996-1997
   
   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 of the License, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*	priv.c
 *	V1.0			6-Aug-1995	IfN/Mey
 *
 *	Copyright E. Meyer <meyer@ifn.ing.tu-bs.de>
 *+
 * Privileged code.
 *-
 */

#define EXTERN
#include "priv.h"
#include <descrip.h>

#ifndef __DECC
#define decc$translate_vms shell$translate_vms
#endif

char *decc$translate_vms(char * __vmsfile);

static struct uai *uai_head = NULL;

char *vms_getlogin()
{
   char *cuserid(), *p;
   p = cuserid(login_name);
   for(;*p != '\0';p++) if ((*p >= 'A') && (*p <= 'Z')) *p += 'a'-'A';
   return(login_name);
}

struct uai *find_uai_by_name(char *name)
{
	struct uai *puai;

	puai = uai_head;
	while (puai != NULL) {
		if (strcmp(name,puai->name) == 0) {
			return(puai);
		}
		puai = puai->next;
	}
	return(NULL);
}

struct uai *find_uai_by_uic(unsigned long uic)
{
	struct uai *puai;

	puai = uai_head;
	while (puai != NULL) {
		if (uic == puai->uic) {
			return(puai);
		}
		puai = puai->next;
	}
	return(NULL);
}

static struct id *get_user_identifiers(unsigned long uic)
{
	unsigned long sts;
	unsigned long ctx;
	struct id *id_list;
	struct id holder;
	struct id id;
	int count;

	holder.uic = uic;
	holder.attr = 0;

	id_list = (struct id *)malloc(sizeof(struct id));
	if (id_list == NULL) return(NULL);

	count = 0;
	ctx = 0;

	while ( (sts=sys$find_held(&holder, &id.uic, &id.attr, &ctx))&1 ) {
		id_list = (struct id *)realloc(id_list,
					sizeof(struct id) * (count+2) );
		if (id_list == NULL) return(NULL);
		id_list[count].uic = id.uic;
		id_list[count].attr = id.attr;
		DEBUG(6,("  identifier %d = %08X\n",count+1,id.uic));
		count++;
	}

	id_list[count].uic = -1;
	DEBUG(6,("  uic %08X holds %d identifiers\n",uic,count));
	return(id_list);
}



long setup_pw()
{
   short int iosb[4], lgth[5];
   long int st;
   struct {
      struct itemdesc id[5];
      int eol;
   } itmlst;
   struct {
      int size;
      char *ptr;
   } namedesc;
   char s[64], t[64];
   struct uai *puai;
   char *p;

   password_struct.pw_name = login_name;
   password_struct.pw_passwd = login_password;
   password_struct.pw_comment = login_comment;
   password_struct.pw_gecos = login_gecos;
   password_struct.pw_dir = login_dir;
   password_struct.pw_shell = login_shell;
   login_comment[0]  = '\0';
   login_gecos[0]    = '\0';
   login_shell[0]    = '\0';

DEBUG (3,("setup_pw: username = \"%s\"\n", login_name));
   puai = find_uai_by_name(login_name);
   if (puai != NULL) {
	login_uai = puai;
	memcpy(login_password,puai->password,8);
	strcpy(login_dir,puai->dir);
	password_struct.pw_uid = puai->uic;
	password_struct.pw_gid = password_struct.pw_uid >> 16;
	login_priv[0] = puai->priv[0];
	login_priv[1] = puai->priv[1];
DEBUG (3,("setup_pw: found uic = %08X\n", puai->uic));
	return(SS$_NORMAL);
   }

   itmlst.id[0].item_code = UAI$_PWD;
   itmlst.id[0].buffer_length = 8;
   itmlst.id[0].buffer = login_password;
   itmlst.id[0].ret_length = &lgth[0];
   itmlst.id[1].item_code = UAI$_DEFDIR;
   itmlst.id[1].buffer_length = 64;
   itmlst.id[1].buffer = s;
   itmlst.id[1].ret_length = &lgth[1];
   itmlst.id[2].item_code = UAI$_DEFDEV;
   itmlst.id[2].buffer_length = 64;
   itmlst.id[2].buffer = t;
   itmlst.id[2].ret_length = &lgth[2];
   itmlst.id[3].item_code = UAI$_UIC;
   itmlst.id[3].buffer_length = 4;
   itmlst.id[3].buffer = (char *) &(password_struct.pw_uid);
   itmlst.id[3].ret_length = &lgth[3];
   itmlst.id[4].item_code = UAI$_PRIV;
   itmlst.id[4].buffer_length = 8;
   itmlst.id[4].buffer = (char *) &(login_priv[0]);
   itmlst.id[4].ret_length = &lgth[4];
   itmlst.eol = 0;
   namedesc.size = strlen(login_name);
   namedesc.ptr = login_name;
   st = sys$getuai(0, 0, &namedesc, &itmlst, 0, 0, 0);
   if ((st != SS$_NORMAL) && !(st & 0x01))
       {
DEBUG (3,("sys$getuai %08X %d\n", st, st));
       return(st);
       }
   password_struct.pw_gid = password_struct.pw_uid >> 16;
   login_password[8] = '\0';
   s[s[0]+1] = '\0';
   t[t[0]+1] = '\0';
   strcat(t+1,s+1);
   p = decc$translate_vms(t+1);
   if (p) strcpy(login_dir,p);
DEBUG (5,("setup_pw: login dir = %s\n", login_dir));

   puai = (struct uai *)malloc(sizeof(struct uai));
   login_uai = puai;
   puai->uic = password_struct.pw_uid;
   puai->id_list = get_user_identifiers(puai->uic);
   puai->priv[0] = login_priv[0];
   puai->priv[1] = login_priv[1];
   strcpy(puai->dir,login_dir);
   memcpy(puai->password,login_password,8);
   strcpy(puai->name,login_name);
   if (uai_head == NULL) {
	puai->next = NULL;
	uai_head = puai;
   }
   else {
	puai->next = uai_head;
	uai_head = puai;
   }

DEBUG (3,("setup_pw: $getuai returns UIC = %08X\n", puai->uic));
DEBUG (3,("          priv = %08X %08X\n", puai->priv[0],puai->priv[1]));
   return(SS$_NORMAL);
 }

static char result[64];
char *crypt(char *key, char *salt)
{
   short int st, iosb[4], lgth[3];
   struct {
      struct itemdesc id[3];
      int eol;
   } itmlst;
   struct {
      int size;
      char *ptr;
   } outdesc, fullnamedesc, namedesc, passwdesc;
   long encrypt, ssalt;
   char username[64];
   char *p;
   long lgi$hpwd();

   for(p=key;*p != '\0';p++) *p = toupper(*p);
   encrypt = 0;
   ssalt = 0;
   itmlst.id[0].item_code = UAI$_SALT;
   itmlst.id[0].buffer_length = 2;
   itmlst.id[0].buffer = (char *) &ssalt;
   itmlst.id[0].ret_length = &lgth[0];
   itmlst.id[1].item_code = UAI$_ENCRYPT;
   itmlst.id[1].buffer_length = 1;
   itmlst.id[1].buffer = (char *) &encrypt;
   itmlst.id[1].ret_length = &lgth[1];
   itmlst.id[2].item_code = UAI$_USERNAME;
   itmlst.id[2].buffer_length = 64;
   itmlst.id[2].buffer = username;
   itmlst.id[2].ret_length = &lgth[2];
   itmlst.eol = 0;
   namedesc.size = strlen(login_name);
   namedesc.ptr = login_name;
DEBUG (3,  ("crypt: username = \"%s\"\n",login_name));
DEBUG (100,("crypt: key = \"%s\"\n",key));
   if ((st=sys$getuai(0,0,&namedesc,&itmlst,0,0,0)) != SS$_NORMAL)
       {
DEBUG (0,("sys$getuai error %08X %d\n", st, st));
	result[0] = '\0';
	return(result);
       }
   outdesc.size = 8;
   outdesc.ptr = result;
   passwdesc.size = strlen(key);
   passwdesc.ptr = key;
/*
   fullnamedesc.size = lgth[2];
   fullnamedesc.ptr = username;
*/
   fullnamedesc.size = strlen(login_name);
   fullnamedesc.ptr = login_name;
   st = lgi$hpwd(&outdesc, &passwdesc, encrypt, ssalt, &fullnamedesc);
   result[8] = '\0';
DEBUG (3,("crypt: result=%08X\n",*((int *)result)));
DEBUG (3,("crypt: passwd=%08X\n",*((int *)login_password)));
   return(result);
}

struct passwd *vms_getpwnam(char *name)
{
   char *p;
DEBUG (3,("getpwnam: name = \"%s\"\n",name));
   strcpy(login_name,name);
   for(p=login_name;*p != '\0';p++) *p = toupper(*p);
   if (setup_pw() != SS$_NORMAL) return(NULL);
   return(&password_struct);
}

struct passwd *vms_getpwuid(uid_t uid)
{
   char *vms_getlogin();
   struct uai *puai;
   struct dsc$descriptor_s dsc_name;
   unsigned short namlen;
   unsigned long sts;

/*
 * If we have the entry, return it.
 * Otherwise use uid as an identifier and get the holder.
 */
   puai = find_uai_by_uic(uid);
   if (puai == NULL) {
	dsc_name.dsc$a_pointer = login_name;
	dsc_name.dsc$w_length = sizeof(login_name);
	dsc_name.dsc$b_class = DSC$K_CLASS_S;
	dsc_name.dsc$b_dtype = DSC$K_DTYPE_T;
	sts = sys$idtoasc(uid,&namlen,&dsc_name,0,0,0);
	if (!(sts&1)) return(NULL);
	login_name[namlen] = '\0';
   }
   else {
/*   	password_struct.pw_name = vms_getlogin(); /**/
	strcpy(login_name,puai->name);
   }

   if (setup_pw() != SS$_NORMAL) return(NULL);
   return(&password_struct);
}

struct passwd *vms_getpwent()
{
   char *vms_getlogin();

   password_struct.pw_name = vms_getlogin();
   if (setup_pw() != SS$_NORMAL) return(NULL);
   return(&password_struct);
}

void vms_setpwent()
{
}

void vms_endpwent()
{
}


int vms_seteuid(uid_t euid)
{
  return(0);
}

int vms_setruid(uid_t ruid)
{
  return(0);
}

int vms_setgid(gid_t gid)
{
  return(0);
}
