1f098b2533d9345ad893386b3d76eb6c4d618865
[kai/samba.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 #include "includes.h"
23
24 /*
25  * Hmmm, only check on WITH_SSL after we have included includes.h
26  * which pulls in config.h which is where WITH_SSL is defined, if 
27  * at all :-)
28  */
29
30 #ifdef WITH_SSL  /* should always be defined if this module is compiled */
31
32 #include <ssl.h>
33 #include <err.h>
34
35 BOOL            sslEnabled;
36 SSL             *ssl = NULL;
37 int             sslFd = -1;
38 static SSL_CTX  *sslContext = NULL;
39 extern int      DEBUGLEVEL;
40
41 static int  ssl_verify_cb(int ok, X509_STORE_CTX *ctx)
42 {
43 char    buffer[256];
44
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;
72         }
73     }
74     return ok;
75 }
76
77 static RSA  *ssl_temp_rsa_cb(SSL *ssl, int export)
78 {
79 static RSA  *rsa = NULL;
80     
81     if(rsa == NULL)
82         rsa = RSA_generate_key(512, RSA_F4, NULL, NULL);
83     return rsa;
84 }
85
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.
89  */
90 int sslutil_init(int isServer)
91 {
92 int     err;
93 char    *certfile, *keyfile, *ciphers, *cacertDir, *cacertFile;
94
95     SSL_load_error_strings();
96     SSLeay_add_ssl_algorithms();
97     switch(lp_ssl_version()){
98         case SMB_SSL_V2:    sslContext = SSL_CTX_new(SSLv2_method());   break;
99         case SMB_SSL_V3:    sslContext = SSL_CTX_new(SSLv3_method());   break;
100         default:
101         case SMB_SSL_V23:   sslContext = SSL_CTX_new(SSLv23_method());  break;
102         case SMB_SSL_TLS1:  sslContext = SSL_CTX_new(TLSv1_method());   break;
103     }
104     if(sslContext == NULL){
105         err = ERR_get_error();
106         fprintf(stderr, "SSL: Error allocating context: %s\n",
107                 ERR_error_string(err, NULL));
108         exit(1);
109     }
110     if(lp_ssl_compatibility()){
111         SSL_CTX_set_options(sslContext, SSL_OP_ALL);
112     }
113     certfile = isServer ? lp_ssl_cert() : lp_ssl_client_cert();
114     if((certfile == NULL || *certfile == 0) && isServer){
115         fprintf(stderr, "SSL: No cert file specified in config file!\n");
116         fprintf(stderr, "The server MUST have a certificate!\n");
117         exit(1);
118     }
119     keyfile = isServer ? lp_ssl_privkey() : lp_ssl_client_privkey();
120     if(keyfile == NULL || *keyfile == 0)
121         keyfile = certfile;
122     if(certfile != NULL && *certfile != 0){
123         if(!SSL_CTX_use_certificate_file(sslContext, certfile, SSL_FILETYPE_PEM)){
124             err = ERR_get_error();
125             fprintf(stderr, "SSL: error reading certificate from file %s: %s\n",
126                     certfile, ERR_error_string(err, NULL));
127             exit(1);
128         }
129         if(!SSL_CTX_use_PrivateKey_file(sslContext, keyfile, SSL_FILETYPE_PEM)){
130             err = ERR_get_error();
131             fprintf(stderr, "SSL: error reading private key from file %s: %s\n",
132                     keyfile, ERR_error_string(err, NULL));
133             exit(1);
134         }
135         if(!SSL_CTX_check_private_key(sslContext)){
136             err = ERR_get_error();
137             fprintf(stderr, "SSL: Private key does not match public key in cert!\n");
138             exit(1);
139         }
140     }
141     cacertDir = lp_ssl_cacertdir();
142     cacertFile = lp_ssl_cacertfile();
143     if(cacertDir != NULL && *cacertDir == 0)
144         cacertDir = NULL;
145     if(cacertFile != NULL && *cacertFile == 0)
146         cacertFile = NULL;
147     if(!SSL_CTX_load_verify_locations(sslContext, cacertFile, cacertDir)){
148         err = ERR_get_error();
149         fprintf(stderr, "SSL: Error error setting CA cert locations: %s\n",
150                 ERR_error_string(err, NULL));
151         fprintf(stderr, "trying default locations.\n");
152         cacertFile = cacertDir = NULL;
153         if(!SSL_CTX_set_default_verify_paths(sslContext)){
154             err = ERR_get_error();
155             fprintf(stderr, "SSL: Error error setting default CA cert location: %s\n",
156                     ERR_error_string(err, NULL));
157             exit(1);
158         }
159     }
160     SSL_CTX_set_tmp_rsa_callback(sslContext, ssl_temp_rsa_cb);
161     if((ciphers = lp_ssl_ciphers()) != NULL && *ciphers != 0)
162         SSL_CTX_set_cipher_list(sslContext, ciphers);
163     if((isServer && lp_ssl_reqClientCert()) || (!isServer && lp_ssl_reqServerCert())){
164         SSL_CTX_set_verify(sslContext,
165             SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, ssl_verify_cb);
166     }else{
167         SSL_CTX_set_verify(sslContext, SSL_VERIFY_NONE, ssl_verify_cb);
168     }
169 #if 1 /* don't know what this is good for, but s_server in SSLeay does it, too */
170     if(isServer){
171         SSL_CTX_set_client_CA_list(sslContext, SSL_load_client_CA_file(certfile));
172     }
173 #endif
174     return 0;
175 }
176
177 int sslutil_accept(int fd)
178 {
179 int     err;
180
181     if(ssl != NULL){
182         DEBUG(0, ("SSL: internal error: more than one SSL connection (server)\n"));
183         return -1;
184     }
185     if((ssl = SSL_new(sslContext)) == NULL){
186         err = ERR_get_error();
187         DEBUG(0, ("SSL: Error allocating handle: %s\n",
188             ERR_error_string(err, NULL)));
189         return -1;
190     }
191     SSL_set_fd(ssl, fd);
192     sslFd = fd;
193     if(SSL_accept(ssl) <= 0){
194         err = ERR_get_error();
195         DEBUG(0, ("SSL: Error accepting on socket: %s\n",
196             ERR_error_string(err, NULL)));
197         return -1;
198     }
199     DEBUG(0, ("SSL: negotiated cipher: %s\n", SSL_get_cipher(ssl)));
200     return 0;
201 }
202
203 int sslutil_fd_is_ssl(int fd)
204 {
205     return fd == sslFd;
206 }
207
208 int sslutil_connect(int fd)
209 {
210 int     err;
211
212     if(ssl != NULL){
213         DEBUG(0, ("SSL: internal error: more than one SSL connection (client)\n"));
214         return -1;
215     }
216     if((ssl = SSL_new(sslContext)) == NULL){
217         err = ERR_get_error();
218         DEBUG(0, ("SSL: Error allocating handle: %s\n",
219             ERR_error_string(err, NULL)));
220         return -1;
221     }
222     SSL_set_fd(ssl, fd);
223     sslFd = fd;
224     if(SSL_connect(ssl) <= 0){
225         err = ERR_get_error();
226         DEBUG(0, ("SSL: Error conencting socket: %s\n",
227             ERR_error_string(err, NULL)));
228         return -1;
229     }
230     DEBUG(0, ("SSL: negotiated cipher: %s\n", SSL_get_cipher(ssl)));
231     return 0;
232 }
233
234 int sslutil_disconnect(int fd)
235 {
236     if(fd == sslFd && ssl != NULL){
237         SSL_free(ssl);
238         ssl = NULL;
239         sslFd = -1;
240     }
241     return 0;
242 }
243
244 int sslutil_negotiate_ssl(int fd, int msg_type)
245 {
246 unsigned char   buf[5] = {0x83, 0, 0, 1, 0x81};
247 char            *reqHosts, *resignHosts;
248
249     reqHosts = lp_ssl_hosts();
250     resignHosts = lp_ssl_hosts_resign();
251     if(!allow_access(resignHosts, reqHosts, client_name(fd), client_addr(fd))){
252         sslEnabled = False;
253         return 0;
254     }
255     if(msg_type != 0x81){ /* first packet must be a session request */
256         DEBUG( 0, ( "Client %s did not use session setup; access denied\n",
257                      client_addr(fd) ) );
258         send_smb(fd, (char *)buf);
259         return -1;
260     }
261     buf[4] = 0x8e;  /* negative session response: use SSL */
262     send_smb(fd, (char *)buf);
263     if(sslutil_accept(fd) != 0){
264         DEBUG( 0, ( "Client %s failed SSL negotiation!\n", client_addr(fd) ) );
265         return -1;
266     }
267     return 1;
268 }
269
270 #else /* WITH_SSL */
271  void ssl_dummy(void);
272  void ssl_dummy(void) {;} /* So some compilers don't complain. */
273 #endif  /* WITH_SSL */