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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
| | ;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2017 nee <nee-git@hidamari.blue>
;;;
;;; This file is part of GNU Guix.
;;;
;;; GNU Guix is free software; you can redistribute it and/or modify it
;;; under the terms of the GNU General Public License as published by
;;; the Free Software Foundation; either version 3 of the License, or (at
;;; your option) any later version.
;;;
;;; GNU Guix is distributed in the hope that it will be useful, but
;;; WITHOUT ANY WARRANTY; without even the implied warranty of
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;;; GNU General Public License for more details.
;;;
;;; You should have received a copy of the GNU General Public License
;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
(define-module (gnu services telephony)
#:use-module (gnu services)
#:use-module (gnu services shepherd)
#:use-module (gnu system shadow)
#:use-module (gnu packages admin)
#:use-module (gnu packages telephony)
#:use-module (guix records)
#:use-module (guix gexp)
#:use-module (srfi srfi-1)
#:use-module (ice-9 match)
#:export (murmur-configuration
make-murmur-configuration
murmur-configuration?
murmur-configuration-package
murmur-configuration-user
murmur-configuration-group
murmur-configuration-port
murmur-configuration-welcome-text
murmur-configuration-server-password
murmur-configuration-max-users
murmur-configuration-max-user-bandwidth
murmur-configuration-database-file
murmur-configuration-log-file
murmur-configuration-pid-file
murmur-configuration-autoban-attempts
murmur-configuration-autoban-timeframe
murmur-configuration-autoban-time
murmur-configuration-opus-threshold
murmur-configuration-channel-nesting-limit
murmur-configuration-channelname-regex
murmur-configuration-username-regex
murmur-configuration-text-message-length
murmur-configuration-image-message-length
murmur-configuration-cert-required?
murmur-configuration-remember-channel?
murmur-configuration-allow-html?
murmur-configuration-allow-ping?
murmur-configuration-bonjour?
murmur-configuration-send-version?
murmur-configuration-log-days
murmur-configuration-obfuscate-ips?
murmur-configuration-ssl-cert
murmur-configuration-ssl-key
murmur-configuration-ssl-dh-params
murmur-configuration-ssl-ciphers
murmur-configuration-public-registration
murmur-configuration-file
murmur-public-registration-configuration
make-murmur-public-registration-configuration
murmur-public-registration-configuration?
murmur-public-registration-configuration-name
murmur-public-registration-configuration-url
murmur-public-registration-configuration-password
murmur-public-registration-configuration-hostname
murmur-service-type))
;; https://github.com/mumble-voip/mumble/blob/master/scripts/murmur.ini
(define-record-type* <murmur-configuration> murmur-configuration
make-murmur-configuration
murmur-configuration?
(package murmur-configuration-package ;<package>
(default mumble))
(user murmur-configuration-user
(default "murmur"))
(group murmur-configuration-group
(default "murmur"))
(port murmur-configuration-port
(default 64738))
(welcome-text murmur-configuration-welcome-text
(default ""))
(server-password murmur-configuration-server-password
(default ""))
(max-users murmur-configuration-max-users
(default 100))
(max-user-bandwidth murmur-configuration-max-user-bandwidth
(default #f))
(database-file murmur-configuration-database-file
(default "/var/lib/murmur/db.sqlite"))
(log-file murmur-configuration-log-file
(default "/var/log/murmur/murmur.log"))
(pid-file murmur-configuration-pid-file
(default "/var/run/murmur/murmur.pid"))
(autoban-attempts murmur-configuration-autoban-attempts
(default 10))
(autoban-timeframe murmur-configuration-autoban-timeframe
(default 120))
(autoban-time murmur-configuration-autoban-time
(default 300))
(opus-threshold murmur-configuration-opus-threshold
(default 100)) ; integer percent
(channel-nesting-limit murmur-configuration-channel-nesting-limit
(default 10))
(channelname-regex murmur-configuration-channelname-regex
(default #f))
(username-regex murmur-configuration-username-regex
(default #f))
(text-message-length murmur-configuration-text-message-length
(default 5000))
(image-message-length murmur-configuration-image-message-length
(default (* 128 1024))) ; 128 Kilobytes
(cert-required? murmur-configuration-cert-required?
(default #f))
(remember-channel? murmur-configuration-remember-channel?
(default #f))
(allow-html? murmur-configuration-allow-html?
(default #f))
(allow-ping? murmur-configuration-allow-ping?
(default #f))
(bonjour? murmur-configuration-bonjour?
(default #f))
(send-version? murmur-configuration-send-version?
(default #f))
(log-days murmur-configuration-log-days
(default 31))
(obfuscate-ips? murmur-obfuscate-ips?
(default #t))
(ssl-cert murmur-configuration-ssl-cert
(default #f))
(ssl-key murmur-configuration-ssl-key
(default #f))
(ssl-dh-params murmur-configuration-ssl-dh-params
(default #f))
(ssl-ciphers murmur-configuration-ssl-ciphers
(default #f))
(public-registration murmur-configuration-public-registration
(default #f)) ; <murmur-public-registration-configuration>
(file murmur-configuration-file
(default #f)))
(define-record-type* <murmur-public-registration-configuration>
murmur-public-registration-configuration
make-murmur-public-registration-configuration
murmur-public-registration-configuration?
(name murmur-public-registration-configuration-name)
(password murmur-public-registration-configuration-password)
(url murmur-public-registration-configuration-url)
(hostname murmur-public-registration-configuration-hostname
(default #f)))
(define (flatten . lst)
"Return a list that recursively concatenates all sub-lists of LST."
(define (flatten1 head out)
(if (list? head)
(fold-right flatten1 out head)
(cons head out)))
(fold-right flatten1 '() lst))
(define (default-murmur-config config)
(match-record
config
<murmur-configuration>
(user port welcome-text server-password max-users max-user-bandwidth
database-file log-file pid-file autoban-attempts autoban-timeframe
autoban-time opus-threshold channel-nesting-limit channelname-regex
username-regex text-message-length image-message-length cert-required?
remember-channel? allow-html? allow-ping? bonjour? send-version?
log-days obfuscate-ips? ssl-cert ssl-key ssl-dh-params ssl-ciphers
public-registration)
(apply mixed-text-file "murmur.ini"
(flatten
"welcometext=" welcome-text "\n"
"port=" (number->string port) "\n"
(if server-password (list "serverpassword=" server-password "\n") '())
(if max-user-bandwidth (list "bandwidth="
(number->string max-user-bandwidth) "\n")
'())
"users=" (number->string max-users) "\n"
"uname=" user "\n"
"database=" database-file "\n"
"logfile=" log-file "\n"
"pidfile=" pid-file "\n"
(if autoban-attempts (list "autobanAttempts=" (number->string autoban-attempts) "\n") '())
(if autoban-timeframe (list "autobanTimeframe=" (number->string autoban-timeframe) "\n") '())
(if autoban-time (list "autobanTime=" (number->string autoban-time) "\n") '())
(if opus-threshold (list "opusthreshold=" (number->string opus-threshold) "\n") '())
(if channel-nesting-limit (list "channelnestinglimit=" (number->string channel-nesting-limit) "\n") '())
(if channelname-regex (list "channelname=" channelname-regex "\n") '())
(if username-regex (list "username=" username-regex "\n") '())
(if text-message-length (list "textmessagelength=" (number->string text-message-length) "\n") '())
(if image-message-length (list "imagemessagelength=" (number->string image-message-length) "\n") '())
(if log-days (list "logdays=" (number->string log-days) "\n") '())
"obfuscate=" (if obfuscate-ips? "true" "false") "\n"
"certrequired=" (if cert-required? "true" "false") "\n"
"rememberchannel=" (if remember-channel? "true" "false") "\n"
"allowhtml=" (if allow-html? "true" "false") "\n"
"allowping=" (if allow-ping? "true" "false") "\n"
"bonjour=" (if bonjour? "true" "false") "\n"
"sendversion=" (if send-version? "true" "false") "\n"
(cond ((and ssl-cert ssl-key)
(list
"sslCert=" ssl-cert "\n"
"sslKey=" ssl-key "\n"))
((or ssl-cert ssl-key)
(error "ssl-cert and ssl-key must both be set"
ssl-cert ssl-key))
(else '()))
(if ssl-dh-params (list "sslDHParams=" ssl-dh-params) '())
(if ssl-ciphers (list "sslCiphers=" ssl-ciphers) '())
(match public-registration
(#f '())
(($ <murmur-public-registration-configuration>
name password url hostname)
(if (and (or (not server-password) (string-null? server-password))
allow-ping?)
(list
"registerName=" name "\n"
"registerPassword=" password "\n"
"registerUrl=" url "\n"
(if hostname
(string-append "registerHostname=" hostname "\n")
""))
(error "To publicly register your murmur server your server must be publicy visible
and users must be able to join without a password. To fix this set:
(allow-ping? #t)
(server-password \"\")
Or set public-registration to #f"))))))))
(define (murmur-activation config)
#~(begin
(use-modules (guix build utils))
(let* ((log-dir (dirname #$(murmur-configuration-log-file config)))
(pid-dir (dirname #$(murmur-configuration-pid-file config)))
(db-dir (dirname #$(murmur-configuration-database-file config)))
(user (getpwnam #$(murmur-configuration-user config)))
(init-dir
(lambda (name dir)
(format #t "creating murmur ~a directory '~a'\n" name dir)
(mkdir-p dir)
(chown dir (passwd:uid user) (passwd:gid user))
(chmod dir #o700)))
(ini #$(or (murmur-configuration-file config)
(default-murmur-config config))))
(init-dir "log" log-dir)
(init-dir "pid" pid-dir)
(init-dir "database" db-dir)
(format #t "murmur: use config file: ~a~%\n" ini)
(format #t "murmur: to set the SuperUser password run:
`~a -ini ~a -readsupw`\n"
#$(file-append (murmur-configuration-package config)
"/bin/murmurd") ini)
#t)))
(define murmur-accounts
(match-lambda
(($ <murmur-configuration> _ user group)
(list
(user-group
(name group)
(system? #t))
(user-account
(name user)
(group group)
(system? #t)
(comment "Murmur Daemon")
(home-directory "/var/empty")
(shell (file-append shadow "/sbin/nologin")))))))
(define (murmur-shepherd-service config)
(list (shepherd-service
(provision '(murmur))
(documentation "Run the Murmur Mumble server.")
(requirement '(networking))
(start #~(make-forkexec-constructor
'(#$(file-append (murmur-configuration-package config)
"/bin/murmurd")
"-ini"
#$(or (murmur-configuration-file config)
(default-murmur-config config)))
#:pid-file #$(murmur-configuration-pid-file config)))
(stop #~(make-kill-destructor)))))
(define murmur-service-type
(service-type (name 'murmur)
(description
"Run the Murmur voice-over-IP (VoIP) server of the Mumble
suite.")
(extensions
(list (service-extension shepherd-root-service-type
murmur-shepherd-service)
(service-extension activation-service-type
murmur-activation)
(service-extension account-service-type
murmur-accounts)))
(default-value (murmur-configuration))))
|