1 /* |
|
2 * CDDL HEADER START |
|
3 * |
|
4 * The contents of this file are subject to the terms of the |
|
5 * Common Development and Distribution License (the "License"). |
|
6 * You may not use this file except in compliance with the License. |
|
7 * |
|
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE |
|
9 * or http://www.opensolaris.org/os/licensing. |
|
10 * See the License for the specific language governing permissions |
|
11 * and limitations under the License. |
|
12 * |
|
13 * When distributing Covered Code, include this CDDL HEADER in each |
|
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. |
|
15 * If applicable, add the following below this CDDL HEADER, with the |
|
16 * fields enclosed by brackets "[]" replaced with your own identifying |
|
17 * information: Portions Copyright [yyyy] [name of copyright owner] |
|
18 * |
|
19 * CDDL HEADER END |
|
20 */ |
|
21 |
|
22 /* |
|
23 * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. |
|
24 */ |
|
25 |
|
26 #include <openssl/ssl.h> |
|
27 #include <openssl/err.h> |
|
28 #include <sys/types.h> |
|
29 #include <sys/socket.h> |
|
30 #include <sys/utsname.h> |
|
31 #include <sys/stat.h> |
|
32 #include <sys/wait.h> |
|
33 #include <stdio.h> |
|
34 #include <string.h> |
|
35 #include <stdlib.h> |
|
36 #include <errno.h> |
|
37 #include <unistd.h> |
|
38 #include <spawn.h> |
|
39 |
|
40 #include <rad/adr_stream.h> |
|
41 #include "rad_object.h" |
|
42 #include "rad_modapi.h" |
|
43 #include "rad_modapi_xport.h" |
|
44 #include "rad_connection.h" |
|
45 #include "rad_xport.h" |
|
46 #include "../rad_listen.h" |
|
47 |
|
48 #include "api_tls.h" |
|
49 |
|
50 static char *pam_service = "rad-tls"; |
|
51 |
|
52 static boolean_t |
|
53 generate_cert(const char *cert, const char *key) |
|
54 { |
|
55 struct utsname name; |
|
56 struct stat st; |
|
57 pid_t pid; |
|
58 char buffer[1024]; |
|
59 const char *args[] = { |
|
60 "/usr/bin/openssl", "req", "-x509", "-newkey", "rsa:1024", |
|
61 "-days", "3650", "-sha1", "-nodes", "-keyout", key, |
|
62 "-out", cert, "-subj", buffer, NULL }; |
|
63 |
|
64 if (stat(cert, &st) != -1 && stat(key, &st) != -1) |
|
65 return (B_TRUE); |
|
66 |
|
67 (void) uname(&name); |
|
68 (void) snprintf(buffer, 1024, "/CN=Remote Administration Daemon @ %s", |
|
69 name.nodename); |
|
70 |
|
71 rad_log(RL_WARN, "generating key/certificate pair\n"); |
|
72 if (posix_spawn(&pid, args[0], NULL, NULL, (char **)args, NULL) != 0) { |
|
73 rad_log(RL_ERROR, "failed to create key pair\n"); |
|
74 return (B_FALSE); |
|
75 } |
|
76 while (waitpid(pid, NULL, 0) == -1 && errno == EINTR) |
|
77 ; |
|
78 |
|
79 if (chmod(cert, 0644) == -1) |
|
80 rad_log(RL_WARN, "failed to chmod '%s'; " |
|
81 "certificate only readable by owner: %s", strerror(errno)); |
|
82 |
|
83 return (B_TRUE); |
|
84 } |
|
85 |
|
86 static void |
|
87 tls_run(void *arg) |
|
88 { |
|
89 radmod_connection_t *conn = arg; |
|
90 rad_proto_handle(conn); |
|
91 rad_conn_free(conn); |
|
92 } |
|
93 |
|
94 static rad_moderr_t |
|
95 tls_listen(rad_thread_t *arg) |
|
96 { |
|
97 SSL_CTX *context; |
|
98 SSL *ssl; |
|
99 int fd; |
|
100 data_t *d, *data = rad_thread_arg(arg); |
|
101 |
|
102 int port = data_to_integer(struct_get(data, "port")); |
|
103 d = struct_get(data, "proto"); |
|
104 const char *protostr = d != NULL ? data_to_string(d) : "rad"; |
|
105 d = struct_get(data, "localonly"); |
|
106 boolean_t local = d != NULL ? data_to_boolean(d) : B_TRUE; |
|
107 d = struct_get(data, "certificate"); |
|
108 const char *cert = data_to_string(d); |
|
109 d = struct_get(data, "privatekey"); |
|
110 const char *key = data_to_string(d); |
|
111 d = struct_get(data, "generate"); |
|
112 boolean_t generate = d != NULL ? data_to_boolean(d) : B_FALSE; |
|
113 d = struct_get(data, "pam_service"); |
|
114 if (d != NULL) { |
|
115 pam_service = (char *)data_to_string(d); |
|
116 } |
|
117 |
|
118 if (generate && !generate_cert(cert, key)) { |
|
119 rad_log(RL_ERROR, "Failed to generate certificate.\n"); |
|
120 return (rm_system); |
|
121 } |
|
122 |
|
123 rad_protocol_t *proto = rad_proto_find(protostr); |
|
124 if (proto == NULL) { |
|
125 rad_log(RL_ERROR, "Unable to find protocol \"%s\".\n", |
|
126 protostr); |
|
127 return (rm_config); |
|
128 } |
|
129 |
|
130 if ((fd = listen_on_port(port, local)) < 0) { |
|
131 rad_log(RL_ERROR, "Error starting server on port %d\n", |
|
132 port); |
|
133 return (rm_system); |
|
134 } |
|
135 |
|
136 rad_log(RL_DEBUG, "Initializing SSL library.\n"); |
|
137 (void) SSL_library_init(); |
|
138 (void) SSL_load_error_strings(); |
|
139 |
|
140 rad_log(RL_DEBUG, "Creating SSL context.\n"); |
|
141 context = SSL_CTX_new(SSLv23_method()); |
|
142 if (context == NULL) { |
|
143 rad_log(RL_ERROR, "Unable to create SSL context.\n"); |
|
144 return (rm_system); |
|
145 } |
|
146 (void) SSL_CTX_set_options(context, SSL_OP_NO_SSLv2); |
|
147 |
|
148 if (SSL_CTX_use_certificate_chain_file(context, cert) == 0) { |
|
149 rad_log(RL_ERROR, "Unable to use cert file: %s\n", cert); |
|
150 ERR_print_errors_fp(stderr); |
|
151 return (rm_system); |
|
152 } |
|
153 |
|
154 if (SSL_CTX_use_PrivateKey_file(context, key, SSL_FILETYPE_PEM) == 0) { |
|
155 rad_log(RL_ERROR, "Unable to use privatekey file: %s\n", key); |
|
156 ERR_print_errors_fp(stderr); |
|
157 return (rm_system); |
|
158 } |
|
159 |
|
160 rad_thread_ack(arg, rm_ok); |
|
161 for (;;) { |
|
162 int afd, result; |
|
163 |
|
164 rad_log(RL_DEBUG, "Waiting for connection.\n"); |
|
165 if ((afd = accept(fd, 0, 0)) == -1) { |
|
166 rad_log(RL_WARN, "Error in accept(): %s\n", |
|
167 strerror(errno)); |
|
168 continue; |
|
169 } |
|
170 rad_log(RL_DEBUG, "Connection accepted.\n"); |
|
171 |
|
172 rad_log(RL_DEBUG, "Creating SSL.\n"); |
|
173 ssl = SSL_new(context); |
|
174 if (ssl == NULL) { |
|
175 rad_log(RL_WARN, "Unable to create SSL.\n"); |
|
176 (void) close(afd); |
|
177 continue; |
|
178 } |
|
179 |
|
180 rad_log(RL_DEBUG, "Initiating SSL connection.\n"); |
|
181 if (!SSL_set_fd(ssl, afd)) { |
|
182 rad_log(RL_WARN, "Unable to set SSL fd.\n"); |
|
183 goto close; |
|
184 } |
|
185 |
|
186 while ((result = SSL_accept(ssl)) != 1) { |
|
187 result = SSL_get_error(ssl, result); |
|
188 |
|
189 /* Shouldn't happen, but just in case: */ |
|
190 if (result == SSL_ERROR_WANT_READ || |
|
191 result == SSL_ERROR_WANT_WRITE) |
|
192 continue; |
|
193 |
|
194 ERR_print_errors_fp(stderr); |
|
195 rad_log(RL_WARN, |
|
196 "Unable to establish connection: %d\n", result); |
|
197 goto close; |
|
198 } |
|
199 |
|
200 rad_log(RL_DEBUG, "Connection accepted.\n"); |
|
201 adr_stream_t *stream = adr_stream_create_ssl(ssl, afd); |
|
202 if (stream == NULL) |
|
203 continue; |
|
204 |
|
205 radmod_connection_t *conn = rad_conn_create_fd(afd, B_TRUE); |
|
206 if (conn == NULL) { |
|
207 adr_stream_close(stream); |
|
208 adr_stream_free(stream); |
|
209 rad_log(RL_WARN, "failed to allocate connection"); |
|
210 continue; |
|
211 } |
|
212 conn->rm_conn_xport = stream; |
|
213 conn->rm_conn_proto_ops = proto; |
|
214 conn->rm_conn_pam_service = pam_service; |
|
215 |
|
216 if (rad_thread_create_async(tls_run, conn) != rm_ok) { |
|
217 rad_conn_close(conn); |
|
218 rad_conn_free(conn); |
|
219 } |
|
220 |
|
221 continue; |
|
222 close: |
|
223 SSL_free(ssl); |
|
224 (void) close(afd); |
|
225 } |
|
226 } |
|
227 |
|
228 static rad_moderr_t |
|
229 starter(data_t *data) |
|
230 { |
|
231 /* |
|
232 * Verify parameters. |
|
233 */ |
|
234 if (struct_get(data, "port") == NULL) { |
|
235 rad_log(RL_ERROR, "Port required\n"); |
|
236 return (rm_config); |
|
237 } |
|
238 |
|
239 if (struct_get(data, "certificate") == NULL) { |
|
240 rad_log(RL_ERROR, "Cert required\n"); |
|
241 return (rm_config); |
|
242 } |
|
243 |
|
244 if (struct_get(data, "privatekey") == NULL) { |
|
245 rad_log(RL_ERROR, "Private key required\n"); |
|
246 return (rm_config); |
|
247 } |
|
248 |
|
249 return (rad_thread_create(tls_listen, data)); |
|
250 } |
|
251 |
|
252 static rad_modinfo_t modinfo = { "xport_tls", "TLS socket transport module" }; |
|
253 |
|
254 int |
|
255 _rad_init(void *handle) |
|
256 { |
|
257 if (rad_module_register(handle, RAD_MODVERSION, &modinfo) == -1) |
|
258 return (-1); |
|
259 |
|
260 rad_xport_register("tls", &t__tls, starter); |
|
261 return (0); |
|
262 } |
|