aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorTed Zlatanov2010-09-26 01:06:28 -0500
committerTed Zlatanov2010-09-26 01:06:28 -0500
commit8af55556e6cc093641dde5205aa5e295039b809f (patch)
tree2f0bebd6d170687acc470e4a1a030abd18daf651 /src
parent8ccbef23ea624d892bada3c66ef2339ada342997 (diff)
downloademacs-8af55556e6cc093641dde5205aa5e295039b809f.tar.gz
emacs-8af55556e6cc093641dde5205aa5e295039b809f.zip
Set up GnuTLS support.
* configure.in: Set up GnuTLS. * lisp/net/gnutls.el: GnuTLS glue code to set up a connection. * src/Makefile.in (LIBGNUTLS_LIBS, LIBGNUTLS_CFLAGS, ALL_CFLAGS) (obj, LIBES): Set up GnuTLS support. * src/config.in: Set up GnuTLS support. * src/emacs.c: Set up GnuTLS support and call syms_of_gnutls. * src/gnutls.c: The source code for GnuTLS support in Emacs. * src/gnutls.h: The GnuTLS glue for Emacs, macros and enums. * src/process.c (make_process, Fstart_process) (read_process_output, send_process): Set up GnuTLS support for process input/output file descriptors. * src/process.h: Set up GnuTLS support.
Diffstat (limited to 'src')
-rw-r--r--src/ChangeLog19
-rw-r--r--src/Makefile.in7
-rw-r--r--src/config.in9
-rw-r--r--src/emacs.c8
-rw-r--r--src/gnutls.c551
-rw-r--r--src/gnutls.h60
-rw-r--r--src/process.c38
-rw-r--r--src/process.h15
8 files changed, 703 insertions, 4 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index d43853e7baa..e6bf911952e 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,22 @@
12010-09-26 Teodor Zlatanov <tzz@lifelogs.com>
2
3 * process.h: Set up GnuTLS support.
4
5 * process.c (make_process, Fstart_process)
6 (read_process_output, send_process): Set up GnuTLS support for
7 process input/output file descriptors.
8
9 * gnutls.h: The GnuTLS glue for Emacs, macros and enums.
10
11 * gnutls.c: The source code for GnuTLS support in Emacs.
12
13 * emacs.c: Set up GnuTLS support and call syms_of_gnutls.
14
15 * config.in: Set up GnuTLS support.
16
17 * Makefile.in (LIBGNUTLS_LIBS, LIBGNUTLS_CFLAGS, ALL_CFLAGS)
18 (obj, LIBES): Set up GnuTLS support.
19
12010-09-26 Juanma Barranquero <lekktu@gmail.com> 202010-09-26 Juanma Barranquero <lekktu@gmail.com>
2 21
3 * w32.c (get_emacs_configuration_options): Fix previous change. 22 * w32.c (get_emacs_configuration_options): Fix previous change.
diff --git a/src/Makefile.in b/src/Makefile.in
index 7fe3fe0ae81..00706460d25 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -286,6 +286,9 @@ LIBRESOLV = @LIBRESOLV@
286 286
287LIBSELINUX_LIBS = @LIBSELINUX_LIBS@ 287LIBSELINUX_LIBS = @LIBSELINUX_LIBS@
288 288
289LIBGNUTLS_LIBS = @LIBGNUTLS_LIBS@
290LIBGNUTLS_CFLAGS = @LIBGNUTLS_CFLAGS@
291
289INTERVALS_H = dispextern.h intervals.h composite.h 292INTERVALS_H = dispextern.h intervals.h composite.h
290 293
291GETLOADAVG_LIBS = @GETLOADAVG_LIBS@ 294GETLOADAVG_LIBS = @GETLOADAVG_LIBS@
@@ -325,6 +328,7 @@ ALL_CFLAGS=-Demacs -DHAVE_CONFIG_H $(MYCPPFLAGS) -I. -I${srcdir} \
325 ${LIBXML2_CFLAGS} ${DBUS_CFLAGS} \ 328 ${LIBXML2_CFLAGS} ${DBUS_CFLAGS} \
326 ${GCONF_CFLAGS} ${FREETYPE_CFLAGS} ${FONTCONFIG_CFLAGS} \ 329 ${GCONF_CFLAGS} ${FREETYPE_CFLAGS} ${FONTCONFIG_CFLAGS} \
327 ${LIBOTF_CFLAGS} ${M17N_FLT_CFLAGS} ${DEPFLAGS} ${PROFILING_CFLAGS} \ 330 ${LIBOTF_CFLAGS} ${M17N_FLT_CFLAGS} ${DEPFLAGS} ${PROFILING_CFLAGS} \
331 $(LIBGNUTLS_CFLAGS) \
328 ${C_WARNINGS_SWITCH} ${CFLAGS} 332 ${C_WARNINGS_SWITCH} ${CFLAGS}
329ALL_OBJC_CFLAGS=$(ALL_CFLAGS) $(GNU_OBJC_CFLAGS) 333ALL_OBJC_CFLAGS=$(ALL_CFLAGS) $(GNU_OBJC_CFLAGS)
330 334
@@ -349,7 +353,7 @@ obj= dispnew.o frame.o scroll.o xdisp.o menu.o $(XMENU_OBJ) window.o \
349 alloc.o data.o doc.o editfns.o callint.o \ 353 alloc.o data.o doc.o editfns.o callint.o \
350 eval.o floatfns.o fns.o font.o print.o lread.o \ 354 eval.o floatfns.o fns.o font.o print.o lread.o \
351 syntax.o $(UNEXEC_OBJ) bytecode.o \ 355 syntax.o $(UNEXEC_OBJ) bytecode.o \
352 process.o callproc.o \ 356 process.o gnutls.o callproc.o \
353 region-cache.o sound.o atimer.o \ 357 region-cache.o sound.o atimer.o \
354 doprnt.o strftime.o intervals.o textprop.o composite.o md5.o xml.o \ 358 doprnt.o strftime.o intervals.o textprop.o composite.o md5.o xml.o \
355 $(MSDOS_OBJ) $(MSDOS_X_OBJ) $(NS_OBJ) $(CYGWIN_OBJ) $(FONT_OBJ) 359 $(MSDOS_OBJ) $(MSDOS_X_OBJ) $(NS_OBJ) $(CYGWIN_OBJ) $(FONT_OBJ)
@@ -601,6 +605,7 @@ LIBES = $(LIBS) $(LIBX_BASE) $(LIBX_OTHER) $(LIBSOUND) \
601 ${LIBXML2_LIBS} $(LIBGPM) $(LIBRESOLV) $(LIBS_SYSTEM) \ 605 ${LIBXML2_LIBS} $(LIBGPM) $(LIBRESOLV) $(LIBS_SYSTEM) \
602 $(LIBS_TERMCAP) $(GETLOADAVG_LIBS) ${GCONF_LIBS} ${LIBSELINUX_LIBS} \ 606 $(LIBS_TERMCAP) $(GETLOADAVG_LIBS) ${GCONF_LIBS} ${LIBSELINUX_LIBS} \
603 $(FREETYPE_LIBS) $(FONTCONFIG_LIBS) $(LIBOTF_LIBS) $(M17N_FLT_LIBS) \ 607 $(FREETYPE_LIBS) $(FONTCONFIG_LIBS) $(LIBOTF_LIBS) $(M17N_FLT_LIBS) \
608 $(LIBGNUTLS_LIBS) \
604 $(LIB_GCC) $(LIB_MATH) $(LIB_STANDARD) $(LIB_GCC) 609 $(LIB_GCC) $(LIB_MATH) $(LIB_STANDARD) $(LIB_GCC)
605 610
606all: emacs${EXEEXT} $(OTHER_FILES) 611all: emacs${EXEEXT} $(OTHER_FILES)
diff --git a/src/config.in b/src/config.in
index 199afbd78ba..43ebb756215 100644
--- a/src/config.in
+++ b/src/config.in
@@ -255,6 +255,9 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
255/* Define to 1 if you have a gif (or ungif) library. */ 255/* Define to 1 if you have a gif (or ungif) library. */
256#undef HAVE_GIF 256#undef HAVE_GIF
257 257
258/* Define if we have the GNU TLS library. */
259#undef HAVE_GNUTLS
260
258/* Define to 1 if you have the gpm library (-lgpm). */ 261/* Define to 1 if you have the gpm library (-lgpm). */
259#undef HAVE_GPM 262#undef HAVE_GPM
260 263
@@ -1094,6 +1097,12 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
1094#include config_opsysfile 1097#include config_opsysfile
1095#include config_machfile 1098#include config_machfile
1096 1099
1100#if HAVE_GNUTLS
1101#define LIBGNUTLS $(LIBGNUTLS_LIBS)
1102#else /* not HAVE_GNUTLS */
1103#define LIBGNUTLS
1104#endif /* not HAVE_GNUTLS */
1105
1097/* Set up some defines, C and LD flags for NeXTstep interface on GNUstep. 1106/* Set up some defines, C and LD flags for NeXTstep interface on GNUstep.
1098 (There is probably a better place to do this, but right now the Cocoa 1107 (There is probably a better place to do this, but right now the Cocoa
1099 side does this in s/darwin.h and we cannot 1108 side does this in s/darwin.h and we cannot
diff --git a/src/emacs.c b/src/emacs.c
index 5e7efb64226..397b6d1ce88 100644
--- a/src/emacs.c
+++ b/src/emacs.c
@@ -59,6 +59,10 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
59#include "keyboard.h" 59#include "keyboard.h"
60#include "keymap.h" 60#include "keymap.h"
61 61
62#ifdef HAVE_GNUTLS
63#include "gnutls.h"
64#endif
65
62#ifdef HAVE_NS 66#ifdef HAVE_NS
63#include "nsterm.h" 67#include "nsterm.h"
64#endif 68#endif
@@ -1569,6 +1573,10 @@ main (int argc, char **argv)
1569 syms_of_fontset (); 1573 syms_of_fontset ();
1570#endif /* HAVE_NS */ 1574#endif /* HAVE_NS */
1571 1575
1576#ifdef HAVE_GNUTLS
1577 syms_of_gnutls ();
1578#endif
1579
1572#ifdef HAVE_DBUS 1580#ifdef HAVE_DBUS
1573 syms_of_dbusbind (); 1581 syms_of_dbusbind ();
1574#endif /* HAVE_DBUS */ 1582#endif /* HAVE_DBUS */
diff --git a/src/gnutls.c b/src/gnutls.c
new file mode 100644
index 00000000000..50bf7940119
--- /dev/null
+++ b/src/gnutls.c
@@ -0,0 +1,551 @@
1/* GnuTLS glue for GNU Emacs.
2 Copyright (C) 2010 Free Software Foundation, Inc.
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software: you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation, either version 3 of the License, or
9(at your option) any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
18
19#include <config.h>
20#include <errno.h>
21#include <setjmp.h>
22
23#include "lisp.h"
24#include "process.h"
25
26#ifdef HAVE_GNUTLS
27#include <gnutls/gnutls.h>
28
29Lisp_Object Qgnutls_code;
30Lisp_Object Qgnutls_anon, Qgnutls_x509pki;
31Lisp_Object Qgnutls_e_interrupted, Qgnutls_e_again,
32 Qgnutls_e_invalid_session, Qgnutls_e_not_ready_for_handshake;
33int global_initialized;
34
35int
36emacs_gnutls_write (int fildes, gnutls_session_t state, char *buf,
37 unsigned int nbyte)
38{
39 register int rtnval, bytes_written;
40
41 bytes_written = 0;
42
43 while (nbyte > 0)
44 {
45 rtnval = gnutls_write (state, buf, nbyte);
46
47 if (rtnval == -1)
48 {
49 if (errno == EINTR)
50 continue;
51 else
52 return (bytes_written ? bytes_written : -1);
53 }
54
55 buf += rtnval;
56 nbyte -= rtnval;
57 bytes_written += rtnval;
58 }
59 fsync (STDOUT_FILENO);
60
61 return (bytes_written);
62}
63
64int
65emacs_gnutls_read (int fildes, gnutls_session_t state, char *buf,
66 unsigned int nbyte)
67{
68 register int rtnval;
69
70 do {
71 rtnval = gnutls_read (state, buf, nbyte);
72 } while (rtnval == GNUTLS_E_INTERRUPTED || rtnval == GNUTLS_E_AGAIN);
73 fsync (STDOUT_FILENO);
74
75 return (rtnval);
76}
77
78/* convert an integer error to a Lisp_Object; it will be either a
79 known symbol like `gnutls_e_interrupted' and `gnutls_e_again' or
80 simply the integer value of the error. GNUTLS_E_SUCCESS is mapped
81 to Qt. */
82Lisp_Object gnutls_make_error (int error)
83{
84 switch (error)
85 {
86 case GNUTLS_E_SUCCESS:
87 return Qt;
88 case GNUTLS_E_AGAIN:
89 return Qgnutls_e_again;
90 case GNUTLS_E_INTERRUPTED:
91 return Qgnutls_e_interrupted;
92 case GNUTLS_E_INVALID_SESSION:
93 return Qgnutls_e_invalid_session;
94 }
95
96 return make_number (error);
97}
98
99DEFUN ("gnutls-get-initstage", Fgnutls_get_initstage, Sgnutls_get_initstage, 1, 1, 0,
100 doc: /* Return the GnuTLS init stage of PROCESS.
101See also `gnutls-boot'. */)
102 (Lisp_Object proc)
103{
104 CHECK_PROCESS (proc);
105
106 return make_number (GNUTLS_INITSTAGE (proc));
107}
108
109DEFUN ("gnutls-errorp", Fgnutls_errorp, Sgnutls_errorp, 1, 1, 0,
110 doc: /* Returns t if ERROR (as generated by gnutls_make_error)
111indicates a GnuTLS problem. */)
112 (Lisp_Object error)
113{
114 if (EQ (error, Qt)) return Qnil;
115
116 return Qt;
117}
118
119DEFUN ("gnutls-error-fatalp", Fgnutls_error_fatalp, Sgnutls_error_fatalp, 1, 1, 0,
120 doc: /* Checks if ERROR is fatal.
121ERROR is an integer or a symbol with an integer `gnutls-code' property. */)
122 (Lisp_Object err)
123{
124 Lisp_Object code;
125
126 if (EQ (err, Qt)) return Qnil;
127
128 if (SYMBOLP (err))
129 {
130 code = Fget (err, Qgnutls_code);
131 if (NUMBERP (code))
132 {
133 err = code;
134 }
135 else
136 {
137 error ("Symbol has no numeric gnutls-code property");
138 }
139 }
140
141 if (!NUMBERP (err))
142 error ("Not an error symbol or code");
143
144 if (0 == gnutls_error_is_fatal (XINT (err)))
145 return Qnil;
146
147 return Qt;
148}
149
150DEFUN ("gnutls-error-string", Fgnutls_error_string, Sgnutls_error_string, 1, 1, 0,
151 doc: /* Returns a description of ERROR.
152ERROR is an integer or a symbol with an integer `gnutls-code' property. */)
153 (Lisp_Object err)
154{
155 Lisp_Object code;
156
157 if (EQ (err, Qt)) return build_string ("Not an error");
158
159 if (SYMBOLP (err))
160 {
161 code = Fget (err, Qgnutls_code);
162 if (NUMBERP (code))
163 {
164 err = code;
165 }
166 else
167 {
168 return build_string ("Symbol has no numeric gnutls-code property");
169 }
170 }
171
172 if (!NUMBERP (err))
173 return build_string ("Not an error symbol or code");
174
175 return build_string (gnutls_strerror (XINT (err)));
176}
177
178DEFUN ("gnutls-deinit", Fgnutls_deinit, Sgnutls_deinit, 1, 1, 0,
179 doc: /* Deallocate GNU TLS resources associated with PROCESS.
180See also `gnutls-init'. */)
181 (Lisp_Object proc)
182{
183 gnutls_session_t state;
184
185 CHECK_PROCESS (proc);
186 state = XPROCESS (proc)->gnutls_state;
187
188 if (GNUTLS_INITSTAGE (proc) >= GNUTLS_STAGE_INIT)
189 {
190 gnutls_deinit (state);
191 GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_INIT - 1;
192 }
193
194 return Qt;
195}
196
197/* Initializes global GNU TLS state to defaults.
198Call `gnutls-global-deinit' when GNU TLS usage is no longer needed.
199Returns zero on success. */
200Lisp_Object gnutls_emacs_global_init (void)
201{
202 int ret = GNUTLS_E_SUCCESS;
203
204 if (!global_initialized)
205 ret = gnutls_global_init ();
206
207 global_initialized = 1;
208
209 return gnutls_make_error (ret);
210}
211
212/* Deinitializes global GNU TLS state.
213See also `gnutls-global-init'. */
214Lisp_Object gnutls_emacs_global_deinit (void)
215{
216 if (global_initialized)
217 gnutls_global_deinit ();
218
219 global_initialized = 0;
220
221 return gnutls_make_error (GNUTLS_E_SUCCESS);
222}
223
224DEFUN ("gnutls-boot", Fgnutls_boot, Sgnutls_boot, 3, 6, 0,
225 doc: /* Initializes client-mode GnuTLS for process PROC.
226Currently only client mode is supported. Returns a success/failure
227value you can check with `gnutls-errorp'.
228
229PRIORITY_STRING is a string describing the priority.
230TYPE is either `gnutls-anon' or `gnutls-x509pki'.
231TRUSTFILE is a PEM encoded trust file for `gnutls-x509pki'.
232KEYFILE is ... for `gnutls-x509pki' (TODO).
233CALLBACK is ... for `gnutls-x509pki' (TODO).
234
235Note that the priority is set on the client. The server does not use
236the protocols's priority except for disabling protocols that were not
237specified.
238
239Processes must be initialized with this function before other GNU TLS
240functions are used. This function allocates resources which can only
241be deallocated by calling `gnutls-deinit' or by calling it again.
242
243Each authentication type may need additional information in order to
244work. For X.509 PKI (`gnutls-x509pki'), you need TRUSTFILE and
245KEYFILE and optionally CALLBACK. */)
246 (Lisp_Object proc, Lisp_Object priority_string, Lisp_Object type,
247 Lisp_Object trustfile, Lisp_Object keyfile, Lisp_Object callback)
248{
249 int ret = GNUTLS_E_SUCCESS;
250
251 /* TODO: GNUTLS_X509_FMT_DER is also an option. */
252 int file_format = GNUTLS_X509_FMT_PEM;
253
254 gnutls_session_t state;
255 gnutls_certificate_credentials_t x509_cred;
256 gnutls_anon_client_credentials_t anon_cred;
257 gnutls_srp_client_credentials_t srp_cred;
258 gnutls_datum_t data;
259 Lisp_Object global_init;
260
261 CHECK_PROCESS (proc);
262 CHECK_SYMBOL (type);
263 CHECK_STRING (priority_string);
264
265 state = XPROCESS (proc)->gnutls_state;
266
267 /* always initialize globals. */
268 global_init = gnutls_emacs_global_init ();
269 if (! NILP (Fgnutls_errorp (global_init)))
270 return global_init;
271
272 /* deinit and free resources. */
273 if (GNUTLS_INITSTAGE (proc) >= GNUTLS_STAGE_CRED_ALLOC)
274 {
275 message ("gnutls: deallocating certificates");
276
277 if (EQ (type, Qgnutls_x509pki))
278 {
279 message ("gnutls: deallocating x509 certificates");
280
281 x509_cred = XPROCESS (proc)->x509_cred;
282 gnutls_certificate_free_credentials (x509_cred);
283 }
284 else if (EQ (type, Qgnutls_anon))
285 {
286 message ("gnutls: deallocating anon certificates");
287
288 anon_cred = XPROCESS (proc)->anon_cred;
289 gnutls_anon_free_client_credentials (anon_cred);
290 }
291 else
292 {
293 error ("unknown credential type");
294 ret = GNUTLS_EMACS_ERROR_INVALID_TYPE;
295 }
296
297 if (GNUTLS_INITSTAGE (proc) >= GNUTLS_STAGE_INIT)
298 {
299 message ("gnutls: deinitializing");
300
301 Fgnutls_deinit (proc);
302 }
303 }
304
305 GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_EMPTY;
306
307 message ("gnutls: allocating credentials");
308
309 if (EQ (type, Qgnutls_x509pki))
310 {
311 message ("gnutls: allocating x509 credentials");
312
313 x509_cred = XPROCESS (proc)->x509_cred;
314 if (gnutls_certificate_allocate_credentials (&x509_cred) < 0)
315 memory_full ();
316 }
317 else if (EQ (type, Qgnutls_anon))
318 {
319 message ("gnutls: allocating anon credentials");
320
321 anon_cred = XPROCESS (proc)->anon_cred;
322 if (gnutls_anon_allocate_client_credentials (&anon_cred) < 0)
323 memory_full ();
324 }
325 else
326 {
327 error ("unknown credential type");
328 ret = GNUTLS_EMACS_ERROR_INVALID_TYPE;
329 }
330
331 if (ret < GNUTLS_E_SUCCESS)
332 return gnutls_make_error (ret);
333
334 GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_CRED_ALLOC;
335
336 message ("gnutls: setting the trustfile");
337
338 if (EQ (type, Qgnutls_x509pki))
339 {
340 if (STRINGP (trustfile))
341 {
342 ret = gnutls_certificate_set_x509_trust_file
343 (x509_cred,
344 XSTRING (trustfile)->data,
345 file_format);
346
347 if (ret < GNUTLS_E_SUCCESS)
348 return gnutls_make_error (ret);
349
350 message ("gnutls: processed %d CA certificates", ret);
351 }
352
353 message ("gnutls: setting the keyfile");
354
355 if (STRINGP (keyfile))
356 {
357 ret = gnutls_certificate_set_x509_crl_file
358 (x509_cred,
359 XSTRING (keyfile)->data,
360 file_format);
361
362 if (ret < GNUTLS_E_SUCCESS)
363 return gnutls_make_error (ret);
364
365 message ("gnutls: processed %d CRL(s)", ret);
366 }
367 }
368
369 GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_FILES;
370
371 message ("gnutls: gnutls_init");
372
373 ret = gnutls_init (&state, GNUTLS_CLIENT);
374
375 if (ret < GNUTLS_E_SUCCESS)
376 return gnutls_make_error (ret);
377
378 XPROCESS (proc)->gnutls_state = state;
379
380 GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_INIT;
381
382 message ("gnutls: setting the priority string");
383
384 ret = gnutls_priority_set_direct(state,
385 (char*) SDATA (priority_string),
386 NULL);
387
388 if (ret < GNUTLS_E_SUCCESS)
389 return gnutls_make_error (ret);
390
391 GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_PRIORITY;
392
393 message ("gnutls: setting the credentials");
394
395 if (EQ (type, Qgnutls_x509pki))
396 {
397 message ("gnutls: setting the x509 credentials");
398
399 ret = gnutls_cred_set (state, GNUTLS_CRD_CERTIFICATE, x509_cred);
400 }
401 else if (EQ (type, Qgnutls_anon))
402 {
403 message ("gnutls: setting the anon credentials");
404
405 ret = gnutls_cred_set (state, GNUTLS_CRD_ANON, anon_cred);
406 }
407 else
408 {
409 error ("unknown credential type");
410 ret = GNUTLS_EMACS_ERROR_INVALID_TYPE;
411 }
412
413 if (ret < GNUTLS_E_SUCCESS)
414 return gnutls_make_error (ret);
415
416 XPROCESS (proc)->anon_cred = anon_cred;
417 XPROCESS (proc)->x509_cred = x509_cred;
418 XPROCESS (proc)->gnutls_cred_type = type;
419
420 GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_CRED_SET;
421
422 return gnutls_make_error (GNUTLS_E_SUCCESS);
423}
424
425DEFUN ("gnutls-bye", Fgnutls_bye,
426 Sgnutls_bye, 2, 2, 0,
427 doc: /* Terminate current GNU TLS connection for PROCESS.
428The connection should have been initiated using `gnutls-handshake'.
429
430If CONT is not nil the TLS connection gets terminated and further
431receives and sends will be disallowed. If the return value is zero you
432may continue using the connection. If CONT is nil, GnuTLS actually
433sends an alert containing a close request and waits for the peer to
434reply with the same message. In order to reuse the connection you
435should wait for an EOF from the peer.
436
437This function may also return `gnutls-e-again', or
438`gnutls-e-interrupted'. */)
439 (Lisp_Object proc, Lisp_Object cont)
440{
441 gnutls_session_t state;
442 int ret;
443
444 CHECK_PROCESS (proc);
445
446 state = XPROCESS (proc)->gnutls_state;
447
448 ret = gnutls_bye (state,
449 NILP (cont) ? GNUTLS_SHUT_RDWR : GNUTLS_SHUT_WR);
450
451 return gnutls_make_error (ret);
452}
453
454DEFUN ("gnutls-handshake", Fgnutls_handshake,
455 Sgnutls_handshake, 1, 1, 0,
456 doc: /* Perform GNU TLS handshake for PROCESS.
457The identity of the peer is checked automatically. This function will
458fail if any problem is encountered, and will return a negative error
459code. In case of a client, if it has been asked to resume a session,
460but the server didn't, then a full handshake will be performed.
461
462If the error `gnutls-e-not-ready-for-handshake' is returned, you
463didn't call `gnutls-boot' first.
464
465This function may also return the non-fatal errors `gnutls-e-again',
466or `gnutls-e-interrupted'. In that case you may resume the handshake
467(by calling this function again). */)
468 (Lisp_Object proc)
469{
470 gnutls_session_t state;
471 int ret;
472
473 CHECK_PROCESS (proc);
474 state = XPROCESS (proc)->gnutls_state;
475
476 if (GNUTLS_INITSTAGE (proc) < GNUTLS_STAGE_HANDSHAKE_CANDO)
477 return Qgnutls_e_not_ready_for_handshake;
478
479
480 if (GNUTLS_INITSTAGE (proc) < GNUTLS_STAGE_TRANSPORT_POINTERS_SET)
481 {
482 /* for a network process in Emacs infd and outfd are the same
483 but this shows our intent more clearly. */
484 message ("gnutls: handshake: setting the transport pointers to %d/%d",
485 XPROCESS (proc)->infd, XPROCESS (proc)->outfd);
486
487 gnutls_transport_set_ptr2 (state, XPROCESS (proc)->infd,
488 XPROCESS (proc)->outfd);
489
490 GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_TRANSPORT_POINTERS_SET;
491 }
492
493 message ("gnutls: handshake: handshaking");
494 ret = gnutls_handshake (state);
495
496 GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_HANDSHAKE_TRIED;
497
498 if (GNUTLS_E_SUCCESS == ret)
499 {
500 /* here we're finally done. */
501 GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_READY;
502 }
503
504 return gnutls_make_error (ret);
505}
506
507void
508syms_of_gnutls (void)
509{
510 global_initialized = 0;
511
512 Qgnutls_code = intern_c_string ("gnutls-code");
513 staticpro (&Qgnutls_code);
514
515 Qgnutls_anon = intern_c_string ("gnutls-anon");
516 staticpro (&Qgnutls_anon);
517
518 Qgnutls_x509pki = intern_c_string ("gnutls-x509pki");
519 staticpro (&Qgnutls_x509pki);
520
521 Qgnutls_e_interrupted = intern_c_string ("gnutls-e-interrupted");
522 staticpro (&Qgnutls_e_interrupted);
523 Fput (Qgnutls_e_interrupted, Qgnutls_code,
524 make_number (GNUTLS_E_INTERRUPTED));
525
526 Qgnutls_e_again = intern_c_string ("gnutls-e-again");
527 staticpro (&Qgnutls_e_again);
528 Fput (Qgnutls_e_again, Qgnutls_code,
529 make_number (GNUTLS_E_AGAIN));
530
531 Qgnutls_e_invalid_session = intern_c_string ("gnutls-e-invalid-session");
532 staticpro (&Qgnutls_e_invalid_session);
533 Fput (Qgnutls_e_invalid_session, Qgnutls_code,
534 make_number (GNUTLS_E_INVALID_SESSION));
535
536 Qgnutls_e_not_ready_for_handshake =
537 intern_c_string ("gnutls-e-not-ready-for-handshake");
538 staticpro (&Qgnutls_e_not_ready_for_handshake);
539 Fput (Qgnutls_e_not_ready_for_handshake, Qgnutls_code,
540 make_number (GNUTLS_E_APPLICATION_ERROR_MIN));
541
542 defsubr (&Sgnutls_get_initstage);
543 defsubr (&Sgnutls_errorp);
544 defsubr (&Sgnutls_error_fatalp);
545 defsubr (&Sgnutls_error_string);
546 defsubr (&Sgnutls_boot);
547 defsubr (&Sgnutls_deinit);
548 defsubr (&Sgnutls_handshake);
549 defsubr (&Sgnutls_bye);
550}
551#endif
diff --git a/src/gnutls.h b/src/gnutls.h
new file mode 100644
index 00000000000..3a9030ba454
--- /dev/null
+++ b/src/gnutls.h
@@ -0,0 +1,60 @@
1/* GnuTLS glue for GNU Emacs.
2 Copyright (C) 2010 Free Software Foundation, Inc.
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software: you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation, either version 3 of the License, or
9(at your option) any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
18
19#ifndef EMACS_GNUTLS_DEFINED
20#define EMACS_GNUTLS_DEFINED
21
22#ifdef HAVE_GNUTLS
23#include <gnutls/gnutls.h>
24
25typedef enum
26{
27 /* Initialization stages. */
28 GNUTLS_STAGE_EMPTY = 0,
29 GNUTLS_STAGE_CRED_ALLOC,
30 GNUTLS_STAGE_FILES,
31 GNUTLS_STAGE_INIT,
32 GNUTLS_STAGE_PRIORITY,
33 GNUTLS_STAGE_CRED_SET,
34
35 /* Handshake stages. */
36 GNUTLS_STAGE_HANDSHAKE_CANDO = GNUTLS_STAGE_CRED_SET,
37 GNUTLS_STAGE_TRANSPORT_POINTERS_SET,
38 GNUTLS_STAGE_HANDSHAKE_TRIED,
39
40 GNUTLS_STAGE_READY,
41} gnutls_initstage_t;
42
43#define GNUTLS_EMACS_ERROR_INVALID_TYPE GNUTLS_E_APPLICATION_ERROR_MIN
44
45#define GNUTLS_INITSTAGE(proc) (XPROCESS (proc)->gnutls_initstage)
46
47#define GNUTLS_PROCESS_USABLE(proc) (GNUTLS_INITSTAGE(proc) >= GNUTLS_STAGE_READY)
48
49int
50emacs_gnutls_write (int fildes, gnutls_session_t state, char *buf,
51 unsigned int nbyte);
52int
53emacs_gnutls_read (int fildes, gnutls_session_t state, char *buf,
54 unsigned int nbyte);
55
56extern void syms_of_gnutls (void);
57
58#endif
59
60#endif
diff --git a/src/process.c b/src/process.c
index 048e2858e9f..ef086914704 100644
--- a/src/process.c
+++ b/src/process.c
@@ -105,6 +105,9 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
105#include "sysselect.h" 105#include "sysselect.h"
106#include "syssignal.h" 106#include "syssignal.h"
107#include "syswait.h" 107#include "syswait.h"
108#ifdef HAVE_GNUTLS
109#include "gnutls.h"
110#endif
108 111
109#if defined (USE_GTK) || defined (HAVE_GCONF) 112#if defined (USE_GTK) || defined (HAVE_GCONF)
110#include "xgselect.h" 113#include "xgselect.h"
@@ -583,6 +586,10 @@ make_process (Lisp_Object name)
583 p->read_output_skip = 0; 586 p->read_output_skip = 0;
584#endif 587#endif
585 588
589#ifdef HAVE_GNUTLS
590 p->gnutls_initstage = GNUTLS_STAGE_EMPTY;
591#endif
592
586 /* If name is already in use, modify it until it is unused. */ 593 /* If name is already in use, modify it until it is unused. */
587 594
588 name1 = name; 595 name1 = name;
@@ -1526,6 +1533,12 @@ usage: (start-process NAME BUFFER PROGRAM &rest PROGRAM-ARGS) */)
1526 XPROCESS (proc)->filter = Qnil; 1533 XPROCESS (proc)->filter = Qnil;
1527 XPROCESS (proc)->command = Flist (nargs - 2, args + 2); 1534 XPROCESS (proc)->command = Flist (nargs - 2, args + 2);
1528 1535
1536#ifdef HAVE_GNUTLS
1537 /* AKA GNUTLS_INITSTAGE(proc). */
1538 XPROCESS (proc)->gnutls_initstage = GNUTLS_STAGE_EMPTY;
1539 XPROCESS (proc)->gnutls_cred_type = Qnil;
1540#endif
1541
1529#ifdef ADAPTIVE_READ_BUFFERING 1542#ifdef ADAPTIVE_READ_BUFFERING
1530 XPROCESS (proc)->adaptive_read_buffering 1543 XPROCESS (proc)->adaptive_read_buffering
1531 = (NILP (Vprocess_adaptive_read_buffering) ? 0 1544 = (NILP (Vprocess_adaptive_read_buffering) ? 0
@@ -5099,7 +5112,13 @@ read_process_output (Lisp_Object proc, register int channel)
5099#endif 5112#endif
5100 if (proc_buffered_char[channel] < 0) 5113 if (proc_buffered_char[channel] < 0)
5101 { 5114 {
5102 nbytes = emacs_read (channel, chars + carryover, readmax); 5115#ifdef HAVE_GNUTLS
5116 if (NETCONN_P(proc) && GNUTLS_PROCESS_USABLE (proc))
5117 nbytes = emacs_gnutls_read (channel, XPROCESS (proc)->gnutls_state,
5118 chars + carryover, readmax);
5119 else
5120#endif
5121 nbytes = emacs_read (channel, chars + carryover, readmax);
5103#ifdef ADAPTIVE_READ_BUFFERING 5122#ifdef ADAPTIVE_READ_BUFFERING
5104 if (nbytes > 0 && p->adaptive_read_buffering) 5123 if (nbytes > 0 && p->adaptive_read_buffering)
5105 { 5124 {
@@ -5132,7 +5151,13 @@ read_process_output (Lisp_Object proc, register int channel)
5132 { 5151 {
5133 chars[carryover] = proc_buffered_char[channel]; 5152 chars[carryover] = proc_buffered_char[channel];
5134 proc_buffered_char[channel] = -1; 5153 proc_buffered_char[channel] = -1;
5135 nbytes = emacs_read (channel, chars + carryover + 1, readmax - 1); 5154#ifdef HAVE_GNUTLS
5155 if (NETCONN_P(proc) && GNUTLS_PROCESS_USABLE (proc))
5156 nbytes = emacs_gnutls_read (channel, XPROCESS (proc)->gnutls_state,
5157 chars + carryover + 1, readmax - 1);
5158 else
5159#endif
5160 nbytes = emacs_read (channel, chars + carryover + 1, readmax - 1);
5136 if (nbytes < 0) 5161 if (nbytes < 0)
5137 nbytes = 1; 5162 nbytes = 1;
5138 else 5163 else
@@ -5542,7 +5567,14 @@ send_process (volatile Lisp_Object proc, const unsigned char *volatile buf,
5542 else 5567 else
5543#endif 5568#endif
5544 { 5569 {
5545 rv = emacs_write (outfd, (char *) buf, this); 5570#ifdef HAVE_GNUTLS
5571 if (NETCONN_P(proc) && GNUTLS_PROCESS_USABLE (proc))
5572 rv = emacs_gnutls_write (outfd,
5573 XPROCESS (proc)->gnutls_state,
5574 (char *) buf, this);
5575 else
5576#endif
5577 rv = emacs_write (outfd, (char *) buf, this);
5546#ifdef ADAPTIVE_READ_BUFFERING 5578#ifdef ADAPTIVE_READ_BUFFERING
5547 if (p->read_output_delay > 0 5579 if (p->read_output_delay > 0
5548 && p->adaptive_read_buffering == 1) 5580 && p->adaptive_read_buffering == 1)
diff --git a/src/process.h b/src/process.h
index 35b01aba6a4..562d888f93f 100644
--- a/src/process.h
+++ b/src/process.h
@@ -24,6 +24,10 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
24#include <unistd.h> 24#include <unistd.h>
25#endif 25#endif
26 26
27#ifdef HAVE_GNUTLS
28#include "gnutls.h"
29#endif
30
27/* This structure records information about a subprocess 31/* This structure records information about a subprocess
28 or network connection. 32 or network connection.
29 33
@@ -76,6 +80,10 @@ struct Lisp_Process
76 /* Working buffer for encoding. */ 80 /* Working buffer for encoding. */
77 Lisp_Object encoding_buf; 81 Lisp_Object encoding_buf;
78 82
83#ifdef HAVE_GNUTLS
84 Lisp_Object gnutls_cred_type;
85#endif
86
79 /* After this point, there are no Lisp_Objects any more. */ 87 /* After this point, there are no Lisp_Objects any more. */
80 /* alloc.c assumes that `pid' is the first such non-Lisp slot. */ 88 /* alloc.c assumes that `pid' is the first such non-Lisp slot. */
81 89
@@ -121,6 +129,13 @@ struct Lisp_Process
121 needs to be synced to `status'. */ 129 needs to be synced to `status'. */
122 unsigned int raw_status_new : 1; 130 unsigned int raw_status_new : 1;
123 int raw_status; 131 int raw_status;
132
133#ifdef HAVE_GNUTLS
134 gnutls_initstage_t gnutls_initstage;
135 gnutls_session_t gnutls_state;
136 gnutls_certificate_client_credentials x509_cred;
137 gnutls_anon_client_credentials_t anon_cred;
138#endif
124}; 139};
125 140
126/* Every field in the preceding structure except for the first two 141/* Every field in the preceding structure except for the first two