/*
 * bbftpd/bbftpd_cert.c
 * Copyright (C) 1999, 2000, 2001, 2002 IN2P3, CNRS
 * bbftp@in2p3.fr
 * http://doc.in2p3.fr/bbftp
 *
 * 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 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.
 */ 

/****************************************************************************

  
  
 bbftpd_cert.c   v 2.2.0 2001/10/03  - Routines creation

*****************************************************************************/
#include <errno.h>
#include <netinet/in.h>
#include <pwd.h>
#include <stdio.h>
#include <syslog.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <utime.h>

#include <bbftpd.h>
#include <config.h>
#include <common.h>
#include <daemon_proto.h>
#include <daemon.h>
#include <structures.h>
#include <version.h>
#include <gssapi.h>
#include <gfw.h>

extern  int             incontrolsock ;
extern  int             outcontrolsock ;
extern  int	            recvcontrolto ;
extern  char            currentusername[MAXLEN] ;
extern  gss_cred_id_t   server_creds;

/*******************************************************************************
** bbftpd_cert_receive_connection :                        	                   *
**                                                                             *
**      This routine is called when a connection occurs in certificate         *
**      authentication mode. It receives the plublic key of the client and     *
**      calls the GSS Framework (GFW) api to validate the connection           * 
**      routine returns 0 to set up correctly the global parameters            *
**                                                                             *
**      OUPUT variable :                                                       *
**          logmessage :  to write the error message in case of error          *
**                                                                             *
**      GLOBAL VARIABLE USED :                                                 *                                                                      *
**          hisrsa              MODIFIED                                       *
**                                                                             *
**                                                                             *
**      RETURN:                                                                *
**          -1  Unrecoverable error                                            *
**           0  OK                                                             *
**                                                                             *
*******************************************************************************/
int bbftpd_cert_receive_connection(int msglen) 
{

    char    logmessage[1024] ;
    char    *username ;
    struct    passwd    *uspass ;
    gss_buffer_desc client_name;
    OM_uint32 min_stat, maj_stat;

    sprintf(logmessage,"bbftpd version %s",VERSION) ;

	maj_stat = gfw_accept_sec_context(&min_stat, incontrolsock, outcontrolsock, server_creds, &client_name);
    if (maj_stat != GSS_S_COMPLETE) {
        gfw_msgs_list *messages = NULL;
        gfw_status_to_strings(maj_stat, min_stat, &messages) ;
        strcat(logmessage, " : ");
        strcat(logmessage, messages->msg);
        while (messages != NULL) {
            syslog(BBFTPD_ERR,"gfw_accept_sec_context failed: %s", messages->msg) ;
            messages = messages->next;
        }
        reply(MSG_BAD_NO_RETRY,logmessage) ;
        return -1;
	}
	
    syslog(BBFTPD_INFO,"Checked certificate : \"%s\"",(char *)client_name.value) ;
	/*
	** Map cert with local user
	*/
	if (globus_gss_assist_gridmap((char *)client_name.value, &username) != 0) {
        syslog(BBFTPD_ERR,"mapping failed for: %s",(char *)client_name.value) ;
		strcat(logmessage, " : grid mapping failed");
        reply(MSG_BAD_NO_RETRY,logmessage) ;
        return -1 ;
	}
	syslog(BBFTPD_INFO, "Mapfile user is:%s", username);
    /*
    ** Here we check the username and pass and set the default dir
    */
    if ( (uspass = getpwnam(username)) == NULL ) {
        syslog(BBFTPD_ERR,"%s is not a local user",username) ;
        strcat(logmessage," : You need an account on the server") ;
        reply(MSG_BAD_NO_RETRY,logmessage) ;
        return -1 ;
    }
    /*
    ** Set the uid and gid of the process
    */
    if ( setgid(uspass->pw_gid) < 0 ) {
        syslog(BBFTPD_ERR,"Error setgid user %s : %s",username,strerror(errno)) ;
        strcat(logmessage," : Cannot set gid: ") ;
	strcat(logmessage,strerror(errno));
        reply(MSG_BAD,logmessage) ;
        return -1 ;
    }
    if ( setuid(uspass->pw_uid) < 0 ) {
        syslog(BBFTPD_ERR,"Error setuid user %s : %s",username,strerror(errno)) ;
        strcat(logmessage," : Cannot set uid: ") ;
	strcat(logmessage,strerror(errno));
        reply(MSG_BAD,logmessage) ;
        return -1 ;
    }
    if ( uspass->pw_dir == NULL ) {
        syslog(BBFTPD_ERR,"No home directory for user %s : %s",username,strerror(errno)) ;
        strcat(logmessage," : You need a home directory on the server") ;
        reply(MSG_BAD,logmessage) ;
        return -1 ;
    }
    /*
    ** Try to cd into home directory. If permission denied (ie no AFS token)
    ** try to cd into "/tmp"
    */
    if ( chdir(uspass->pw_dir) < 0) {
        if ( errno == EACCES) {
            syslog(BBFTPD_WARNING,"Permission denied on user %s home directory: using /tmp",username) ;
            if ( chdir("/tmp") < 0) {
                syslog(BBFTPD_ERR,"Cannot cd into /tmp: %s",strerror(errno)) ;
                strcat(logmessage," : Cannot access home directory nor /tmp") ;
                reply(MSG_BAD,logmessage) ;
                return -1 ;
            }
            strcat(logmessage," : Home directory not accessible, /tmp used instead") ;
            syslog(BBFTPD_INFO,"User %s connected",username) ;
            strcpy(currentusername,username) ;
            reply(MSG_WARN,logmessage) ;
            return 1 ;
        } else {
            syslog(BBFTPD_ERR,"Cannot cd into user %s home directory: %s",username,strerror(errno)) ;
            strcat(logmessage," : Cannot access home directory: ") ;
	    strcat(logmessage,strerror(errno));
            reply(MSG_BAD,logmessage) ;
            return -1 ;
        }
    }
                
    syslog(BBFTPD_INFO,"User %s connected",username) ;
    strcpy(currentusername,username) ;
    return 0 ;
}



syntax highlighted by Code2HTML, v. 0.9.1