comparison lisp/code-process.el @ 5814:a216b3c2b09e

Add TLS support. See xemacs-patches message with ID <CAHCOHQk6FNm2xf=XiGEpPq43+7WOzNZ=SuD9V79o3wb9WVCTrQ@mail.gmail.com>.
author Jerry James <james@xemacs.org>
date Tue, 07 Oct 2014 21:16:10 -0600
parents 91b3aa59f49b
children
comparison
equal deleted inserted replaced
5813:36dddf9d90d1 5814:a216b3c2b09e
269 If VAL is a function symbol, the function must return a coding system 269 If VAL is a function symbol, the function must return a coding system
270 or a cons of coding systems which are used as above. 270 or a cons of coding systems which are used as above.
271 271
272 See also the function `find-operation-coding-system'.") 272 See also the function `find-operation-coding-system'.")
273 273
274 (defun open-network-stream (name buffer host service &optional protocol) 274 (defun network-stream-get-response (stream start end-of-command)
275 (when end-of-command
276 (with-current-buffer (process-buffer stream)
277 (save-excursion
278 (goto-char start)
279 (while (and (memq (process-status stream) '(open run))
280 (not (re-search-forward end-of-command nil t)))
281 (accept-process-output stream 0 50)
282 (goto-char start))
283 ;; Return the data we got back, or nil if the process died.
284 (unless (= start (point))
285 (buffer-substring start (point)))))))
286
287 (defun network-stream-command (stream command eoc)
288 (when command
289 (let ((start (point-max (process-buffer stream))))
290 (process-send-string stream command)
291 (network-stream-get-response stream start eoc))))
292
293 (defun network-stream-open-plain (name buffer host service parameters)
294 (let ((start (point buffer))
295 (stream
296 (open-network-stream-internal name buffer host service
297 (plist-get parameters :protocol))))
298 (list stream
299 (network-stream-get-response stream start
300 (plist-get parameters :end-of-command))
301 nil
302 'plain)))
303
304 (defun network-stream-open-tls (name buffer host service parameters)
305 (with-current-buffer buffer
306 (let* ((start (point-max))
307 (stream
308 (open-network-stream-internal name buffer host service
309 (plist-get parameters :protocol) t)))
310 (if (null stream)
311 (list nil nil nil 'plain)
312 (let ((eoc (plist-get parameters :end-of-command))
313 (capability-command (plist-get parameters :capability-command)))
314 (list stream
315 (network-stream-get-response stream start eoc)
316 (network-stream-command stream capability-command eoc)
317 'tls))))))
318
319 (defun network-stream-certificate (host service parameters)
320 (let ((spec (plist-get :client-certificate parameters)))
321 (cond
322 ((listp spec)
323 ;; Either nil or a list with a key/certificate pair.
324 spec)
325 ((eq spec t)
326 (when (fboundp 'auth-source-search)
327 (let* ((auth-info
328 (car (auth-source-search :max 1
329 :host host
330 :port service)))
331 (key (plist-get auth-info :key))
332 (cert (plist-get auth-info :cert)))
333 (and key cert
334 (list key cert))))))))
335
336 (defun network-stream-open-starttls (name buffer host service parameters)
337 (let* ((start (point buffer))
338 (require-tls (eq (plist-get parameters :type) 'starttls))
339 (starttls-function (plist-get parameters :starttls-function))
340 (success-string (plist-get parameters :success))
341 (capability-command (plist-get parameters :capability-command))
342 (eoc (plist-get parameters :end-of-command))
343 (eo-capa (or (plist-get parameters :end-of-capability) eoc))
344 (protocol (plist-get parameters :protocol))
345 ;; Return (STREAM GREETING CAPABILITIES RESULTING-TYPE)
346 (stream (open-network-stream-internal name buffer host service
347 protocol))
348 (greeting (and (not (plist-get parameters :nogreeting))
349 (network-stream-get-response stream start eoc)))
350 (capabilities (network-stream-command stream capability-command
351 eo-capa))
352 (resulting-type 'plain)
353 starttls-available starttls-command error)
354
355 ;; First check whether the server supports STARTTLS at all.
356 (when (and capabilities success-string starttls-function)
357 (setq starttls-command
358 (funcall starttls-function capabilities)))
359 ;; If we have built-in STARTTLS support, try to upgrade the
360 ;; connection.
361 (when (and starttls-command
362 (setq starttls-available t)
363 (not (eq (plist-get parameters :type) 'plain)))
364 (when (let ((response
365 (network-stream-command stream starttls-command eoc)))
366 (and response (string-match success-string response)))
367 ;; The server said it was OK to begin STARTTLS negotiations.
368 (let ((cert (network-stream-certificate host service parameters)))
369 (condition-case nil
370 (tls-negotiate stream host (and cert (list cert)))
371 ;; If we get a tls-specific error (for instance if the
372 ;; certificate the server gives us is completely syntactically
373 ;; invalid), then close the connection and possibly (further
374 ;; down) try to create a non-encrypted connection.
375 (gnutls-error (delete-process stream))))
376 (if (memq (process-status stream) '(open run))
377 (setq resulting-type 'tls)
378 ;; We didn't successfully negotiate STARTTLS; if TLS
379 ;; isn't demanded, reopen an unencrypted connection.
380 (unless require-tls
381 (setq stream
382 (make-network-process :name name :buffer buffer
383 :host host :service service))
384 (network-stream-get-response stream start eoc)))
385 ;; Re-get the capabilities, which may have now changed.
386 (setq capabilities
387 (network-stream-command stream capability-command eo-capa))))
388
389 ;; If TLS is mandatory, close the connection if it's unencrypted.
390 (when (and require-tls
391 ;; ... but Emacs wasn't able to -- either no built-in
392 ;; support, or no gnutls-cli installed.
393 (eq resulting-type 'plain))
394 (setq error
395 (if (or (null starttls-command)
396 starttls-available)
397 "Server does not support TLS"
398 ;; See `starttls-available-p'. If this predicate
399 ;; changes to allow running under Windows, the error
400 ;; message below should be amended.
401 (if (memq system-type '(windows-nt ms-dos))
402 (concat "Emacs does not support TLS")
403 (concat "Emacs does not support TLS, and no external `"
404 (if starttls-use-gnutls
405 starttls-gnutls-program
406 starttls-program)
407 "' program was found"))))
408 (delete-process stream)
409 (setq stream nil))
410 ;; Return value:
411 (list stream greeting capabilities resulting-type error)))
412
413 ;; Requires that format-spec.el from gnus be loaded
414 (defun network-stream-open-shell (name buffer host service parameters)
415 (require 'format-spec)
416 (let* ((capability-command (plist-get parameters :capability-command))
417 (eo-capa (plist-get parameters :end-of-capability))
418 (eoc (plist-get parameters :end-of-command))
419 (start (point buffer))
420 (stream (let ((process-connection-type nil))
421 (start-process name buffer shell-file-name
422 shell-command-switch
423 (format-spec
424 (plist-get parameters :shell-command)
425 (format-spec-make
426 ?s host
427 ?p service))))))
428 (list stream
429 (network-stream-get-response stream start eoc)
430 (network-stream-command stream capability-command (or eo-capa eoc))
431 'plain)))
432
433 (defun open-network-stream (name buffer host service &rest parameters)
275 "Open a TCP connection for a service to a host. 434 "Open a TCP connection for a service to a host.
276 Return a process object to represent the connection. 435 Normally, return a process object to represent the connection. If the
436 :return-list parameter is non-NIL, instead return a list; see below.
277 Input and output work as for subprocesses; `delete-process' closes it. 437 Input and output work as for subprocesses; `delete-process' closes it.
278 NAME is name for process. It is modified if necessary to make it unique. 438 NAME is name for process. It is modified if necessary to make it unique.
279 BUFFER is the buffer (or buffer-name) to associate with the process. 439 BUFFER is the buffer (or buffer-name) to associate with the process.
280 Process output goes at end of that buffer, unless you specify 440 Process output goes at end of that buffer, unless you specify
281 an output stream or filter function to handle the output. 441 an output stream or filter function to handle the output.
282 BUFFER may be also nil, meaning that this process is not associated 442 BUFFER may be also nil, meaning that this process is not associated
283 with any buffer. 443 with any buffer.
284 Third arg is name of the host to connect to, or its IP address. 444 Third arg is name of the host to connect to, or its IP address.
285 Fourth arg SERVICE is name of the service desired, or an integer 445 Fourth arg SERVICE is name of the service desired, or an integer
286 specifying a port number to connect to. 446 specifying a port number to connect to.
287 Fifth argument PROTOCOL is a network protocol. Currently 'tcp 447
288 (Transmission Control Protocol) and 'udp (User Datagram Protocol) are 448 The remaining PARAMETERS should be a sequence of keywords and values:
289 supported. When omitted, 'tcp is assumed. 449 - :protocol is a network protocol. Currently 'tcp (Transmission Control
450 Protocol) and 'udp (User Datagram Protocol) are supported. When
451 omitted, 'tcp is assumed.
452 - :type specifies the connection type; it is one of the following:
453 nil or `network': begin with an ordinary network connection, and if
454 the parameters :success and :capability-command are also
455 supplied, try to upgrade to an encrypted connection via
456 STARTTLS. If that fails (e.g., HOST does not support TLS),
457 retain an unencrypted connection.
458 `plain': an ordinary, unencrypted network connection.
459 `starttls': begin with an ordinary network connection and try to
460 upgrade via STARTTLS. If that fails, drop the connection
461 and return a killed process object.
462 `tls': a TLS connection.
463 `ssl': a synonym for `tls'.
464 `shell': a shell connection.
465 - :return-list specifies this function's return value.
466 If omitted or nil, return a process object as usual. Otherwise, return
467 (PROC . PROPS), where PROC is a process object and PROPS is a plist of
468 connection properties, with these keywords:
469 :greeting: the greeting returned by HOST (a string), or nil.
470 :capabilities: a string representing HOST's capabilities, or nil if none
471 could be found.
472 :type: the resulting connection type, `plain' (unencrypted) or `tls'
473 (encrypted).
474 - :end-of-command specifies a regexp matching the end of a command.
475 - :end-of-capability specifies a regexp matching the end of the response
476 to the command specified for :capability-command. It defaults to the
477 regexp specified for :end-of-command.
478 - :success specifies a regexp matching a message indicating a successful
479 STARTTLS negotiation. For example, the default should be \"^3\" for an
480 NNTP connection.
481 - :capability-command specifies a command used to query HOST for its
482 capabilities. For example, this should be \"1 CAPABILITY\\r\\n\" for
483 IMAP.
484 - :starttls-function specifies a function for handling STARTTLS. This
485 function should take one parameter, the response to the capability
486 command, and should return the command to switch on STARTTLS if the
487 server supports it, or nil otherwise.
488 - :always-query-capabilities, if non-nil, indicates that the server should
489 be queried for capabilities even if constructing a `plain' network
490 connection.
491 - :client-certificate is either a list (certificate-key-filename
492 certificate-filename), or `t', meaning that `auth-source' will be
493 queried for the key and certificate. This parameter is used only when
494 constructing a TLS or STARTTLS connection.
495 - :use-starttls-if-possible, if non-nil, indicates that STARTTLS should
496 be used even if TLS support is not compiled in to XEmacs.
497 - :nogreeting, if non-nil, indicates that we should not wait for a
498 greeting from the server.
499 - :nowait, if non-nil, indicates that an asynchronous connection should be
500 made, if possible. NOTE: this is currently unimplemented.
501
502 For backwards compatibility, if exactly five arguments are given, the fifth
503 must be one of nil, 'tcp, or 'udp. Both nil and 'tcp select TCP (Transmission
504 Control Protocol) and 'udp selects UDP (User Datagram Protocol).
290 505
291 Output via `process-send-string' and input via buffer or filter (see 506 Output via `process-send-string' and input via buffer or filter (see
292 `set-process-filter') are stream-oriented. That means UDP datagrams are 507 `set-process-filter') are stream-oriented. That means UDP datagrams are
293 not guaranteed to be sent and received in discrete packets. (But small 508 not guaranteed to be sent and received in discrete packets. (But small
294 datagrams around 500 bytes that are not truncated by `process-send-string' 509 datagrams around 500 bytes that are not truncated by `process-send-string'
313 proceed essentially independently one from the other, as in `start-process'. 528 proceed essentially independently one from the other, as in `start-process'.
314 529
315 You can change the coding systems later on using 530 You can change the coding systems later on using
316 `set-process-coding-system', `set-process-input-coding-system', or 531 `set-process-coding-system', `set-process-input-coding-system', or
317 `set-process-output-coding-system'." 532 `set-process-output-coding-system'."
533 (when (and (car parameters) (not (cdr parameters)))
534 (setq parameters (list :protocol (car parameters))))
318 (let (cs-r cs-w) 535 (let (cs-r cs-w)
319 (let (ret) 536 (let (ret)
320 (catch 'found 537 (catch 'found
321 (let ((alist network-coding-system-alist) 538 (let ((alist network-coding-system-alist)
322 (case-fold-search nil) 539 (case-fold-search nil)
349 (car default-network-coding-system) 566 (car default-network-coding-system)
350 'undecided)) 567 'undecided))
351 (coding-system-for-write 568 (coding-system-for-write
352 (or coding-system-for-write cs-w 569 (or coding-system-for-write cs-w
353 (cdr default-network-coding-system) 570 (cdr default-network-coding-system)
354 'raw-text))) 571 'raw-text))
355 (open-network-stream-internal name buffer host service protocol)))) 572 (type (plist-get parameters :type))
573 (return-list (plist-get parameters :return-list))
574 (capability-command (plist-get parameters :capability-command)))
575 (if (and (not return-list)
576 (or (eq type 'plain)
577 (and (or (null type) (eq type 'network))
578 (not (and (plist-get parameters :success)
579 capability-command)))))
580 ;; The simplest case: a plain connection
581 (open-network-stream-internal name buffer host service
582 (plist-get parameters :protocol))
583 (let ((work-buffer (or buffer
584 (generate-new-buffer " *stream buffer*")))
585 (fun (cond ((and (eq type 'plain)
586 (not (plist-get parameters
587 :always-query-capabilities)))
588 #'network-stream-open-plain)
589 ((memq type '(nil network starttls plain))
590 #'network-stream-open-starttls)
591 ((memq type '(tls ssl)) #'network-stream-open-tls)
592 ((eq type 'shell) 'network-stream-open-shell)
593 (t (error "Invalid connection type" type))))
594 result)
595 (unwind-protect
596 (setq result
597 (funcall fun name work-buffer host service parameters))
598 (unless buffer
599 (and (processp (car result))
600 (set-process-buffer (car result) nil))
601 (kill-buffer work-buffer)))
602 (if return-list
603 (list (car result)
604 :greeting (nth 1 result)
605 :capabilities (nth 2 result)
606 :type (nth 3 result)
607 :error (nth 4 result))
608 (car result)))))))
356 609
357 (defun set-buffer-process-coding-system (decoding encoding) 610 (defun set-buffer-process-coding-system (decoding encoding)
358 "Set coding systems for the process associated with the current buffer. 611 "Set coding systems for the process associated with the current buffer.
359 DECODING is the coding system to be used to decode input from the process, 612 DECODING is the coding system to be used to decode input from the process,
360 ENCODING is the coding system to be used to encode output to the process. 613 ENCODING is the coding system to be used to encode output to the process.