Line data Source code
1 : #include "../burp.h"
2 : #include "../asfd.h"
3 : #include "../async.h"
4 : #include "../cmd.h"
5 : #include "../conf.h"
6 : #include "../conffile.h"
7 : #include "../fsops.h"
8 : #include "../handy.h"
9 : #include "../iobuf.h"
10 : #include "../log.h"
11 : #include "../run_script.h"
12 : #include "cvss.h"
13 : #include "ca.h"
14 :
15 : #ifdef HAVE_WIN32
16 : // Want to avoid giving standard users access to the conf files, otherwise
17 : // they can get access to all the backed up files, which may include files
18 : // they shouldn't be able to get.
19 : static void hack_windows_perms(const char *path)
20 : {
21 : char cmd[512]="";
22 : snprintf(cmd, sizeof(cmd), "icacls.exe \"%s\" /inheritance:r /grant:r Administrators:F SYSTEM:F", path);
23 : system(cmd);
24 : }
25 : #endif
26 :
27 0 : static int generate_key_and_csr(struct asfd *asfd,
28 : struct conf **confs, const char *csr_path)
29 : {
30 0 : int a=0;
31 : const char *args[12];
32 0 : const char *ca_burp_ca=get_string(confs[OPT_CA_BURP_CA]);
33 0 : const char *cname=get_string(confs[OPT_CNAME]);
34 0 : const char *ssl_key=get_string(confs[OPT_SSL_KEY]);
35 :
36 0 : logp("Generating SSL key and certificate signing request\n");
37 0 : logp("Running '%s --key --keypath %s --request --requestpath %s --name %s'\n", ca_burp_ca, ssl_key, csr_path, cname);
38 : #ifdef HAVE_WIN32
39 : win32_enable_backup_privileges();
40 : #else
41 : // FIX THIS
42 0 : signal(SIGPIPE, SIG_IGN);
43 : #endif
44 0 : args[a++]=ca_burp_ca;
45 0 : args[a++]="--key";
46 0 : args[a++]="--keypath";
47 0 : args[a++]=ssl_key;
48 0 : args[a++]="--request";
49 0 : args[a++]="--requestpath";
50 0 : args[a++]=csr_path;
51 0 : args[a++]="--name";
52 0 : args[a++]=cname;
53 0 : args[a++]=NULL;
54 0 : if(run_script(asfd, args, NULL, confs, 1 /* wait */,
55 : 0, 0 /* do not use logp - stupid openssl prints lots of dots
56 : one at a time with no way to turn it off */))
57 : {
58 0 : logp("error when running '%s --key --keypath %s --request --requestpath %s --name %s'\n",
59 : ca_burp_ca, ssl_key, csr_path, cname);
60 0 : return -1;
61 : }
62 :
63 : #ifdef HAVE_WIN32
64 : hack_windows_perms(ssl_key);
65 : hack_windows_perms(csr_path);
66 : #endif
67 :
68 : return 0;
69 : }
70 :
71 : /* Rewrite the conf file with the ssl_peer_cn value changed to what the
72 : server told us it should be. */
73 0 : static int rewrite_client_conf(struct conf **confs)
74 : {
75 0 : int ret=-1;
76 0 : char p[32]="";
77 0 : struct fzp *dp=NULL;
78 0 : struct fzp *sp=NULL;
79 0 : char *tmp=NULL;
80 0 : char buf[4096]="";
81 0 : const char *conffile=get_string(confs[OPT_CONFFILE]);
82 0 : const char *ssl_peer_cn=get_string(confs[OPT_SSL_PEER_CN]);
83 :
84 0 : snprintf(p, sizeof(p), ".%d", getpid());
85 0 : if(!(tmp=prepend(conffile, p)))
86 : goto end;
87 0 : if(!(sp=fzp_open(conffile, "rb"))
88 0 : || !(dp=fzp_open(tmp, "wb")))
89 : goto end;
90 :
91 0 : while(fzp_gets(sp, buf, sizeof(buf)))
92 : {
93 0 : char *copy=NULL;
94 0 : char *field=NULL;
95 0 : char *value=NULL;
96 0 : int r=0;
97 :
98 0 : if(!(copy=strdup_w(buf, __func__)))
99 : goto end;
100 0 : if(conf_get_pair(buf, &field, &value, &r)
101 0 : || !field || !value
102 0 : || strcmp(field, "ssl_peer_cn"))
103 : {
104 0 : fzp_printf(dp, "%s", copy);
105 0 : free_w(©);
106 0 : continue;
107 : }
108 0 : free_w(©);
109 : #ifdef HAVE_WIN32
110 : fzp_printf(dp, "ssl_peer_cn = %s\r\n", ssl_peer_cn);
111 : #else
112 0 : fzp_printf(dp, "ssl_peer_cn = %s\n", ssl_peer_cn);
113 : #endif
114 : }
115 0 : fzp_close(&sp);
116 0 : if(fzp_close(&dp))
117 : {
118 0 : logp("error closing %s in %s\n", tmp, __func__);
119 0 : goto end;
120 : }
121 :
122 0 : if(files_equal(conffile, tmp, 0/*compressed*/))
123 : {
124 : // No need to overwrite if there were no differences.
125 0 : ret=0;
126 0 : unlink(tmp);
127 0 : goto end;
128 : }
129 :
130 0 : logp("Rewriting conf file: %s\n", conffile);
131 :
132 : // Nasty race conditions going on here. However, the new config
133 : // file will get left behind, so at worse you will have to move
134 : // the new file into the correct place by hand. Or delete everything
135 : // and start again.
136 : #ifdef HAVE_WIN32
137 : // Need to delete the destination, or Windows gets upset.
138 : unlink(conffile);
139 : #endif
140 0 : if(do_rename(tmp, conffile)) goto end;
141 :
142 0 : ret=0;
143 : end:
144 0 : fzp_close(&sp);
145 0 : fzp_close(&dp);
146 0 : if(ret)
147 : {
148 0 : logp("%s with %s failed\n", __func__, conffile);
149 0 : unlink(tmp);
150 : }
151 0 : free_w(&tmp);
152 0 : return ret;
153 : }
154 :
155 0 : static enum asl_ret csr_client_func(struct asfd *asfd,
156 : struct conf **confs, __attribute__((unused)) void *param)
157 : {
158 0 : if(strncmp_w(asfd->rbuf->buf, "csr ok:"))
159 : {
160 0 : iobuf_log_unexpected(asfd->rbuf, __func__);
161 0 : return ASL_END_ERROR;
162 : }
163 : // The server appends its name after 'csr ok:'
164 0 : if(set_string(confs[OPT_SSL_PEER_CN],
165 0 : asfd->rbuf->buf+strlen("csr ok:")))
166 : return ASL_END_ERROR;
167 0 : return ASL_END_OK;
168 : }
169 :
170 : /* Return 1 for everything OK, signed and returned, -1 for error, 0 for
171 : nothing done. */
172 0 : int ca_client_setup(struct asfd *asfd, struct conf **confs)
173 : {
174 0 : int ret=-1;
175 : struct stat statp;
176 0 : char csr_path[256]="";
177 0 : char ssl_cert_tmp[512]="";
178 0 : char ssl_cert_ca_tmp[512]="";
179 0 : const char *ca_burp_ca=get_string(confs[OPT_CA_BURP_CA]);
180 0 : const char *ca_csr_dir=get_string(confs[OPT_CA_CSR_DIR]);
181 0 : const char *cname=get_string(confs[OPT_CNAME]);
182 0 : const char *ssl_key=get_string(confs[OPT_SSL_KEY]);
183 0 : const char *ssl_cert=get_string(confs[OPT_SSL_CERT]);
184 0 : const char *ssl_cert_ca=get_string(confs[OPT_SSL_CERT_CA]);
185 0 : struct cntr *cntr=get_cntr(confs);
186 :
187 : /* Store setting, compared later to decide whether to rewrite the config */
188 0 : char *ssl_peer_cn_old=strdup_w(get_string(confs[OPT_SSL_PEER_CN]), __func__);
189 0 : if(!ssl_peer_cn_old) goto end;
190 :
191 : // Do not continue if we have one of the following things not set.
192 0 : if( !ca_burp_ca
193 0 : || !ca_csr_dir
194 0 : || !ssl_cert_ca
195 0 : || !ssl_cert
196 0 : || !ssl_key
197 : // Do not try to get a new certificate if we already have a key.
198 0 : || !lstat(ssl_key, &statp))
199 : {
200 0 : if(asfd->write_str(asfd, CMD_GEN, "nocsr")
201 0 : || asfd_read_expect(asfd, CMD_GEN, "nocsr ok"))
202 : {
203 0 : logp("problem reading from server nocsr\n");
204 0 : goto end;
205 : }
206 0 : logp("nocsr ok\n");
207 0 : ret=0;
208 0 : goto end;
209 : }
210 :
211 : // Tell the server we want to do a signing request and store the servers name in ssl_peer_cn.
212 0 : if(asfd->write_str(asfd, CMD_GEN, "csr")
213 0 : || asfd->simple_loop(asfd, confs, NULL, __func__, csr_client_func))
214 : goto end;
215 :
216 0 : logp("Server will sign a certificate request\n");
217 :
218 : // First need to generate a client key and a certificate signing
219 : // request.
220 0 : snprintf(csr_path, sizeof(csr_path), "%s/%s.csr", ca_csr_dir, cname);
221 0 : if(generate_key_and_csr(asfd, confs, csr_path)) goto end_cleanup;
222 :
223 : // Then copy the csr to the server.
224 0 : if(send_a_file(asfd, csr_path, cntr)) goto end_cleanup;
225 :
226 0 : snprintf(ssl_cert_tmp, sizeof(ssl_cert_tmp), "%s.%d",
227 : ssl_cert, getpid());
228 0 : snprintf(ssl_cert_ca_tmp, sizeof(ssl_cert_ca_tmp), "%s.%d",
229 : ssl_cert_ca, getpid());
230 :
231 : // The server will then sign it, and give it back.
232 0 : if(receive_a_file(asfd, ssl_cert_tmp, cntr)) goto end_cleanup;
233 : // The server will also send the CA certificate.
234 0 : if(receive_a_file(asfd, ssl_cert_ca_tmp, cntr)) goto end_cleanup;
235 :
236 : // Possible race condition - the rename can delete the destination
237 : // and then fail. Worse case, the user has to rename them by hand.
238 0 : if(do_rename(ssl_cert_tmp, ssl_cert)
239 0 : || do_rename(ssl_cert_ca_tmp, ssl_cert_ca))
240 : goto end_cleanup;
241 :
242 : #ifdef HAVE_WIN32
243 : hack_windows_perms(ssl_cert);
244 : hack_windows_perms(ssl_cert_ca);
245 : #endif
246 :
247 : // Need to rewrite our configuration file to contain the server
248 : // name (ssl_peer_cn) if the name differs from the config file.
249 0 : if(strncmp_w(ssl_peer_cn_old, get_string(confs[OPT_SSL_PEER_CN])))
250 : {
251 0 : if(rewrite_client_conf(confs)) goto end_cleanup;
252 : }
253 :
254 : // My goodness, everything seems to have gone OK. Stand back!
255 : ret=1;
256 : end_cleanup:
257 0 : if(ret<0)
258 : {
259 : // On error, remove any possibly newly created files, so that
260 : // this function might run again on another go.
261 0 : unlink(csr_path);
262 0 : unlink(ssl_key);
263 0 : unlink(ssl_cert);
264 0 : unlink(ssl_cert_ca);
265 0 : unlink(ssl_cert_tmp);
266 0 : unlink(ssl_cert_ca_tmp);
267 : }
268 : end:
269 0 : if(ssl_peer_cn_old) free_w(&ssl_peer_cn_old);
270 0 : return ret;
271 : }
|