/* xlogin-auth_shadow.c
	
	(c) 2008 Jonathan Andrews
	
	xlogin pulls in one of the xlogin-auth_<mech>.c files and calls it xlogin-auth.c

	Authenticate a user using shadow passwords and getpwent to read user UID, GID and HOME fields
*/

#define AUTHNAME	"shadow\0"
#define _XOPEN_SOURCE 500          /* define before 1st #include */

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



// See userrec structure in xlogin.c for field names.
// Caller expects valid values for newuid,newgid,homedir,authused

int auth( struct userrec * userrecord )
{
	char line[1024];
    	FILE *f;
    	int len;
    	int count = 0;
   	int userfound=FALSE;
	char pass[512];
	char user[512];

	strcpy(pass,userrecord->password);
	strcpy(user,userrecord->username);
	strcpy(userrecord->authused,AUTHNAME);						// Allows xlogin to know you authenticated via shadow password

	// If root is now allowed to login then exit early with a fail

	if ((strcmp(user,"root")==0)&(userrecord->allowroot!=TRUE))
	{
		if (verbose==TRUE)
			printf("%s: root is now allowed to auth, override with -allowroot option\n",PROGNAME);
		return(FALSE);
	}


    	if ((f = fopen("/etc/shadow", "r")) == NULL) return 1;
    	strcat(user, ":");
    	len = strlen(user);
	userfound=FALSE;	
    	while (fgets(line, sizeof line, f)) 
	{
        	if (strncmp(line, user, len) == 0) 
		{
			int cmplen = 13;
            		if (strncmp(&line[len], "$1$", 3) == 0) cmplen = 34;
            		if (strncmp(crypt(pass, &line[len]), &line[len], cmplen) == 0) userfound=TRUE;
            		break;
        	}
    	}
    	fclose(f);

	if (verbose==TRUE)
	{
		if (userfound==TRUE)
			printf("%s: User authed ok from /etc/shadow\n",PROGNAME);
		else	printf("%s: User did not auth from /etc/shadow\n",PROGNAME);
		fflush(stdout);
	}
			


	user[strlen(user)-1]='\0';
	if (userfound==TRUE)
	{
 		struct passwd *p;
   		userfound=FALSE;

   		while (((p=getpwent()) != NULL)&(userfound!=TRUE))
      		{
      			//printf("compare [%s] with [%s]\n",username,p->pw_name); fflush(stdout);
            		if (strcmp(user,p->pw_name)==0)
           		{
       				printf("%s: Found user,  UID=%ld  GID=%ld  HOME=%s\n",PROGNAME,(long) p->pw_uid,(long) p->pw_gid,p->pw_dir);
         			userrecord->newuid= p->pw_uid;
     				userrecord->newgid= p->pw_gid;
            			strcpy(userrecord->homedir,p->pw_dir);
           			fflush(stdout);
         			userfound=TRUE;
     			}	
		}
		endpwent();                                                             // Destroys the p strucre

		// If after getting the details from the password database the user was not found then we have a problem, any
		// user in /etc/shadow should also be in /etc/password.... best thing to do is bail
		if (userfound!=TRUE)
        	{
     			printf("%s: Error, user authed but not found by getpwent!\n",PROGNAME);
			fflush(stdout);
      			exit(1);
  		}
	}


    	return (userfound); 								// Return true if authenticated
}



