/*****************************************************************************\
* Copyright (c) 2002 Pelle Johansson.                                         *
* All rights reserved.                                                        *
*                                                                             *
* This file is part of the moftpd package. Use and distribution of            *
* this software is governed by the terms in the file LICENCE, which           *
* should have come with this package.                                         *
\*****************************************************************************/

/* $moftpd: com_security.c 1249 2004-12-09 15:14:38Z morth $ */

#include "system.h"

#include "commands.h"

#include "connection.h"

#ifdef USE_TLS
extern char *sslCertsPath;
#endif

/* Security commands */

int command_auth (connection_t *conn, const char *arg, int expected)
{
  if (!strlen (arg))
  {
    reply (conn, "501 Argument missing.");
    return 0;
  }
  if (conn->authed)
  {
    reply (conn, "534 Can't start encryption when logged in.");
    return 0;
  }
#ifdef USE_TLS
  if (conn->tlsControl)
  {
    reply (conn, "534 Authentication already negotiated.");
    return 0;
  }
  
  if (!strcasecmp (arg, "TLS") || !strcasecmp (arg, "TLC-C"))
  {
    if (!conn->server->tlsCert)
    {
      reply (conn, "534 This server does not allow encryption.");
      return 0;
    }
    
    conn->tlsControl = tls_open (conn->sock, conn->server->tlsOptions, conn->server->tlsCert,
	  conn->server->tlsKey);
    if (!conn->tlsControl)
    {
      reply (conn, "431 TLS initialisation failed.");
      return 0;
    }
    reply (conn, "234 Waiting for TLS handshake.");
    tls_start (conn->tlsControl);
    conn->tlsState = 0;
    conn->pbsz = -1;
    return 0;
  }
#endif
  reply (conn, "504 Unknown authentication method.");
  return 0;
}

int command_adat (connection_t *conn, const char *arg, int expected)
{
  reply (conn, "502 ADAT not yet implemented.");
  return 0;
}

int command_prot (connection_t *conn, const char *arg, int expected)
{
  int lvl;
  
  if (!strlen (arg))
  {
    reply (conn, "501 Argument missing.");
    return 0;
  }
  
  if (conn->dataSock >= 0)
  {
    reply (conn, "503 Can't change protection level with open data socket.");
    return 0;
  }
  
#ifdef USE_TLS
  if (!conn->tlsControl)
#endif
  {
    reply (conn, "536 Need to establish a secure connection first.");
    return 0;
  }
  
  if (conn->pbsz == -1)
  {
    reply (conn, "503 Need to negotiate buffer size first.");
    return 0;
  }
  
  switch (arg[0])
  {
  case 'C':
  case 'c':
    lvl = 0;
    break;
  case 'S':
  case 's':
  case 'E':
  case 'e':
    reply (conn, "536 TLS does not support this protection level.");
    return 0;
  case 'P':
  case 'p':
    lvl = acEncrypted | acSigned;
    break;
  default:
    reply (conn, "504 Unknown protection level.");
    return 0;
  }
  conn->protLevel = lvl;
  reply (conn, "200 Protection level set.");
  return 0;
}

int command_pbsz (connection_t *conn, const char *arg, int expected)
{
  char *ep;
  /*unsigned long l = */strtoul (arg, &ep, 10);
  
  if (!strlen (arg))
  {
    reply (conn, "501 Argument missing.");
    return 0;
  }
  if (ep && *ep)
  {
    reply (conn, "501 Numerical argument expected.");
    return 0;
  }
  
#ifdef USE_TLS
  if (conn->tlsControl)
  {
    conn->pbsz = 0;
    reply (conn, "200 PBSZ=0");
  }
  else
#endif
    reply (conn, "533 Need to establish a secure connection first.");
  return 0;
}

int command_ccc (connection_t *conn, const char *arg, int expected)
{
#ifdef USE_TLS
  if (conn->tlsControl)
  {
    if (!conn->authed || (conn->server->loginTLS && conn->server->tlsNoLogout))
    {
      reply (conn, "534 Won't turn off TLS protection.");
      return 0;
    }
    reply (conn, "200 Shutting down TLS protection.");
    tls_stop (conn->tlsControl);
    conn->tlsState = 2;
  }
  else
#endif
    reply (conn, "533 Need to establish a secure connection first.");
  return 0;
}

int command_mic (connection_t *conn, const char *arg, int expected)
{
  reply (conn, "502 MIC not yet implemented.");
  return 0;
}

int command_conf (connection_t *conn, const char *arg, int expected)
{
  reply (conn, "502 CONF not yet implemented.");
  return 0;
}

int command_enc (connection_t *conn, const char *arg, int expected)
{
  reply (conn, "502 ENC not yet implemented.");
  return 0;
}


syntax highlighted by Code2HTML, v. 0.9.1