/**************************************************************************
    getpwduid.c:test program for NSS for NDS

    Copyright (C) 2002  Patrick Pollet

    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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA


    Revision history:

	1.00  	2003, January 06	Patrick Pollet <patrick.pollet@insa-lyon.fr>
		initial release
	1.01	2003, January 08	Patrick Pollet <patrick.pollet@insa-lyon.fr>
		added conf structure and control group
		added optional fallback UID and GID if none found in NDS (default is to skip user,group)
	1.02	2003, January 09	Patrick Pollet <patrick.pollet@insa-lyon.fr>
		added initgroups
	1.03	2003, January 10	Patrick Pollet <patrick.pollet@insa-lyon.fr>
		fixed bug in nds_user_info2 (bad structure received by nds_user_location2)
	1.04	2003, January 11	Patrick Pollet <patrick.pollet@insa-lyon.fr>
		fixed setting ndsXXX=NULL trees in case of errors in _nss_ncp_setxxent()
		made always NAME_CONTEXT=[Root] in CreateContextAndConn
		calling NWCCloseIteration only it some errors has occured in the search
	1.05
		modified to use nss_ncp.so
************************************************************************/


#define  TRUE		1
#define  FALSE		0

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <ncp/nwnet.h>

#ifdef VERBOSE
#include <ncp/ncplib.h>
#endif
#include <unistd.h>
#include <ctype.h>
#include <wchar.h>
#include <string.h>

#include "private/libintl.h"

#include <pwd.h>
#include <grp.h>
#include <shadow.h>
#include <sys/syslog.h>

#include <nss.h>

#include "nss_ncp.h"
#include "nss_cfgfile.h"


static struct nss_ncp_conf defConf ={0, TRUE, NULL, NULL, NULL, 100, NULL, -1, -1, TRUE, TRUE, TRUE};

/**************** TESTING ******************/

static void print_passwd (struct passwd pwd){
	printf("%s:%s:%d:%d:%s:%s:%s\n",pwd.pw_name,pwd.pw_passwd,pwd.pw_uid,pwd.pw_gid,pwd.pw_gecos,pwd.pw_dir,pwd.pw_shell);
}

static void print_group (struct group grp){
	char ** mmb; int num;
	printf("%s:%s:%d:",grp.gr_name,grp.gr_passwd,grp.gr_gid);
	for (mmb=grp.gr_mem,num=0;*mmb; mmb++,num++) {
		if (num)
			printf(",");
		printf ("%s",*mmb);

	}
	printf("\n");

}

static void print_shadow (struct spwd spw){
	printf("%s:%s:%ld:%ld:%ld:%ld:%ld:%ld:%ld\n",spw.sp_namp,spw.sp_pwdp,spw.sp_lstchg,spw.sp_min,spw.sp_max,spw.sp_warn,spw.sp_inact,spw.sp_expire,spw.sp_flag);
}


static void print_user_groups(gid_t * groups, long int start, long int size){
	int i;
	printf("start=%ld size=%ld\n",start,size);
	for (i=0; i<start; i++)
		printf("%d ",groups[i]);
	printf("\n");
}

static void give_details_on_user_groups(gid_t *groups, long int start){
	struct group grp;
	char buffer[65000];
	long int i;
	for (i=0; i<start;i++) {
		enum nss_status err=_nss_ncp_getgrgid_r (groups[i],&grp,buffer,sizeof(buffer),&errno);
		if (err==NSS_STATUS_SUCCESS)
			print_group(grp);
		else printf("nss result is %d for group %d\n",err,groups[i]);
	}
}

#define _(X) gettext(X)

static char *progname;

static void usage(void)
{
	fprintf(stderr, _("usage: %s [options]\n"), progname);
	exit (1);
}

static void help(void)
{
	printf(_("\n"
	         "usage: %s [options]\n"), progname);
	printf(_("\n"
	       	"-h             Print this help text\n"
	       	"-u id          Unix User passwd info to search by uid in NDS\n"
		"-n login	Unix User passwd infos to search by name in NDS\n"
		"-s login	Unix User shadow infos to search by name in NDS\n"
		"-i grpid       Unix  group to search by gid in NDS\n"
		"-g grpname	Unix group to search by name in NDS\n"
		"-m login       Get Unix groups of user login\n"
		"-U 		all Unix users to search in NDS\n"
		"-G 		all Unix groups to search in NDS\n"
		"-S 		all Unix shadows to search in NDS\n"
		"-D		verbose mode (fill /var/log/secure && screen)\n"
		"-T treeName	use this Tree  \n"
		"-B serverName	use this server\n"
		"-C NDS ctx	start in this context (default=[Root])\n"
		"-O NDS group	restrict user's search to this group\n"
		"-f fallbackID if no UID,GID found in NDS use this one (default=-1 skip user & group)\n"
		"-2		show the BUG (two calls )\n"
	       "\n"));
	exit (1);
}

/*************************************************************************
** main
*/
int main (int argc, char** argv) {

	const char* userName=NULL;
	uid_t userId=-1;
	const char* groupName=NULL;
	gid_t groupId=-1;
	const char* shadowName=NULL;
	const char* memberName=NULL;
	int opt;
	int allUsers=0;
	int allGroups=0;
	int allShadows=0;
	char buffer[65000];
	int nbCalls=1;

	struct passwd pwd;
	struct group grp;
	struct spwd spw;

	progname = argv[0];
	while ((opt = getopt(argc, argv, "h?u:n:g:i:s:m:T:B:C:O:f:UGSD2")) != EOF)
	{
		switch (opt)
		{
		case 'n':
			userName = optarg;
			break;
		case 'm':
			memberName = optarg;
			break;
		case 's':
			shadowName = optarg;
			break;
		case 'g':
			groupName = optarg;
			break;
		case 'i':
			groupId = strtoul(optarg, NULL, 0);
			break;
		case 'u':
			userId = strtoul(optarg, NULL, 0);
			break;
		case 'U':
			allUsers=1;
			break;
		case 'G':
			allGroups=1;
			break;
		case 'S':
			allShadows=1;
			break;
		case 'D':
			defConf.debug=QF_DEBUG;
			break;
		case 'T':
			defConf.server=optarg;
			defConf.useTree=1;
			break;
		case 'B':
			defConf.server=optarg;
			defConf.useTree=0;
			break;
		case 'C':
			defConf.startCtx=optarg;
			break;
		case 'O':
			defConf.ctrlGroup=optarg;
			break;
		case 'f':
			defConf.fallbackUid=strtoul(optarg, NULL, 0);
			defConf.fallbackGid=strtoul(optarg, NULL, 0);
			break;
		case '2':
			nbCalls=2;
			break;
		case 'h':
		case '?':
			help();

		default:
			usage();
		}
	}
	if (defConf.debug)
		openlog("ncp_nss", LOG_PID, LOG_AUTHPRIV);

	while(nbCalls--) {  // do it once or twice (freeze at the second !!!!)

	if (userName) {
		printf ("searching in passwd for login %s\n",userName);
		if (_nss_ncp_getpwnam_r (userName,&pwd,buffer,sizeof(buffer),&errno)==NSS_STATUS_SUCCESS)
			print_passwd(pwd);
	}
	if (memberName) {
		#define MAX_GRP 30
		gid_t groups[MAX_GRP];
		long int start=0;
		long int size=MAX_GRP;
		printf ("searching groups of %s\n",memberName);
		if ( _nss_ncp_initgroups (memberName, /*999 */ defConf.defGid,&start,&size,groups,0,&errno)==NSS_STATUS_SUCCESS) {
                //long int *start, long int *size, gid_t * groups,long int limit,int *errnop) {
			print_user_groups(groups,start,size);
			give_details_on_user_groups(groups,start);// FREEZE AT THIS SECOND CALL to NWCCOpenConnByNAME !!!!
		}

	}
	if (userId != (uid_t)-1) {
		printf ("searching in passwd for uid %d\n",userId);
		if ( _nss_ncp_getpwuid_r (userId, &pwd,buffer,sizeof(buffer),&errno)==NSS_STATUS_SUCCESS)
			print_passwd(pwd);
	}

	if (allUsers) {
		_nss_ncp_setpwent();

		while ( _nss_ncp_getpwent_r(&pwd,buffer,sizeof(buffer),&errno)==NSS_STATUS_SUCCESS)
			print_passwd(pwd);
		_nss_ncp_endpwent();
	}

	if (groupName) {
		printf ("searching in group for %s\n",groupName);
		if (_nss_ncp_getgrnam_r (groupName,&grp,buffer,sizeof(buffer),&errno)==NSS_STATUS_SUCCESS) {
			print_group(grp);
		}
	}

	if (groupId != (gid_t)-1) {
		printf ("searching in group for gid %d\n",groupId);
		if ( _nss_ncp_getgrgid_r (groupId, &grp,buffer,sizeof(buffer),&errno)==NSS_STATUS_SUCCESS)
			print_group(grp);
	}

	if (allGroups) {
		_nss_ncp_setgrent();

		while ( _nss_ncp_getgrent_r(&grp,buffer,sizeof(buffer),&errno)==NSS_STATUS_SUCCESS)
			print_group(grp);
		_nss_ncp_endgrent();
	}

	if (shadowName) {
		printf ("searching in shadow for login %s\n",shadowName);
		if (_nss_ncp_getspnam_r (shadowName,&spw,buffer,sizeof(buffer),&errno)==NSS_STATUS_SUCCESS)
			print_shadow(spw);
	}

	if (allShadows) {
		_nss_ncp_setspent();
		while ( _nss_ncp_getspent_r(&spw,buffer,sizeof(buffer),&errno)==NSS_STATUS_SUCCESS)
			print_shadow(spw);
		_nss_ncp_endspent();
	}
	}

	if (defConf.debug)
		closelog();
	exit(0);
}
