From cb757820f5452d192ce3b1eeb4f19a17ee93c3fe Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 16 Jun 1998 01:35:52 +0000 Subject: Added SSL support from Christian Starkjohann This patch may not yet compile with -DUSE_SSL enabled, further Makefile changes may be needed. But it was important to get this code in place before I go off to USENIX. Jeremy. (This used to be commit 31e768369fdc61e07c59630c86c62239f3d3f3f7) --- source3/client/client.c | 4 + source3/client/clientutil.c | 13 +++ source3/include/proto.h | 14 +++ source3/include/smb.h | 4 + source3/lib/util.c | 80 ++++++++++--- source3/libsmb/clientgen.c | 13 +++ source3/param/loadparm.c | 73 ++++++++++++ source3/smbd/server.c | 25 +++++ source3/smbd/ssl.c | 266 ++++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 476 insertions(+), 16 deletions(-) create mode 100644 source3/smbd/ssl.c (limited to 'source3') 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 +#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 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 +#include + +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 */ -- cgit