#include "shared_encrypt.h"
/* ENCRYPT_PASSWORDS is #defined in global.h */
#ifdef ENCRYPT_PASSWORDS

static
char des_salt_char(char letter)
{
/* salt_string contains the characters which may be used as a 
** crypt() salt
*/
 char *salt_string = "aA0bBcC1dDe2EfF3gGh4H.I5iJ6jK7k8L9lMmNnOo/PpqQrRsStTuUVvWwxXYyZz";
 
 return *(salt_string + (letter % 64));   /* 64 is the length of salt_string above */

}





/* returns a two character DES salt string
** - take the first two chars of username as a salt
** - use it to encrypt the username
** - return chars 5 and 11 of the encrypted username as the 
**   salt
**/

static
char *des_salt(const char *username)
{
 static char salt[3];
 char encrypted_username[MAX_ENCRYPTED_PASSWORD + 1];

 if(strlen(username) >= 2)   /* this should always be the case */
  {   
      *salt = des_salt_char(*username);
      *(salt + 1) = des_salt_char(*(username + 1));
      *(salt + 2) = '\0';
  }  
 else
     strcpy(salt, "x4");    /* should never get to that point */
      
    
  strncpy(encrypted_username, crypt(username, salt), MAX_ENCRYPTED_PASSWORD + 1);
  
  if(strlen(encrypted_username) >= 12)
   {   
    *salt = des_salt_char(encrypted_username[5]);
    *(salt + 1) = des_salt_char(encrypted_username[11]);
    *(salt + 2) = '\0';
   }
    
   return salt;
}




/** returns the last 8 chars of string
**/
static
char *last_eight_chars(const char *string)
{
 int len;
 static char last_eight[9];
  
 len = strlen(string);
 if(len <= 8)
     strcpy(last_eight, string);
 else
    strcpy(last_eight, string + len - 8);
    
 return last_eight;   
}





static 
char *md5_salt(const char *username)
{
 static char salt[MAX_SALT + 1];
 char encrypted_username[MAX_ENCRYPTED_PASSWORD + 1];
 char tmp_salt[MAX_SALT + 1];
 char *ptr;
 
 strncpy(encrypted_username, crypt(username, des_salt(username)), MAX_ENCRYPTED_PASSWORD + 1);
 
 strncpy(tmp_salt, last_eight_chars(encrypted_username), MAX_SALT + 1); 
 for(ptr = tmp_salt; *ptr; ptr++)
    *ptr = des_salt_char(*ptr);
      
 strcpy(salt,"$1$");
 strcat(salt, tmp_salt);
 strcat(salt, "$");
 return salt;


}





static
char *my_salt(const char *username)
{

if(USE_MD5_ENCRYPTION)    /* #defined in global.h */
   return md5_salt(username);
else
   return des_salt(username);
}      



char *encrypted_password(const char *plaintext_password, const char *username)
{
  

 return crypt(plaintext_password, my_salt(username));

}


#else    /***************** no encryption version *******************/

char *encrypted_password(const char *plaintext_password, const char *username)
{
  
 static char the_password[MAX_ENCRYPTED_PASSWORD + 1];
 
 strncpy(the_password,  plaintext_password, MAX_ENCRYPTED_PASSWORD + 1);
 
 return the_password;
 

}

#endif




void
create_admin_user_dir(char *username, char *plaintext_passwd, ADMIN_CONFIG_STRUCT *conf)
{
	char dir_name[MAX_PATH +1];
	FILE *fp;
	struct stat buf;

        /* create 'keys' directory, if it doesn't exist */
	snprintf(dir_name, MAX_PATH+1, "../%s/%s/%s", USERS_DIR, ADMIN_DIR, KEY_DIR);
	if(stat(dir_name, &buf) != 0)
	{
	   if(mkdir(dir_name, 0770) == -1)
	     cs_critical_error( ERR_MKDIR_FAILED, "");
	}


        /* create 'survey' directory, if it doesn't exist */
/*	snprintf(dir_name, MAX_PATH+1, "../%s/%s/%s", USERS_DIR, ADMIN_DIR, SURVEY_DIR);
	if(stat(dir_name, &buf) != 0)
	{
	   if(mkdir(dir_name, 0770) == -1)
	     cs_critical_error( ERR_MKDIR_FAILED, "");
	}
	    
*/	    
	    
       /* create the 'letter' dir for this user, if it doesn't exist */
	snprintf(dir_name, MAX_PATH+1, "../%s/%s/%c", USERS_DIR, ADMIN_DIR,sub_dir_name(username));  /* shared_authenticate.c */
	if(stat(dir_name, &buf) != 0)
	{
	  if(mkdir(dir_name, 0770) == -1)
	   cs_critical_error( ERR_MKDIR_FAILED, "");
	}

        /* create the username directory for this user */
	snprintf(dir_name, MAX_PATH +1, "../%s/%s/%c/%s",
		USERS_DIR, ADMIN_DIR,	sub_dir_name(username), username);
	if(mkdir(dir_name, 0770) == -1)
	   cs_critical_error( ERR_MKDIR_FAILED, "");

        /* write the password file */
	snprintf(dir_name, MAX_PATH +1, "../%s/%s/%c/%s/%s",
		USERS_DIR, ADMIN_DIR, 	sub_dir_name(username), username, PASSWD_FNAME);
	fp = fopen(dir_name, "w");
	if(!fp)
	  cs_critical_error( ERR_FOPEN_WRITE_FAILED, "");
	fputs(encrypted_password(plaintext_passwd ,username), fp);
	fclose(fp);

       /* write the configuration file */
       write_super_configuration_file(username, conf);   /* shared_super_util.c */
       
	
}
       



/*** returns via encrypted_password, the encrypted password for the
**** administrator identified by username.
***  Returns 0 on failure , 1 on success
**/

int
get_super_user_password (const  char *username, char *encrypted_password)
{
   char path[MAX_PATH +1];
   char line[200];
   FILE *fp;

   snprintf(path, MAX_PATH +1, "../%s/%s/%c/%s/%s",
           USERS_DIR, ADMIN_DIR, sub_dir_name(username), username, PASSWD_FNAME);

   fp = fopen(path, "r");
   if(!fp)
      return 0;

   if(!fgets(line, 200, fp))
        {
         fclose(fp);
         return 0;
        }
    fclose(fp);

    strtrm(line);   /* shared_strtrm.c */
    strncpy(encrypted_password, line, MAX_ENCRYPTED_PASSWORD + 1);
    *(encrypted_password + MAX_ENCRYPTED_PASSWORD) = '\0';
    return 1;
}    





/** Does the plaintext_passwd provided by the administrator username
*** match the encrypted password for that user?
**/

int
confirm_super_password(const char *plaintext_passwd, const char *username)
{
  char correct_password[MAX_ENCRYPTED_PASSWORD + 1];

  return get_super_user_password (username, correct_password) &&
           !strcmp(correct_password, encrypted_password(plaintext_passwd, username)) ;
}


int
get_central_user_password (const  char *username, char *encrypted_password)
{
 FILE *fp;
 char line[200];
 char passwd_fname[MAX_PATH + 1];
 char dir;

  dir = sub_dir_name(username); 
  snprintf(passwd_fname, MAX_PATH + 1,
              "../%s/%c/%s/%s", USERS_DIR, dir, username,PASSWD_FNAME);

 fp = fopen(passwd_fname,"r");
 if(!fp)
    return 0;

 if(!fgets(line,200,fp))
  {
    fclose(fp);   
    return 0;
  }
    
   fclose(fp);
  strtrm(line); /*shared_strtrm.c */
  strncpy(encrypted_password,line,MAX_ENCRYPTED_PASSWORD + 1);
  return 1;
}  


int
write_central_password_file (const char *username,
					const char *plaintext_password)
{
 char passwd_fname[MAX_PATH + 1];
 FILE *fp;
 char dir;

 dir = sub_dir_name(username); 
 snprintf(passwd_fname, MAX_PATH + 1,
              "../%s/%c/%s/%s", USERS_DIR, dir, username, PASSWD_FNAME);
 fp = fopen(passwd_fname, "w");
 if(!fp)
       return 0;
 fputs(encrypted_password(plaintext_password, username), fp);   /* shared_encrypt.c */      
 fclose(fp);
 
 return 1;
}




USER_STATUS
record_central_user_info(USER_STATUS status, const char *realname, 
				const char *username, const char *password,
				const char *id, 
				const char *crs)
{

 char user_dir[MAX_PATH + 1];
 
 if(status == NEW_USER)
 {
  if(!create_central_letter_dir (sub_dir_name(username)))   /*sub_dir_name() is in shared_authenticate.c */
       return ERROR;
  if(!create_central_user_dir (username))
       return ERROR;
  if(!write_central_password_file (username, password))
       return ERROR;
  if(!write_central_id_file (realname,username,id))
       return ERROR;
  
  sprintf(user_dir,"../%s", USERS_DIR);
  if(!add_to_user_index(user_dir, username, realname, id)) /*shared_user_index.c*/
      return ERROR;
  
 }

 /* next for both new and existing users */
 if(!update_central_course_file(username,crs))  /* shared_add_util.c */
          return ERROR;
    
 return status;     
}





int
update_central_user ( const char *first, const char *last,
                         const char *id, const char * crs,
                         const char *realname, char *username,
                         char *plaintext_password)
{
int try,done;
USER_STATUS status;
int user_len;

derive_username(first, last, id, username, MAX_USERNAME + 1); /* shared_authenticate.c */  
user_len = strlen (username);
for(try = 0, done = 0; !done && (try < MAX_USERNAME_TRIES); try++)  /* MAX_USERNAME_TRIES is in shared_authenticate.h */
{
 status =  check_central_username (username,id);   /* shared_central_user.c */
 switch (status)         
  {
   case NEW_USER:
   case EXISTING_USER: 
                   done = 1;
                   derive_password (username, first, last, id, 
                                             plaintext_password, MAX_PASSWORD); /* shared_authenticate.c */
                   

                   if(record_central_user_info(status, realname,
                                               username, plaintext_password, id, 
                                               crs) == ERROR)
                           return 0;                    
                   break;
      	             
   default:         derive_another_username(first, last,id,username,MAX_USERNAME + 1, try + 1);
      	            break;  
   }
}

   if (!done)
	return 0;
   else
       return 1;
	
}




int 
write_password (const char *username, const char *plaintext_password,
					const char *course_path)
{
 FILE *fp;
 char passwd_path[MAX_PATH + 1];

 snprintf(passwd_path, MAX_PATH + 1,
                     "%s%s%s/%s/%s",course_path,
                               strlen(course_path)?"/":"",
                               PEOPLE_DIR,
                               username,PASSWORD_FNAME);
 fp = fopen (passwd_path,"w");
 if(!fp)
   return 0;
 if(get_exclusive_lock(fileno(fp), 0))   /* shared_lock.c */
 {
     fclose(fp);
     return 0;
 }
 fputs(encrypted_password(plaintext_password, username), fp);   /* shared_encrypt.c */

 release_lock(fileno(fp));     /* shared_lock.c */

 fclose(fp);
 return 1;
}




