summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/client/client.c4
-rw-r--r--source3/client/clientutil.c13
-rw-r--r--source3/include/proto.h14
-rw-r--r--source3/include/smb.h4
-rw-r--r--source3/lib/util.c80
-rw-r--r--source3/libsmb/clientgen.c13
-rw-r--r--source3/param/loadparm.c73
-rw-r--r--source3/smbd/server.c25
-rw-r--r--source3/smbd/ssl.c266
9 files changed, 476 insertions, 16 deletions
diff --git a/source3/client/client.c b/source3/client/client.c
index c48c5500cd..bdfa29f86b 100644
--- a/source3/client/client.c
+++ b/source3/client/client.c
@@ -3588,6 +3588,10 @@ static void usage(char *pname)
interpret_coding_system(term_code);
+#ifdef USE_SSL
+ sslutil_init(0);
+#endif
+
pstrcpy(workgroup,lp_workgroup());
load_interfaces();
diff --git a/source3/client/clientutil.c b/source3/client/clientutil.c
index 0c60ac0109..e63f668481 100644
--- a/source3/client/clientutil.c
+++ b/source3/client/clientutil.c
@@ -338,6 +338,10 @@ BOOL cli_send_session_request(char *inbuf,char *outbuf)
_smb_setlen(outbuf,len);
CVAL(outbuf,0) = 0x81;
+#ifdef USE_SSL
+retry:
+#endif /* USE_SSL */
+
send_smb(Client,outbuf);
DEBUG(5,("Sent session request\n"));
@@ -373,6 +377,15 @@ BOOL cli_send_session_request(char *inbuf,char *outbuf)
return cli_send_session_request(inbuf,outbuf);
} /* C. Hoch 9/14/95 End */
+#ifdef USE_SSL
+ if(CVAL(inbuf,0) == 0x83 && CVAL(inbuf,4) == 0x8e) { /* use ssl */
+ fprintf(stderr, "Making secure connection\n");
+ if(!sslutil_fd_is_ssl(Client)){
+ if(sslutil_connect(Client) == 0)
+ goto retry;
+ }
+ }
+#endif
if (CVAL(inbuf,0) != 0x82)
{
diff --git a/source3/include/proto.h b/source3/include/proto.h
index 5ff9df5a5f..1758301ef4 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -976,6 +976,20 @@ char *lp_ldap_suffix(void);
char *lp_ldap_filter(void);
char *lp_ldap_root(void);
char *lp_ldap_rootpasswd(void);
+int lp_ssl_version(void);
+char *lp_ssl_hosts(void);
+char *lp_ssl_hosts_resign(void);
+char *lp_ssl_cacertdir(void);
+char *lp_ssl_cacertfile(void);
+char *lp_ssl_cert(void);
+char *lp_ssl_privkey(void);
+char *lp_ssl_client_cert(void);
+char *lp_ssl_client_privkey(void);
+char *lp_ssl_ciphers(void);
+BOOL lp_ssl_enabled(void);
+BOOL lp_ssl_reqClientCert(void);
+BOOL lp_ssl_reqServerCert(void);
+BOOL lp_ssl_compatibility(void);
BOOL lp_dns_proxy(void);
BOOL lp_wins_support(void);
BOOL lp_we_are_a_wins_server(void);
diff --git a/source3/include/smb.h b/source3/include/smb.h
index 085c06769b..a5571d3645 100644
--- a/source3/include/smb.h
+++ b/source3/include/smb.h
@@ -1290,6 +1290,10 @@ enum remote_arch_types {RA_UNKNOWN, RA_WFWG, RA_OS2, RA_WIN95, RA_WINNT, RA_SAMB
/* case handling */
enum case_handling {CASE_LOWER,CASE_UPPER};
+#ifdef USE_SSL
+/* SSL version options */
+enum ssl_version_enum {SMB_SSL_V2,SMB_SSL_V3,SMB_SSL_V23,SMB_SSL_TLS1};
+#endif /* USE_SSL */
/* Macros to get at offsets within smb_lkrng and smb_unlkrng
structures. We cannot define these as actual structures
diff --git a/source3/lib/util.c b/source3/lib/util.c
index e53870bf9c..750ca0f3ab 100644
--- a/source3/lib/util.c
+++ b/source3/lib/util.c
@@ -29,6 +29,13 @@
#endif
#endif
+#ifdef USE_SSL
+#include <ssl.h>
+#undef Realloc /* SSLeay defines this and samba has a function of this name */
+extern SSL *ssl;
+extern int sslFd;
+#endif /* USE_SSL */
+
pstring scope = "";
int DEBUGLEVEL = 1;
@@ -639,6 +646,10 @@ void set_socket_options(int fd, char *options)
****************************************************************************/
void close_sockets(void )
{
+#ifdef USE_SSL
+ sslutil_disconnect(Client);
+#endif /* USE_SSL */
+
close(Client);
Client = 0;
}
@@ -2137,7 +2148,16 @@ int read_with_timeout(int fd,char *buf,int mincnt,int maxcnt,long time_out)
if (mincnt == 0) mincnt = maxcnt;
while (nread < mincnt) {
+#ifdef USE_SSL
+ if(fd == sslFd){
+ readret = SSL_read(ssl, buf + nread, maxcnt - nread);
+ }else{
+ readret = read(fd, buf + nread, maxcnt - nread);
+ }
+#else /* USE_SSL */
readret = read(fd, buf + nread, maxcnt - nread);
+#endif /* USE_SSL */
+
if (readret == 0) {
smb_read_error = READ_EOF;
return -1;
@@ -2182,7 +2202,16 @@ int read_with_timeout(int fd,char *buf,int mincnt,int maxcnt,long time_out)
return -1;
}
- readret = read(fd, buf+nread, maxcnt-nread);
+#ifdef USE_SSL
+ if(fd == sslFd){
+ readret = SSL_read(ssl, buf + nread, maxcnt - nread);
+ }else{
+ readret = read(fd, buf + nread, maxcnt - nread);
+ }
+#else /* USE_SSL */
+ readret = read(fd, buf+nread, maxcnt-nread);
+#endif /* USE_SSL */
+
if (readret == 0) {
/* we got EOF on the file descriptor */
smb_read_error = READ_EOF;
@@ -2265,18 +2294,29 @@ int read_data(int fd,char *buffer,int N)
smb_read_error = 0;
while (total < N)
- {
+ {
+#ifdef USE_SSL
+ if(fd == sslFd){
+ ret = SSL_read(ssl, buffer + total, N - total);
+ }else{
ret = read(fd,buffer + total,N - total);
- if (ret == 0) {
- smb_read_error = READ_EOF;
- return 0;
- }
- if (ret == -1) {
- smb_read_error = READ_ERROR;
- return -1;
- }
- total += ret;
}
+#else /* USE_SSL */
+ ret = read(fd,buffer + total,N - total);
+#endif /* USE_SSL */
+
+ if (ret == 0)
+ {
+ smb_read_error = READ_EOF;
+ return 0;
+ }
+ if (ret == -1)
+ {
+ smb_read_error = READ_ERROR;
+ return -1;
+ }
+ total += ret;
+ }
return total;
}
@@ -2290,14 +2330,22 @@ int write_data(int fd,char *buffer,int N)
int ret;
while (total < N)
- {
+ {
+#ifdef USE_SSL
+ if(fd == sslFd){
+ ret = SSL_write(ssl,buffer + total,N - total);
+ }else{
ret = write(fd,buffer + total,N - total);
+ }
+#else /* USE_SSL */
+ ret = write(fd,buffer + total,N - total);
+#endif /* USE_SSL */
- if (ret == -1) return -1;
- if (ret == 0) return total;
+ if (ret == -1) return -1;
+ if (ret == 0) return total;
- total += ret;
- }
+ total += ret;
+ }
return total;
}
diff --git a/source3/libsmb/clientgen.c b/source3/libsmb/clientgen.c
index 9dfd482da3..68bd369606 100644
--- a/source3/libsmb/clientgen.c
+++ b/source3/libsmb/clientgen.c
@@ -1633,12 +1633,25 @@ BOOL cli_session_request(struct cli_state *cli, char *host, int name_type,
_smb_setlen(cli->outbuf,len);
CVAL(cli->outbuf,0) = 0x81;
+#ifdef USE_SSL
+retry:
+#endif /* USE_SSL */
+
send_smb(cli->fd,cli->outbuf);
DEBUG(5,("Sent session request\n"));
if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout))
return False;
+#ifdef USE_SSL
+ if(CVAL(cli->inbuf,0) == 0x83 && CVAL(cli->inbuf,4) == 0x8e){ /* use ssl */
+ if(!sslutil_fd_is_ssl(cli->fd)){
+ if(sslutil_connect(cli->fd) == 0)
+ goto retry;
+ }
+ }
+#endif /* USE_SSL */
+
if (CVAL(cli->inbuf,0) != 0x82) {
/* This is the wrong place to put the error... JRA. */
cli->rap_error = CVAL(cli->inbuf,0);
diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c
index cf41a75500..2122541000 100644
--- a/source3/param/loadparm.c
+++ b/source3/param/loadparm.c
@@ -179,6 +179,22 @@ typedef struct
#ifdef USE_LDAP
int ldap_port;
#endif /* USE_LDAP */
+#ifdef USE_SSL
+ int sslVersion;
+ char *sslHostsRequire;
+ char *sslHostsResign;
+ char *sslCaCertDir;
+ char *sslCaCertFile;
+ char *sslCert;
+ char *sslPrivKey;
+ char *sslClientCert;
+ char *sslClientPrivKey;
+ char *sslCiphers;
+ BOOL sslEnabled;
+ BOOL sslReqClientCert;
+ BOOL sslReqServerCert;
+ BOOL sslCompatibility;
+#endif /* USE_SSL */
BOOL bDNSproxy;
BOOL bWINSsupport;
BOOL bWINSproxy;
@@ -432,6 +448,11 @@ static struct enum_list enum_case[] = {{CASE_LOWER, "lower"}, {CASE_UPPER, "uppe
static struct enum_list enum_lm_announce[] = {{0, "False"}, {1, "True"}, {2, "Auto"}, {-1, NULL}};
+#ifdef USE_SSL
+static struct enum_list enum_ssl_version[] = {{SMB_SSL_V2, "ssl2"}, {SMB_SSL_V3, "ssl3"}
+ {SMB_SSL_V23, "ssl2or3"}, {SMB_SSL_TLS1, "tls1"}, {-1, NULL}};
+#endif
+
/* note that we do not initialise the defaults union - it is not allowed in ANSI C */
static struct parm_struct parm_table[] =
{
@@ -499,6 +520,24 @@ static struct parm_struct parm_table[] =
{"hosts deny", P_STRING, P_LOCAL, &sDefault.szHostsdeny, NULL, NULL, FLAG_GLOBAL|FLAG_BASIC|FLAG_PRINT},
{"deny hosts", P_STRING, P_LOCAL, &sDefault.szHostsdeny, NULL, NULL, 0},
+#ifdef USE_SSL
+ {"Secure Socket Layer Options", P_SEP, P_SEPARATOR},
+ {"ssl", P_BOOL, P_GLOBAL, &Globals.sslEnabled, NULL, NULL, 0 },
+ {"ssl hosts", P_STRING, P_GLOBAL, &Globals.sslHostsRequire, NULL, NULL, 0 },
+ {"ssl hosts resign", P_STRING, P_GLOBAL, &Globals.sslHostsResign, NULL, NULL, 0} ,
+ {"ssl CA certDir", P_STRING, P_GLOBAL, &Globals.sslCaCertDir, NULL, NULL, 0 },
+ {"ssl CA certFile", P_STRING, P_GLOBAL, &Globals.sslCaCertFile, NULL, NULL, 0 },
+ {"ssl server cert", P_STRING, P_GLOBAL, &Globals.sslCert, NULL, NULL, 0 },
+ {"ssl server key", P_STRING, P_GLOBAL, &Globals.sslPrivKey, NULL, NULL, 0 },
+ {"ssl client cert", P_STRING, P_GLOBAL, &Globals.sslClientCert, NULL, NULL, 0 },
+ {"ssl client key", P_STRING, P_GLOBAL, &Globals.sslClientPrivKey, NULL, NULL, 0 },
+ {"ssl require clientcert", P_BOOL, P_GLOBAL, &Globals.sslReqClientCert, NULL, NULL , 0},
+ {"ssl require servercert", P_BOOL, P_GLOBAL, &Globals.sslReqServerCert, NULL, NULL , 0},
+ {"ssl ciphers", P_STRING, P_GLOBAL, &Globals.sslCiphers, NULL, NULL, 0 },
+ {"ssl version", P_ENUM, P_GLOBAL, &Globals.sslVersion, NULL, enum_ssl_version, 0},
+ {"ssl compatibility", P_BOOL, P_GLOBAL, &Globals.sslCompatibility, NULL, NULL, 0 },
+#endif /* USE_SSL */
+
{"Logging Options", P_SEP, P_SEPARATOR},
{"log level", P_INTEGER, P_GLOBAL, &DEBUGLEVEL, NULL, NULL, FLAG_BASIC},
{"debuglevel", P_INTEGER, P_GLOBAL, &DEBUGLEVEL, NULL, NULL, 0},
@@ -790,6 +829,23 @@ static void init_globals(void)
Globals.ldap_port=389;
#endif /* USE_LDAP */
+#ifdef USE_SSL
+ Globals.sslVersion = SMB_SSL_V23;
+ Globals.sslHostsRequire = NULL;
+ Globals.sslHostsResign = NULL;
+ Globals.sslCaCertDir = NULL;
+ Globals.sslCaCertFile = NULL;
+ Globals.sslCert = NULL;
+ Globals.sslPrivKey = NULL;
+ Globals.sslClientCert = NULL;
+ Globals.sslClientPrivKey = NULL;
+ Globals.sslCiphers = NULL;
+ Globals.sslEnabled = False;
+ Globals.sslReqClientCert = False;
+ Globals.sslReqServerCert = False;
+ Globals.sslCompatibility = False;
+#endif /* USE_SSL */
+
/* these parameters are set to defaults that are more appropriate
for the increasing samba install base:
@@ -1003,6 +1059,23 @@ FN_GLOBAL_STRING(lp_ldap_root,&Globals.szLdapRoot);
FN_GLOBAL_STRING(lp_ldap_rootpasswd,&Globals.szLdapRootPassword);
#endif /* USE_LDAP */
+#ifdef USE_SSL
+FN_GLOBAL_INTEGER(lp_ssl_version,&Globals.sslVersion);
+FN_GLOBAL_STRING(lp_ssl_hosts,&Globals.sslHostsRequire);
+FN_GLOBAL_STRING(lp_ssl_hosts_resign,&Globals.sslHostsResign);
+FN_GLOBAL_STRING(lp_ssl_cacertdir,&Globals.sslCaCertDir);
+FN_GLOBAL_STRING(lp_ssl_cacertfile,&Globals.sslCaCertFile);
+FN_GLOBAL_STRING(lp_ssl_cert,&Globals.sslCert);
+FN_GLOBAL_STRING(lp_ssl_privkey,&Globals.sslPrivKey);
+FN_GLOBAL_STRING(lp_ssl_client_cert,&Globals.sslClientCert);
+FN_GLOBAL_STRING(lp_ssl_client_privkey,&Globals.sslClientPrivKey);
+FN_GLOBAL_STRING(lp_ssl_ciphers,&Globals.sslCiphers);
+FN_GLOBAL_BOOL(lp_ssl_enabled,&Globals.sslEnabled);
+FN_GLOBAL_BOOL(lp_ssl_reqClientCert,&Globals.sslReqClientCert);
+FN_GLOBAL_BOOL(lp_ssl_reqServerCert,&Globals.sslReqServerCert);
+FN_GLOBAL_BOOL(lp_ssl_compatibility,&Globals.sslCompatibility);
+#endif /* USE_SSL */
+
FN_GLOBAL_BOOL(lp_dns_proxy,&Globals.bDNSproxy)
FN_GLOBAL_BOOL(lp_wins_support,&Globals.bWINSsupport)
FN_GLOBAL_BOOL(lp_we_are_a_wins_server,&Globals.bWINSsupport)
diff --git a/source3/smbd/server.c b/source3/smbd/server.c
index 25ec11abaa..45a63a544a 100644
--- a/source3/smbd/server.c
+++ b/source3/smbd/server.c
@@ -2810,6 +2810,10 @@ max can be %d\n", num_interfaces, FD_SETSIZE));
static void process_smb(char *inbuf, char *outbuf)
{
extern int Client;
+#ifdef USE_SSL
+ extern BOOL sslEnabled; /* don't use function for performance reasons */
+ static int sslConnected = 0;
+#endif /* USE_SSL */
static int trans_num;
int msg_type = CVAL(inbuf,0);
int32 len = smb_len(inbuf);
@@ -2834,6 +2838,18 @@ static void process_smb(char *inbuf, char *outbuf)
DEBUG(6,("got message type 0x%x of len 0x%x\n",msg_type,len));
DEBUG(3,("%s Transaction %d of length %d\n",timestring(),trans_num,nread));
+#ifdef USE_SSL
+ if(sslEnabled && !sslConnected){
+ sslConnected = sslutil_negotiate_ssl(Client, msg_type);
+ if(sslConnected < 0){ /* an error occured */
+ exit_server("SSL negotiation failed");
+ }else if(sslConnected){
+ trans_num++;
+ return;
+ }
+ }
+#endif /* USE_SSL */
+
#ifdef WITH_VTP
if(trans_num == 1 && VT_Check(inbuf))
{
@@ -5425,6 +5441,15 @@ static void usage(char *pname)
if (!reload_services(False))
return(-1);
+#ifdef USE_SSL
+ {
+ extern BOOL sslEnabled;
+ sslEnabled = lp_ssl_enabled();
+ if(sslEnabled)
+ sslutil_init(True);
+ }
+#endif /* USE_SSL */
+
codepage_initialise(lp_client_code_page());
pstrcpy(global_myworkgroup, lp_workgroup());
diff --git a/source3/smbd/ssl.c b/source3/smbd/ssl.c
new file mode 100644
index 0000000000..1bb89f05b1
--- /dev/null
+++ b/source3/smbd/ssl.c
@@ -0,0 +1,266 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ SSLeay utility functions
+ Copyright (C) Christian Starkjohann <cs@obdev.at> 1998
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifdef USE_SSL /* should always be defined if this module is compiled */
+
+#include "includes.h"
+#include <ssl.h>
+#include <err.h>
+
+BOOL sslEnabled;
+SSL *ssl = NULL;
+int sslFd = -1;
+static SSL_CTX *sslContext = NULL;
+extern int DEBUGLEVEL;
+
+static int ssl_verify_cb(int ok, X509_STORE_CTX *ctx)
+{
+char buffer[256];
+
+ X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert),
+ buffer, sizeof(buffer));
+ if(ok){
+ DEBUG(0, ("SSL: Certificate OK: %s\n", buffer));
+ }else{
+ switch (ctx->error){
+ case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
+ DEBUG(0, ("SSL: Cert error: CA not known: %s\n", buffer));
+ break;
+ case X509_V_ERR_CERT_NOT_YET_VALID:
+ DEBUG(0, ("SSL: Cert error: Cert not yet valid: %s\n", buffer));
+ break;
+ case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
+ DEBUG(0, ("SSL: Cert error: illegal \'not before\' field: %s\n",
+ buffer));
+ break;
+ case X509_V_ERR_CERT_HAS_EXPIRED:
+ DEBUG(0, ("SSL: Cert error: Cert expired: %s\n", buffer));
+ break;
+ case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
+ DEBUG(0, ("SSL: Cert error: invalid \'not after\' field: %s\n",
+ buffer));
+ break;
+ default:
+ DEBUG(0, ("SSL: Cert error: unknown error %d in %s\n", ctx->error,
+ buffer));
+ break;
+ }
+ }
+ return ok;
+}
+
+static RSA *ssl_temp_rsa_cb(SSL *ssl, int export)
+{
+static RSA *rsa = NULL;
+
+ if(rsa == NULL)
+ rsa = RSA_generate_key(512, RSA_F4, NULL, NULL);
+ return rsa;
+}
+
+/* This is called before we fork. It should ask the user for the pass phrase
+ * if necessary. Error output can still go to stderr because the process
+ * has a terminal.
+ */
+int sslutil_init(int isServer)
+{
+int err;
+char *certfile, *keyfile, *ciphers, *cacertDir, *cacertFile;
+
+ SSL_load_error_strings();
+ SSLeay_add_ssl_algorithms();
+ switch(lp_ssl_version()){
+ case SMB_SSL_V2: sslContext = SSL_CTX_new(SSLv2_method()); break;
+ case SMB_SSL_V3: sslContext = SSL_CTX_new(SSLv3_method()); break;
+ default:
+ case SMB_SSL_V23: sslContext = SSL_CTX_new(SSLv23_method()); break;
+ case SMB_SSL_TLS1: sslContext = SSL_CTX_new(TLSv1_method()); break;
+ }
+ if(sslContext == NULL){
+ err = ERR_get_error();
+ fprintf(stderr, "SSL: Error allocating context: %s\n",
+ ERR_error_string(err, NULL));
+ exit(1);
+ }
+ if(lp_ssl_compatibility()){
+ SSL_CTX_set_options(sslContext, SSL_OP_ALL);
+ }
+ certfile = isServer ? lp_ssl_cert() : lp_ssl_client_cert();
+ if((certfile == NULL || *certfile == 0) && isServer){
+ fprintf(stderr, "SSL: No cert file specified in config file!\n");
+ fprintf(stderr, "The server MUST have a certificate!\n");
+ exit(1);
+ }
+ keyfile = isServer ? lp_ssl_privkey() : lp_ssl_client_privkey();
+ if(keyfile == NULL || *keyfile == 0)
+ keyfile = certfile;
+ if(certfile != NULL && *certfile != 0){
+ if(!SSL_CTX_use_certificate_file(sslContext, certfile, SSL_FILETYPE_PEM)){
+ err = ERR_get_error();
+ fprintf(stderr, "SSL: error reading certificate from file %s: %s\n",
+ certfile, ERR_error_string(err, NULL));
+ exit(1);
+ }
+ if(!SSL_CTX_use_PrivateKey_file(sslContext, keyfile, SSL_FILETYPE_PEM)){
+ err = ERR_get_error();
+ fprintf(stderr, "SSL: error reading private key from file %s: %s\n",
+ keyfile, ERR_error_string(err, NULL));
+ exit(1);
+ }
+ if(!SSL_CTX_check_private_key(sslContext)){
+ err = ERR_get_error();
+ fprintf(stderr, "SSL: Private key does not match public key in cert!\n");
+ exit(1);
+ }
+ }
+ cacertDir = lp_ssl_cacertdir();
+ cacertFile = lp_ssl_cacertfile();
+ if(cacertDir != NULL && *cacertDir == 0)
+ cacertDir = NULL;
+ if(cacertFile != NULL && *cacertFile == 0)
+ cacertFile = NULL;
+ if(!SSL_CTX_load_verify_locations(sslContext, cacertFile, cacertDir)){
+ err = ERR_get_error();
+ fprintf(stderr, "SSL: Error error setting CA cert locations: %s\n",
+ ERR_error_string(err, NULL));
+ fprintf(stderr, "trying default locations.\n");
+ cacertFile = cacertDir = NULL;
+ if(!SSL_CTX_set_default_verify_paths(sslContext)){
+ err = ERR_get_error();
+ fprintf(stderr, "SSL: Error error setting default CA cert location: %s\n",
+ ERR_error_string(err, NULL));
+ exit(1);
+ }
+ }
+ SSL_CTX_set_tmp_rsa_callback(sslContext, ssl_temp_rsa_cb);
+ if((ciphers = lp_ssl_ciphers()) != NULL && *ciphers != 0)
+ SSL_CTX_set_cipher_list(sslContext, ciphers);
+ if((isServer && lp_ssl_reqClientCert()) || (!isServer && lp_ssl_reqServerCert())){
+ SSL_CTX_set_verify(sslContext,
+ SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, ssl_verify_cb);
+ }else{
+ SSL_CTX_set_verify(sslContext, SSL_VERIFY_NONE, ssl_verify_cb);
+ }
+#if 1 /* don't know what this is good for, but s_server in SSLeay does it, too */
+ if(isServer){
+ SSL_CTX_set_client_CA_list(sslContext, SSL_load_client_CA_file(certfile));
+ }
+#endif
+ return 0;
+}
+
+int sslutil_accept(int fd)
+{
+int err;
+
+ if(ssl != NULL){
+ DEBUG(0, ("SSL: internal error: more than one SSL connection (server)\n"));
+ return -1;
+ }
+ if((ssl = SSL_new(sslContext)) == NULL){
+ err = ERR_get_error();
+ DEBUG(0, ("SSL: Error allocating handle: %s\n",
+ ERR_error_string(err, NULL)));
+ return -1;
+ }
+ SSL_set_fd(ssl, fd);
+ sslFd = fd;
+ if(SSL_accept(ssl) <= 0){
+ err = ERR_get_error();
+ DEBUG(0, ("SSL: Error accepting on socket: %s\n",
+ ERR_error_string(err, NULL)));
+ return -1;
+ }
+ DEBUG(0, ("SSL: negotiated cipher: %s\n", SSL_get_cipher(ssl)));
+ return 0;
+}
+
+int sslutil_fd_is_ssl(int fd)
+{
+ return fd == sslFd;
+}
+
+int sslutil_connect(int fd)
+{
+int err;
+
+ if(ssl != NULL){
+ DEBUG(0, ("SSL: internal error: more than one SSL connection (client)\n"));
+ return -1;
+ }
+ if((ssl = SSL_new(sslContext)) == NULL){
+ err = ERR_get_error();
+ DEBUG(0, ("SSL: Error allocating handle: %s\n",
+ ERR_error_string(err, NULL)));
+ return -1;
+ }
+ SSL_set_fd(ssl, fd);
+ sslFd = fd;
+ if(SSL_connect(ssl) <= 0){
+ err = ERR_get_error();
+ DEBUG(0, ("SSL: Error conencting socket: %s\n",
+ ERR_error_string(err, NULL)));
+ return -1;
+ }
+ DEBUG(0, ("SSL: negotiated cipher: %s\n", SSL_get_cipher(ssl)));
+ return 0;
+}
+
+int sslutil_disconnect(int fd)
+{
+ if(fd == sslFd && ssl != NULL){
+ SSL_free(ssl);
+ ssl = NULL;
+ sslFd = -1;
+ }
+ return 0;
+}
+
+int sslutil_negotiate_ssl(int fd, int msg_type)
+{
+unsigned char buf[5] = {0x83, 0, 0, 1, 0x81};
+char *reqHosts, *resignHosts;
+
+ reqHosts = lp_ssl_hosts();
+ resignHosts = lp_ssl_hosts_resign();
+ if(!allow_access(resignHosts, reqHosts, client_name(fd), client_addr(fd))){
+ sslEnabled = False;
+ return 0;
+ }
+ if(msg_type != 0x81){ /* first packet must be a session request */
+ DEBUG(0, ("%s Client %s did not use session setup; access denied\n",
+ timestring(), client_addr(fd)));
+ send_smb(fd, (char *)buf);
+ return -1;
+ }
+ buf[4] = 0x8e; /* negative session response: use SSL */
+ send_smb(fd, (char *)buf);
+ if(sslutil_accept(fd) != 0){
+ DEBUG(0, ("%s Client %s failed SSL negotiation!\n",
+ timestring(), client_addr(fd)));
+ return -1;
+ }
+ return 1;
+}
+
+#else /* USE_SSL */
+ void ssl_dummy(void) {;} /* So some compilers don't complain. */
+#endif /* USE_SSL */