merge from the autoconf2 branch to the main branch
[ira/wip.git] / source3 / smbd / ssl.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    SSLeay utility functions
5    Copyright (C) Christian Starkjohann <cs@obdev.at> 1998
6    
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.
11    
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.
16    
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.
20 */
21
22 #ifdef WITH_SSL  /* should always be defined if this module is compiled */
23
24 #include "includes.h"
25 #include <ssl.h>
26 #include <err.h>
27
28 BOOL            sslEnabled;
29 SSL             *ssl = NULL;
30 int             sslFd = -1;
31 static SSL_CTX  *sslContext = NULL;
32 extern int      DEBUGLEVEL;
33
34 static int  ssl_verify_cb(int ok, X509_STORE_CTX *ctx)
35 {
36 char    buffer[256];
37
38     X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert),
39             buffer, sizeof(buffer));
40     if(ok){
41         DEBUG(0, ("SSL: Certificate OK: %s\n", buffer));
42     }else{
43         switch (ctx->error){
44         case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
45             DEBUG(0, ("SSL: Cert error: CA not known: %s\n", buffer));
46             break;
47         case X509_V_ERR_CERT_NOT_YET_VALID:
48             DEBUG(0, ("SSL: Cert error: Cert not yet valid: %s\n", buffer));
49             break;
50         case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
51             DEBUG(0, ("SSL: Cert error: illegal \'not before\' field: %s\n",
52                     buffer));
53             break;
54         case X509_V_ERR_CERT_HAS_EXPIRED:
55             DEBUG(0, ("SSL: Cert error: Cert expired: %s\n", buffer));
56             break;
57         case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
58             DEBUG(0, ("SSL: Cert error: invalid \'not after\' field: %s\n",
59                     buffer));
60             break;
61         default:
62             DEBUG(0, ("SSL: Cert error: unknown error %d in %s\n", ctx->error,
63                     buffer));
64             break;
65         }
66     }
67     return ok;
68 }
69
70 static RSA  *ssl_temp_rsa_cb(SSL *ssl, int export)
71 {
72 static RSA  *rsa = NULL;
73     
74     if(rsa == NULL)
75         rsa = RSA_generate_key(512, RSA_F4, NULL, NULL);
76     return rsa;
77 }
78
79 /* This is called before we fork. It should ask the user for the pass phrase
80  * if necessary. Error output can still go to stderr because the process
81  * has a terminal.
82  */
83 int sslutil_init(int isServer)
84 {
85 int     err;
86 char    *certfile, *keyfile, *ciphers, *cacertDir, *cacertFile;
87
88     SSL_load_error_strings();
89     SSLeay_add_ssl_algorithms();
90     switch(lp_ssl_version()){
91         case SMB_SSL_V2:    sslContext = SSL_CTX_new(SSLv2_method());   break;
92         case SMB_SSL_V3:    sslContext = SSL_CTX_new(SSLv3_method());   break;
93         default:
94         case SMB_SSL_V23:   sslContext = SSL_CTX_new(SSLv23_method());  break;
95         case SMB_SSL_TLS1:  sslContext = SSL_CTX_new(TLSv1_method());   break;
96     }
97     if(sslContext == NULL){
98         err = ERR_get_error();
99         fprintf(stderr, "SSL: Error allocating context: %s\n",
100                 ERR_error_string(err, NULL));
101         exit(1);
102     }
103     if(lp_ssl_compatibility()){
104         SSL_CTX_set_options(sslContext, SSL_OP_ALL);
105     }
106     certfile = isServer ? lp_ssl_cert() : lp_ssl_client_cert();
107     if((certfile == NULL || *certfile == 0) && isServer){
108         fprintf(stderr, "SSL: No cert file specified in config file!\n");
109         fprintf(stderr, "The server MUST have a certificate!\n");
110         exit(1);
111     }
112     keyfile = isServer ? lp_ssl_privkey() : lp_ssl_client_privkey();
113     if(keyfile == NULL || *keyfile == 0)
114         keyfile = certfile;
115     if(certfile != NULL && *certfile != 0){
116         if(!SSL_CTX_use_certificate_file(sslContext, certfile, SSL_FILETYPE_PEM)){
117             err = ERR_get_error();
118             fprintf(stderr, "SSL: error reading certificate from file %s: %s\n",
119                     certfile, ERR_error_string(err, NULL));
120             exit(1);
121         }
122         if(!SSL_CTX_use_PrivateKey_file(sslContext, keyfile, SSL_FILETYPE_PEM)){
123             err = ERR_get_error();
124             fprintf(stderr, "SSL: error reading private key from file %s: %s\n",
125                     keyfile, ERR_error_string(err, NULL));
126             exit(1);
127         }
128         if(!SSL_CTX_check_private_key(sslContext)){
129             err = ERR_get_error();
130             fprintf(stderr, "SSL: Private key does not match public key in cert!\n");
131             exit(1);
132         }
133     }
134     cacertDir = lp_ssl_cacertdir();
135     cacertFile = lp_ssl_cacertfile();
136     if(cacertDir != NULL && *cacertDir == 0)
137         cacertDir = NULL;
138     if(cacertFile != NULL && *cacertFile == 0)
139         cacertFile = NULL;
140     if(!SSL_CTX_load_verify_locations(sslContext, cacertFile, cacertDir)){
141         err = ERR_get_error();
142         fprintf(stderr, "SSL: Error error setting CA cert locations: %s\n",
143                 ERR_error_string(err, NULL));
144         fprintf(stderr, "trying default locations.\n");
145         cacertFile = cacertDir = NULL;
146         if(!SSL_CTX_set_default_verify_paths(sslContext)){
147             err = ERR_get_error();
148             fprintf(stderr, "SSL: Error error setting default CA cert location: %s\n",
149                     ERR_error_string(err, NULL));
150             exit(1);
151         }
152     }
153     SSL_CTX_set_tmp_rsa_callback(sslContext, ssl_temp_rsa_cb);
154     if((ciphers = lp_ssl_ciphers()) != NULL && *ciphers != 0)
155         SSL_CTX_set_cipher_list(sslContext, ciphers);
156     if((isServer && lp_ssl_reqClientCert()) || (!isServer && lp_ssl_reqServerCert())){
157         SSL_CTX_set_verify(sslContext,
158             SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, ssl_verify_cb);
159     }else{
160         SSL_CTX_set_verify(sslContext, SSL_VERIFY_NONE, ssl_verify_cb);
161     }
162 #if 1 /* don't know what this is good for, but s_server in SSLeay does it, too */
163     if(isServer){
164         SSL_CTX_set_client_CA_list(sslContext, SSL_load_client_CA_file(certfile));
165     }
166 #endif
167     return 0;
168 }
169
170 int sslutil_accept(int fd)
171 {
172 int     err;
173
174     if(ssl != NULL){
175         DEBUG(0, ("SSL: internal error: more than one SSL connection (server)\n"));
176         return -1;
177     }
178     if((ssl = SSL_new(sslContext)) == NULL){
179         err = ERR_get_error();
180         DEBUG(0, ("SSL: Error allocating handle: %s\n",
181             ERR_error_string(err, NULL)));
182         return -1;
183     }
184     SSL_set_fd(ssl, fd);
185     sslFd = fd;
186     if(SSL_accept(ssl) <= 0){
187         err = ERR_get_error();
188         DEBUG(0, ("SSL: Error accepting on socket: %s\n",
189             ERR_error_string(err, NULL)));
190         return -1;
191     }
192     DEBUG(0, ("SSL: negotiated cipher: %s\n", SSL_get_cipher(ssl)));
193     return 0;
194 }
195
196 int sslutil_fd_is_ssl(int fd)
197 {
198     return fd == sslFd;
199 }
200
201 int sslutil_connect(int fd)
202 {
203 int     err;
204
205     if(ssl != NULL){
206         DEBUG(0, ("SSL: internal error: more than one SSL connection (client)\n"));
207         return -1;
208     }
209     if((ssl = SSL_new(sslContext)) == NULL){
210         err = ERR_get_error();
211         DEBUG(0, ("SSL: Error allocating handle: %s\n",
212             ERR_error_string(err, NULL)));
213         return -1;
214     }
215     SSL_set_fd(ssl, fd);
216     sslFd = fd;
217     if(SSL_connect(ssl) <= 0){
218         err = ERR_get_error();
219         DEBUG(0, ("SSL: Error conencting socket: %s\n",
220             ERR_error_string(err, NULL)));
221         return -1;
222     }
223     DEBUG(0, ("SSL: negotiated cipher: %s\n", SSL_get_cipher(ssl)));
224     return 0;
225 }
226
227 int sslutil_disconnect(int fd)
228 {
229     if(fd == sslFd && ssl != NULL){
230         SSL_free(ssl);
231         ssl = NULL;
232         sslFd = -1;
233     }
234     return 0;
235 }
236
237 int sslutil_negotiate_ssl(int fd, int msg_type)
238 {
239 unsigned char   buf[5] = {0x83, 0, 0, 1, 0x81};
240 char            *reqHosts, *resignHosts;
241
242     reqHosts = lp_ssl_hosts();
243     resignHosts = lp_ssl_hosts_resign();
244     if(!allow_access(resignHosts, reqHosts, client_name(fd), client_addr(fd))){
245         sslEnabled = False;
246         return 0;
247     }
248     if(msg_type != 0x81){ /* first packet must be a session request */
249         DEBUG(0, ("%s Client %s did not use session setup; access denied\n",
250             timestring(), client_addr(fd)));
251         send_smb(fd, (char *)buf);
252         return -1;
253     }
254     buf[4] = 0x8e;  /* negative session response: use SSL */
255     send_smb(fd, (char *)buf);
256     if(sslutil_accept(fd) != 0){
257         DEBUG(0, ("%s Client %s failed SSL negotiation!\n",
258             timestring(), client_addr(fd)));
259         return -1;
260     }
261     return 1;
262 }
263
264 #else /* WITH_SSL */
265  void ssl_dummy(void) {;} /* So some compilers don't complain. */
266 #endif  /* WITH_SSL */