add WITH_SENDFILE profiling data (from Pierre Belanger)
[Samba.git] / source / smbd / ssl.c
blob349ca34f9599752cf6b137aaec9e3367b5dbee3a
1 /*
2 Unix SMB/Netbios implementation.
3 Version 1.9.
4 SSLeay utility functions
5 Copyright (C) Christian Starkjohann <cs@obdev.at> 1998
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 /*
23 * since includes.h pulls in config.h which is were WITH_SSL will be
24 * defined, we want to include includes.h before testing for WITH_SSL
25 * RJS 26-Jan-1999
28 #include "includes.h"
30 #ifdef WITH_SSL /* should always be defined if this module is compiled */
32 #include <openssl/ssl.h>
33 #include <openssl/err.h>
35 BOOL sslEnabled;
36 SSL *ssl = NULL;
37 int sslFd = -1;
38 static SSL_CTX *sslContext = NULL;
39 extern int DEBUGLEVEL;
41 static int ssl_verify_cb(int ok, X509_STORE_CTX *ctx)
43 char buffer[256];
45 X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert),
46 buffer, sizeof(buffer));
47 if(ok){
48 DEBUG(0, ("SSL: Certificate OK: %s\n", buffer));
49 }else{
50 switch (ctx->error){
51 case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
52 DEBUG(0, ("SSL: Cert error: CA not known: %s\n", buffer));
53 break;
54 case X509_V_ERR_CERT_NOT_YET_VALID:
55 DEBUG(0, ("SSL: Cert error: Cert not yet valid: %s\n", buffer));
56 break;
57 case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
58 DEBUG(0, ("SSL: Cert error: illegal \'not before\' field: %s\n",
59 buffer));
60 break;
61 case X509_V_ERR_CERT_HAS_EXPIRED:
62 DEBUG(0, ("SSL: Cert error: Cert expired: %s\n", buffer));
63 break;
64 case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
65 DEBUG(0, ("SSL: Cert error: invalid \'not after\' field: %s\n",
66 buffer));
67 break;
68 default:
69 DEBUG(0, ("SSL: Cert error: unknown error %d in %s\n", ctx->error,
70 buffer));
71 break;
74 return ok;
77 static RSA *ssl_temp_rsa_cb(SSL *ssl, int is_export, int keylength)
79 static RSA *rsa = NULL;
81 if(rsa == NULL)
82 rsa = RSA_generate_key(keylength, RSA_F4, NULL, NULL);
83 return rsa;
86 /* This is called before we fork. It should ask the user for the pass phrase
87 * if necessary. Error output can still go to stderr because the process
88 * has a terminal.
90 int sslutil_init(int isServer)
92 int err, entropybytes;
93 char *certfile, *keyfile, *ciphers, *cacertDir, *cacertFile;
94 char *egdsocket, *entropyfile;
96 SSL_load_error_strings();
97 SSLeay_add_ssl_algorithms();
98 egdsocket = lp_ssl_egdsocket();
99 if (egdsocket != NULL && *egdsocket != 0)
100 RAND_egd(egdsocket);
101 entropyfile = lp_ssl_entropyfile();
102 entropybytes = lp_ssl_entropybytes();
103 if (entropyfile != NULL && *entropyfile != 0)
104 RAND_load_file(entropyfile, entropybytes);
105 switch(lp_ssl_version()){
106 case SMB_SSL_V2: sslContext = SSL_CTX_new(SSLv2_method()); break;
107 case SMB_SSL_V3: sslContext = SSL_CTX_new(SSLv3_method()); break;
108 default:
109 case SMB_SSL_V23: sslContext = SSL_CTX_new(SSLv23_method()); break;
110 case SMB_SSL_TLS1: sslContext = SSL_CTX_new(TLSv1_method()); break;
112 if(sslContext == NULL){
113 err = ERR_get_error();
114 fprintf(stderr, "SSL: Error allocating context: %s\n",
115 ERR_error_string(err, NULL));
116 exit(1);
118 if(lp_ssl_compatibility()){
119 SSL_CTX_set_options(sslContext, SSL_OP_ALL);
121 certfile = isServer ? lp_ssl_server_cert() : lp_ssl_client_cert();
122 if((certfile == NULL || *certfile == 0) && isServer){
123 fprintf(stderr, "SSL: No cert file specified in config file!\n");
124 fprintf(stderr, "The server MUST have a certificate!\n");
125 exit(1);
127 keyfile = isServer ? lp_ssl_server_privkey() : lp_ssl_client_privkey();
128 if(keyfile == NULL || *keyfile == 0)
129 keyfile = certfile;
130 if(certfile != NULL && *certfile != 0){
131 if(!SSL_CTX_use_certificate_chain_file(sslContext, certfile)){
132 err = ERR_get_error();
133 fprintf(stderr, "SSL: error reading certificate from file %s: %s\n",
134 certfile, ERR_error_string(err, NULL));
135 exit(1);
137 if(!SSL_CTX_use_PrivateKey_file(sslContext, keyfile, SSL_FILETYPE_PEM)){
138 err = ERR_get_error();
139 fprintf(stderr, "SSL: error reading private key from file %s: %s\n",
140 keyfile, ERR_error_string(err, NULL));
141 exit(1);
143 if(!SSL_CTX_check_private_key(sslContext)){
144 err = ERR_get_error();
145 fprintf(stderr, "SSL: Private key does not match public key in cert!\n");
146 exit(1);
149 cacertDir = lp_ssl_cacertdir();
150 cacertFile = lp_ssl_cacertfile();
151 if(cacertDir != NULL && *cacertDir == 0)
152 cacertDir = NULL;
153 if(cacertFile != NULL && *cacertFile == 0)
154 cacertFile = NULL;
155 if(!SSL_CTX_load_verify_locations(sslContext, cacertFile, cacertDir)){
156 err = ERR_get_error();
157 if (cacertFile || cacertDir) {
158 fprintf(stderr, "SSL: Error error setting CA cert locations: %s\n",
159 ERR_error_string(err, NULL));
160 fprintf(stderr, "trying default locations.\n");
162 cacertFile = cacertDir = NULL;
163 if(!SSL_CTX_set_default_verify_paths(sslContext)){
164 err = ERR_get_error();
165 fprintf(stderr, "SSL: Error error setting default CA cert location: %s\n",
166 ERR_error_string(err, NULL));
167 exit(1);
170 SSL_CTX_set_tmp_rsa_callback(sslContext, ssl_temp_rsa_cb);
171 if((ciphers = lp_ssl_ciphers()) != NULL && *ciphers != 0)
172 SSL_CTX_set_cipher_list(sslContext, ciphers);
173 if((isServer && lp_ssl_reqClientCert()) || (!isServer && lp_ssl_reqServerCert())){
174 SSL_CTX_set_verify(sslContext,
175 SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, ssl_verify_cb);
176 }else{
177 SSL_CTX_set_verify(sslContext, SSL_VERIFY_NONE, ssl_verify_cb);
179 #if 1 /* don't know what this is good for, but s_server in SSLeay does it, too */
180 if(isServer){
181 SSL_CTX_set_client_CA_list(sslContext, SSL_load_client_CA_file(certfile));
183 #endif
184 return 0;
187 int sslutil_accept(int fd)
189 int err;
191 if(ssl != NULL){
192 DEBUG(0, ("SSL: internal error: more than one SSL connection (server)\n"));
193 return -1;
195 if((ssl = SSL_new(sslContext)) == NULL){
196 err = ERR_get_error();
197 DEBUG(0, ("SSL: Error allocating handle: %s\n",
198 ERR_error_string(err, NULL)));
199 return -1;
201 SSL_set_fd(ssl, fd);
202 sslFd = fd;
203 if(SSL_accept(ssl) <= 0){
204 err = ERR_get_error();
205 DEBUG(0, ("SSL: Error accepting on socket: %s\n",
206 ERR_error_string(err, NULL)));
207 return -1;
209 DEBUG(0, ("SSL: negotiated cipher: %s\n", SSL_get_cipher(ssl)));
210 return 0;
213 int sslutil_fd_is_ssl(int fd)
215 return fd == sslFd;
218 int sslutil_connect(int fd)
220 int err;
222 if(ssl != NULL){
223 DEBUG(0, ("SSL: internal error: more than one SSL connection (client)\n"));
224 return -1;
226 if((ssl = SSL_new(sslContext)) == NULL){
227 err = ERR_get_error();
228 DEBUG(0, ("SSL: Error allocating handle: %s\n",
229 ERR_error_string(err, NULL)));
230 return -1;
232 SSL_set_fd(ssl, fd);
233 sslFd = fd;
234 if(SSL_connect(ssl) <= 0){
235 err = ERR_get_error();
236 DEBUG(0, ("SSL: Error conencting socket: %s\n",
237 ERR_error_string(err, NULL)));
238 return -1;
240 DEBUG(0, ("SSL: negotiated cipher: %s\n", SSL_get_cipher(ssl)));
241 return 0;
244 int sslutil_disconnect(int fd)
246 if(fd == sslFd && ssl != NULL){
247 SSL_free(ssl);
248 ssl = NULL;
249 sslFd = -1;
251 return 0;
254 int sslutil_negotiate_ssl(int fd, int msg_type)
256 unsigned char buf[5] = {0x83, 0, 0, 1, 0x81};
257 char *reqHosts, *resignHosts;
259 reqHosts = lp_ssl_hosts();
260 resignHosts = lp_ssl_hosts_resign();
261 if(!allow_access(resignHosts, reqHosts, get_socket_name(fd), get_socket_addr(fd))){
262 sslEnabled = False;
263 return 0;
265 if(msg_type != 0x81){ /* first packet must be a session request */
266 DEBUG( 0, ( "Client %s did not use session setup; access denied\n",
267 client_addr() ) );
268 if (!send_smb(fd, (char *)buf))
269 DEBUG(0, ("sslutil_negotiate_ssl: send_smb failed.\n"));
270 return -1;
272 buf[4] = 0x8e; /* negative session response: use SSL */
273 if (!send_smb(fd, (char *)buf)) {
274 DEBUG(0,("sslutil_negotiate_ssl: send_smb failed.\n"));
275 return -1;
277 if(sslutil_accept(fd) != 0){
278 DEBUG( 0, ( "Client %s failed SSL negotiation!\n", client_addr() ) );
279 return -1;
281 return 1;
284 #else /* WITH_SSL */
285 void ssl_dummy(void);
286 void ssl_dummy(void) {;} /* So some compilers don't complain. */
287 #endif /* WITH_SSL */