-
Notifications
You must be signed in to change notification settings - Fork 29
/
Copy pathauthentication-mechanisms.lisp
118 lines (94 loc) · 4.39 KB
/
authentication-mechanisms.lisp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
;;;; +----------------------------------------------------------------+
;;;; | DBUS |
;;;; +----------------------------------------------------------------+
(defpackage #:dbus/authentication-mechanisms
(:use #:cl #:dbus/utils #:dbus/protocols #:dbus/conditions)
(:import-from #:split-sequence #:split-sequence)
(:import-from #:alexandria #:starts-with-subseq)
(:import-from #:babel #:octets-to-string)
(:export
#:find-authentication-mechanism-class
#:standard-authentication-mechanism
#:generic-authentication-mechanism
#:receive-authentication-response
#:send-authentication-command))
(in-package #:dbus/authentication-mechanisms)
;;;; Authentication mechanisms
(define-name-class-mapping
:class authentication-mechanism
:map *authentication-mechanism-classes*
:find find-authentication-mechanism-class)
(defclass standard-authentication-mechanism (authentication-mechanism)
((name :initarg :name :reader authentication-mechanism-name)
(textual :initarg :textual :reader authentication-mechanism-textual-p))
(:default-initargs :textual nil)
(:documentation "Represents a standard authentication mechanism."))
(defclass generic-authentication-mechanism (standard-authentication-mechanism)
()
(:documentation "Represents an authentication mechanism that is not
supported by the D-BUS system."))
(defmethod feed-authentication-mechanism ((mechanism generic-authentication-mechanism) challenge)
(declare (ignore challenge))
(values :error))
(defun parse-authentication-response (line &key as-string)
"Parse authentication response line and return two values:
:REJECTED
Current authentication exchanged failed; the second value is a
list of authentication mechanisms.
:OK
Client has been authenticated; the second value is the server's
UUID.
:DATA
Data are available; the second value is either an octet vector or
a string, depending on the value of AS-STRING.
:AGREE-UNIX-FD
The server supports Unix file descriptor passing; the second value
is NIL.
:ERROR
Bad command or arguments; the second value is NIL.
:UNEXPECTED
Unexpected command; the second value is the response line."
(cond ((starts-with-subseq "REJECTED " line)
(values :rejected (split-sequence #\Space line :start 9)))
((starts-with-subseq "OK " line)
(values :ok (subseq line 3)))
((starts-with-subseq "DATA " line)
(let ((data (decode-hex-string line :start 5)))
(values :data (if as-string (octets-to-string data :encoding :utf-8) data))))
((equal "AGREE_UNIX_FD" line)
(values :agree-unix-fd nil))
((starts-with-subseq "ERROR " line)
(values :error nil))
(t (values :unexpected line))))
(defun format-authentication-command (command &rest arguments)
"Format and return authentication command line. Command is one
of :AUTH, :CANCEL, :BEGIN, :DATA, :NEGOTIATE-UNIX-FD, or :ERROR, and
takes arguments in accordance with the D-BUS specification."
(ecase command
(:auth
(destructuring-bind (&optional mechanism initial-response) arguments
(format nil "AUTH ~@[~A~]~@[ ~A~]" mechanism initial-response)))
(:cancel "CANCEL ")
(:begin "BEGIN ")
(:data
(destructuring-bind (data) arguments
(format nil "DATA ~A" (encode-hex-string data))))
(:negotiate-unix-fd "NEGOTIATE_UNIX_FD ")
(:error
(destructuring-bind (&optional explanation) arguments
(format nil "ERROR ~@[~A~]" explanation)))))
(defun receive-authentication-response (connection &key as-string expect)
"Receive authentication response line from the server. If EXPECT is
NIL, just return the response command and argument. Otherwise,
compare its value to the response command. If they are the same, just
return the argument; otherwise, signal an authentication error."
(multiple-value-bind (command argument)
(parse-authentication-response (receive-line connection)
:as-string as-string)
(cond ((null expect) (values command argument))
((eq command expect) argument)
(t (error 'authentication-error :command command :argument argument)))))
(defun send-authentication-command (connection command &rest arguments)
"Send an authentication command to the server."
(send-line (apply #'format-authentication-command command arguments)
connection))