Package: guix-patches;
Reported by: Maxim Cournoyer <maxim.cournoyer <at> gmail.com>
Date: Mon, 31 Mar 2025 02:29:07 UTC
Severity: normal
Tags: patch
Done: Maxim Cournoyer <maxim.cournoyer <at> gmail.com>
Bug is archived. No further changes may be made.
Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):
From: Maxim Cournoyer <maxim.cournoyer <at> gmail.com> To: guix-patches <at> gnu.org Cc: Maxim Cournoyer <maxim.cournoyer <at> gmail.com> Subject: [PATCH] services: Add ngircd-service-type. Date: Mon, 31 Mar 2025 11:27:48 +0900
* gnu/services/messaging.scm (pascal-case, ngircd-serialize-string) (ngircd-serialize-boolean, ngircd-serialize-file-like) (ngircd-serialize-list-of-strings, ngircd-serialize-list-of-ports) (ngircd-serialize-number, ngircd-serialize-port) (string-or-number?, ngircd-serialize-string-or-number): New procedures. (ngircd-global, ngircd-limits, ngircd-options, ngircd-ssl) (ngircd-operator, ngircd-server, ngircd-channel) (ngircd-configuration): New configurations. (serialize-ngircd-global, serialize-ngircd-limits) (serialize-ngircd-options, serialize-ngircd-operator) (serialize-list-of-ngircd-operators, serialize-ngircd-server) (serialize-ngircd-channel, serialize-list-of-ngircd-channels) (serialize-ngircd-configuration): New procedures. (list-of-ngircd-operators?, list-of-ngircd-servers?) (list-of-ngircd-channels?): New predicates. (ngircd-generate-documentation): New procedure. (ngircd-user+group, ngircd-account, ngircd-wrapper): Likewise. (ngircd-shepherd-service): New shepherd service. (%ngircd-activation): New procedure. (ngircd-service-type): New service type. * gnu/tests/messaging.scm (%ngircd-os): New variable. (run-ngircd-test): New procedure. (%test-ngircd): New test. * doc/guix.texi (Messaging Services): Document it. Change-Id: I3ce9a7fd0b33afab22cf15942a1db0cf5b12bfdb --- doc/guix.texi | 394 ++++++++++++++++++++++ gnu/services/messaging.scm | 650 +++++++++++++++++++++++++++++++++++++ gnu/tests/messaging.scm | 73 +++++ 3 files changed, 1117 insertions(+) diff --git a/doc/guix.texi b/doc/guix.texi index f6d774fd13..06aec854b3 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -30351,6 +30351,400 @@ Messaging Services @end table @end deftp +@subsubheading ngIRCd service + +@cindex IRCd, Internet Relay Chat daemon +@cindex IRC daemon service +@cindex IRC server service +@cindex IRC (Internet Relay Chat) + +@url{https://ngircd.barton.de/, ngIRCd}, is a lightweight @acronym{IRCd, +Internet Relay Chat daemon}, which can be used to host your own IRC +server. + +@defvar ngircd-service-type +The service type for ngIRCd. Its value is a @code{ngircd-configuration} +object, documented below. +@end defvar + +@c To regenerate the rest of this section documentation, use the +@c `ngircd-generate-documentation' procedure in (gnu services +@c messaging). + +@c %start of fragment + +@deftp {Data Type} ngircd-configuration +Available @code{ngircd-configuration} fields are: + +@table @asis +@item @code{ngircd} (default: @code{ngircd}) (type: file-like) +The @code{ngircd} package to use. + +@item @code{debug?} (default: @code{#f}) (type: boolean) +Turn on debugging messages. + +@item @code{global} (type: ngircd-global) +A ngircd-global record object used to specify global options. + +@item @code{limits} (type: maybe-ngircd-limits) +The ngircd-limits record object used to specify limits options. + +@item @code{options} (type: maybe-ngircd-options) +The ngircd-options record object used to specify optional features and +configuration options. + +@item @code{ssl} (type: maybe-ngircd-ssl) +The ngircd-ssl record object used to specify the SSL-related options. + +@item @code{operators} (type: maybe-list-of-ngircd-operators) +A list of ngircd-operator record objects used to specify the operators. + +@item @code{servers} (type: maybe-list-of-ngircd-servers) +A list of ngircd-server record objects used to specify other remote +servers to connect to. + +@item @code{channels} (type: maybe-list-of-ngircd-channels) +A list of ngircd-channels record objects specifying pre-defined channels +to be created by the server when starting up. + +@end table + +@end deftp + + +@c %end of fragment + +@c %start of fragment + +@deftp {Data Type} ngircd-global +Available @code{ngircd-global} fields are: + +@table @asis +@item @code{name} (type: maybe-string) +Server name in the IRC network. This is an individual name of the IRC +server, it is not related to the DNS host name. It must be unique in +the IRC network and must contain at least one dot (@samp{.}) character. +When not set, ngIRCd tries to deduce a valid IRC server name from the +local host name. + +@item @code{admin-info-1} (type: maybe-string) +First administrator information. + +@item @code{admin-info-2} (type: maybe-string) +Second administrator information. + +@item @code{admin-email} (type: maybe-string) +Email to reach administrators. + +@item @code{help-file} (type: maybe-file-like) +File-like containing the ngIRCd help text. + +@item @code{info} (type: maybe-string) +Info text of the server. This will be shown by WHOIS and LINKS requests +for example. + +@item @code{listen} (default: @code{("::" "0.0.0.0")}) (type: maybe-list-of-strings) +A list of IP address on which the server should listen. By default it +listens on all interfaces. + +@item @code{motd-file} (type: file-like) +Text file with the @i{message of the day} (MOTD). This message will be +shown to all users connecting to the server. + +@item @code{motd-phrase} (type: maybe-string) +A simple Phrase (<127 chars) to use if you don't want to use a MOTD +file. + +@item @code{network} (type: maybe-string) +The name of the IRC network to which this server belongs. This name is +optional, should only contain ASCII characters, and can't contain +spaces. It is only used to inform clients. + +@item @code{password} (type: maybe-string) +Global password or all users needed to connect to the server. By +default, no password is required. PAM must be disabled for this option +to have an effect. + +@item @code{pid-file} (default: @code{"/run/ngircd/ngircd.pid"}) (type: string) +The file name where the PID of ngIRCd is written after it starts. + +@item @code{ports} (default: @code{(6667)}) (type: maybe-list-of-ports) +Port number(s) on which the server should listen for @emph{unencrypted} +connections. + +@item @code{server-uid} (default: @code{"ngircd"}) (type: string-or-number) +The user that the @command{ngircd} command should run as. + +@item @code{server-gid} (default: @code{"ngircd"}) (type: string-or-number) +The group that the @command{ngircd} command should run as. + +@end table + +@end deftp + + +@c %end of fragment + +@c %start of fragment + +@deftp {Data Type} ngircd-limits +Available @code{ngircd-limits} fields are: + +@table @asis +@item @code{connect-retry} (default: @code{60}) (type: maybe-number) +The number of seconds the server should wait before re-attempting to +establish a link to not yet (or no longer) connected servers. + +@item @code{max-connections} (default: @code{0}) (type: maybe-number) +Maximum number of simultaneous in- and outbound connections the server +is allowed to accept. There is no limit by default. + +@item @code{max-connections-ip} (default: @code{5}) (type: maybe-number) +Maximum number of simultaneous connections from a single IP address that +the server will accept. This configuration options lowers the risk of +denial of service attacks (DoS). Set to 0 to remove the limit. + +@item @code{max-joins} (default: @code{10}) (type: maybe-number) +Maximum number of channels a user can be member of. Set to 0 to remove +the limit. + +@item @code{max-list-size} (default: @code{100}) (type: maybe-number) +Maximum number of channels returned in response to a LIST command. + +@item @code{ping-timeout} (default: @code{120}) (type: maybe-number) +Number of seconds of inactivity after which the server will send a PING +to the peer to test whether it is alive or not. + +@item @code{pong-timeout} (default: @code{20}) (type: maybe-number) +If a client fails to answer a PING with a PONG within this amount of +seconds, it will be disconnected by the server. + +@end table + +@end deftp + + +@c %end of fragment + +@c %start of fragment + +@deftp {Data Type} ngircd-options +Available @code{ngircd-options} fields are: + +@table @asis +@item @code{allowed-channel-types} (default: @code{"#&+"}) (type: maybe-string) +List of allowed channel types (channel prefixes) for newly created +channels on the local server. By default, all supported channel types +are allowed. + +@item @code{allow-remote-oper?} (default: @code{#f}) (type: maybe-boolean) +If this option is active, IRC operators connected to remote servers are +allowed to control this local server using administrative commands, for +example like CONNECT, DIE, SQUIT, etc. + +@item @code{connect-ipv4?} (default: @code{#t}) (type: maybe-boolean) +Set to @code{#f} to prevent ngIRCd from connecting to other IRC servers +using the IPv4 protocol, allowed by default. + +@item @code{connect-ipv6?} (default: @code{#t}) (type: maybe-boolean) +Set to @code{#f} to prevent ngIRCd from connecting to other IRC servers +using the IPv6 protocol, allowed by default. + +@item @code{dns?} (default: @code{#t}) (type: maybe-boolean) +Set to @code{#f} to disable DNS lookups when clients connect. If you +configure the daemon to connect to other servers, ngIRCd may still +perform a DNS lookup if required. + +@item @code{more-privacy?} (default: @code{#f}) (type: maybe-boolean) +Set this to @code{#t} to have ngIRCd censor user idle time, logon time +as well as the PART/QUIT messages (that sometimes used to inform +everyone about which client software is being used). WHOWAS requests +are also silently ignored, and NAMES output doesn't list any clients for +non-members. This option is most useful when ngIRCd is being used +together with anonymizing software such as TOR or I2P and one does not +wish to make it too easy to collect statistics on the users. + +@item @code{notice-before-registration?} (default: @code{#f}) (type: maybe-boolean) +Normally ngIRCd doesn't send any messages to a client until it is +registered. Enable this option to let the daemon send @samp{NOTICE *} +messages to clients while connecting. + +@item @code{oper-can-use-mode?} (default: @code{#f}) (type: maybe-boolean) +Should IRC Operators be allowed to use the MODE command even if they are +not(!) channel-operators? + +@item @code{oper-chan-p-auto-op?} (default: @code{#t}) (type: maybe-boolean) +Should IRC Operators get AutoOp (+o) in persistent (+P) channels? + +@item @code{oper-server-mode?} (default: @code{#f}) (type: maybe-boolean) +If @code{open-can-use-mode?} is @code{#t}, this may lead the +compatibility problems with servers that run the ircd-irc2 software. +This option masks mode requests by non-chanops as if they were coming +from the server. Only enable this if you have ircd-irc2 servers in your +IRC network. + +@item @code{pam?} (default: @code{#t}) (type: maybe-boolean) +Set to @code{#f} to disable all calls to the PAM library at runtime; all +users connecting without password are allowed to connect, all passwords +given will fail. Users identified without PAM are registered with a +tilde (@samp{~}) prepended to their user name. + +@item @code{pam-is-optional?} (default: @code{#f}) (type: maybe-boolean) +Set to @code{#t} to make PAM authentication optional, causing clients +not sending a password to still be able to connect, but won't become +identified and keep the tilder (@samp{~}) character prepended to their +supplied user name. + +@item @code{require-auth-ping?} (default: @code{#f}) (type: maybe-boolean) +Set to @code{#t} to have ngIRCd send an authentication PING when a new +client connects, and register this client only after receiving the +corresponding PONG reply. + +@end table + +@end deftp + + +@c %end of fragment + +@c %start of fragment + +@deftp {Data Type} ngircd-ssl +Available @code{ngircd-ssl} fields are: + +@table @asis +@item @code{cert-file} (type: maybe-string) +SSL certificate file of the private server key. + +@item @code{key-file} (type: maybe-string) +File name of the SSL Server Key to be used for SSL connections, which is +required for SSL/TLS support. + +@item @code{ca-file} (default: @code{"/etc/ssl/certs/ca-certificates.crt"}) (type: string) +A file listing all the certificates of the trusted Certificate +Authorities. + +@item @code{ports} (type: maybe-list-of-ports) +Like the global configuration's @code{port} option, except that ngIRCd +will expect incoming connections to be SSL/TLS encrypted. Common port +numbers for SSL-encrypted IRC are 6669 and 6697. + +@item @code{cipher-list} (type: maybe-string) +The GnuTLS cipher suites allowed for SSL/TLS connections, a value such +as @code{"SECURE128:-VERS-SSL3.0"}. Refer to @samp{man 3 +gnutls_priority_init} for details. + +@item @code{dh-file} (type: maybe-file-like) +A file-like containing the Diffie-Hellman parameters, which can be +created with GnuTLS via @samp{certtool --generate-dh-params}. If this +file is not present, the Diffie-Hellman parameters will be computed on +startup, which may take some time. + +@end table + +@end deftp + + +@c %end of fragment + +@c %start of fragment + +@deftp {Data Type} ngircd-operator +Available @code{ngircd-operator} fields are: + +@table @asis +@item @code{name} (type: string) +ID of the operator (may be different of the nickname). + +@item @code{password} (type: string) +Password of the IRC operator. + +@item @code{mask} (type: maybe-string) +Mask that is to be checked before an /OPER for this account is accepted, +for example: @code{"nick!ident@@*.example.com"}. + +@end table + +@end deftp + + +@c %end of fragment + +@c %start of fragment + +@deftp {Data Type} ngircd-server +Available @code{ngircd-server} fields are: + +@table @asis +@item @code{name} (type: string) +IRC name of the remote server. + +@item @code{host} (type: string) +Internet host name (or IP address) of the peer. + +@item @code{my-password} (type: string) +Own password for this connection. This password has to be configured as +@code{peer-password} on the other server and must not have @samp{:} as +first character. + +@item @code{peer-password} (type: string) +Foreign password for this connection. This password has to be +configured as @code{my-password} on the other server. + +@item @code{bind} (type: maybe-string) +IP address to use as source IP for the outgoing connection. The default +is to let the operating system decide. + +@item @code{port} (type: maybe-port) +Port of the remote server to which ngIRCd should connect (active). If +no port is assigned to a configured server, the daemon only waits for +incoming connections (passive, which is the default). + +@item @code{group} (type: maybe-number) +Group of this server. + +@item @code{passive?} (default: @code{#f}) (type: maybe-boolean) +Set to @code{#t} to disable automatic connection even if the port value +is specified. + +@item @code{ssl-connect?} (default: @code{#f}) (type: maybe-boolean) +Connect to the remote server using TLS/SSL. + +@end table + +@end deftp + + +@c %end of fragment + +@c %start of fragment + +@deftp {Data Type} ngircd-channel +Available @code{ngircd-channel} fields are: + +@table @asis +@item @code{name} (type: string) +Name of the channel, including channel prefix ("#" or "&"). + +@item @code{topic} (type: maybe-string) +Topic for this channel. + +@item @code{modes} (type: maybe-list-of-strings) +Initial channel modes, as used in MODE commands. Modifying lists (ban +list, invite list, exception list) is supported. If multiple MODE +strings are specified, they are evaluated in the order listed (left to +right). + +@item @code{key-file} (type: maybe-file-like) +Path and file name of a ngIRCd key file containing individual channel +keys for different users. Refer to @samp{man 5 ngircd.conf} for more +details. + +@end table + +@end deftp +@c %end of fragment + @subsubheading Quassel Service @cindex IRC (Internet Relay Chat) diff --git a/gnu/services/messaging.scm b/gnu/services/messaging.scm index 9bfeabacf4..341583ea58 100644 --- a/gnu/services/messaging.scm +++ b/gnu/services/messaging.scm @@ -3,6 +3,7 @@ ;;; Copyright © 2017 Mathieu Othacehe <m.othacehe <at> gmail.com> ;;; Copyright © 2015, 2017-2020, 2022-2024 Ludovic Courtès <ludo <at> gnu.org> ;;; Copyright © 2018 Pierre-Antoine Rouby <contact <at> parouby.fr> +;;; Copyright © 2025 Maxim Cournoyer <maxim.cournoyer <at> gmail.com> ;;; ;;; This file is part of GNU Guix. ;;; @@ -20,6 +21,7 @@ ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>. (define-module (gnu services messaging) + #:use-module ((gnu home services utils) #:select (object->camel-case-string)) #:use-module (gnu packages admin) #:use-module (gnu packages base) #:use-module (gnu packages irc) @@ -38,7 +40,10 @@ (define-module (gnu services messaging) #:use-module (guix deprecation) #:use-module (guix least-authority) #:use-module (srfi srfi-1) + #:use-module (srfi srfi-26) #:use-module (srfi srfi-35) + #:use-module (srfi srfi-71) + #:use-module (ice-9 format) #:use-module (ice-9 match) #:export (prosody-service-type prosody-configuration @@ -58,6 +63,32 @@ (define-module (gnu services messaging) bitlbee-configuration? bitlbee-service-type + <ngircd-configuration> + ngircd-configuration + ngircd-configuration? + <ngircd-global> + ngircd-global + ngircd-global? + <ngircd-limits> + ngircd-limits + ngircd-limits? + <ngircd-options> + ngircd-options + ngircd-options? + <ngircd-ssl> + ngircd-ssl + ngircd-ssl? + <ngircd-operator> + ngircd-operator + ngircd-operator? + <ngircd-server> + ngircd-server + ngircd-server? + <ngircd-channel> + ngircd-channel + ngircd-channel? + ngircd-service-type + quassel-configuration quassel-service-type @@ -921,6 +952,625 @@ (define bitlbee-service-type "Run @url{http://bitlbee.org,BitlBee}, a daemon that acts as a gateway between IRC and chat networks."))) + +;;; +;;; ngIRCd. +;;; + +(define-maybe string + (prefix ngircd-)) + +(define-maybe file-like + (prefix ngircd-)) + +(define-maybe list-of-strings + (prefix ngircd-)) + +(define (port? x) + (and (number? x) + (and (>= x 0) (<= x 65535)))) + +(define list-of-ports? + (list-of port?)) + +(define-maybe port + (prefix ngircd-)) + +(define-maybe list-of-ports + (prefix ngircd-)) + +(define-maybe number + (prefix ngircd-)) + +(define-maybe boolean + (prefix ngircd-)) + +(define (pascal-case text) + (object->camel-case-string text 'upper)) + +(define (ngircd-serialize-string field value) + (format #f "~a = ~a~%" (pascal-case field) value)) + +(define (ngircd-serialize-boolean field value) + (let* ((field (symbol->string field)) + (name (if (string-suffix? "?" field) + (string-drop-right field 1) + field))) + (format #f "~a = ~:[false~;true~]~%" (pascal-case name) value))) + +(define (ngircd-serialize-file-like field value) + #~(format #f "~a = ~a~%" #$(pascal-case field) #$value)) + +(define (ngircd-serialize-list-of-strings field value) + (format #f "~a = ~{~a~^,~}~%" (pascal-case field) value)) + +(define ngircd-serialize-list-of-ports + ngircd-serialize-list-of-strings) + +(define ngircd-serialize-number ngircd-serialize-string) + +(define ngircd-serialize-port ngircd-serialize-number) + +(define (string-or-number? x) + (or (string? x) (number? x))) + +(define ngircd-serialize-string-or-number ngircd-serialize-string) + +(define-configuration ngircd-global ;[Global] + (name + maybe-string + "Server name in the IRC network. This is an individual name of the IRC +server, it is not related to the DNS host name. It must be unique in the IRC +network and must contain at least one dot (@samp{.}) character. When not set, +ngIRCd tries to deduce a valid IRC server name from the local host name.") + (admin-info-1 + maybe-string + "First administrator information.") + (admin-info-2 + maybe-string + "Second administrator information.") + (admin-email + maybe-string + "Email to reach administrators.") + (help-file + maybe-file-like + "File-like containing the ngIRCd help text.") + (info + maybe-string + "Info text of the server. This will be shown by WHOIS and LINKS requests +for example.") + (listen + (maybe-list-of-strings (list "::" "0.0.0.0")) + "A list of IP address on which the server should listen. By default it +listens on all interfaces.") + (motd-file + ;; Provide an empty default file to avoid a warning when running --conftest + ;; in the activation script. + (file-like (plain-file "ngircd.motd" "")) + "Text file with the @i{message of the day} (MOTD). This message will be +shown to all users connecting to the server.") + (motd-phrase + maybe-string + "A simple Phrase (<127 chars) to use if you don't want to use a MOTD +file.") + (network + maybe-string + "The name of the IRC network to which this server belongs. This name is +optional, should only contain ASCII characters, and can't contain spaces. It +is only used to inform clients.") + (password + maybe-string + "Global password or all users needed to connect to the server. By default, +no password is required. PAM must be disabled for this option to have an +effect.") + (pid-file + (string "/run/ngircd/ngircd.pid") + "The file name where the PID of ngIRCd is written after it starts.") + (ports + (maybe-list-of-ports (list 6667)) + "Port number(s) on which the server should listen for @emph{unencrypted} +connections.") + (server-uid + (string-or-number "ngircd") + "The user that the @command{ngircd} command should run as.") + (server-gid + (string-or-number "ngircd") + "The group that the @command{ngircd} command should run as.") + (prefix ngircd-)) + +(define (serialize-ngircd-global _ config) + #~(string-append + "[Global]\n" + #$(serialize-configuration config ngircd-global-fields))) + +(define-configuration ngircd-limits ;[Limits] + (connect-retry + (maybe-number 60) + "The number of seconds the server should wait before re-attempting to +establish a link to not yet (or no longer) connected servers.") + (max-connections + (maybe-number 0) + "Maximum number of simultaneous in- and outbound connections the server is +allowed to accept. There is no limit by default.") + (max-connections-ip + (maybe-number 5) + "Maximum number of simultaneous connections from a single IP address that +the server will accept. This configuration options lowers the risk of denial +of service attacks (DoS). Set to 0 to remove the limit.") + (max-joins + (maybe-number 10) + "Maximum number of channels a user can be member of. Set to 0 to remove +the limit.") + (max-list-size + (maybe-number 100) + "Maximum number of channels returned in response to a LIST command.") + (ping-timeout + (maybe-number 120) + "Number of seconds of inactivity after which the server will send a PING to +the peer to test whether it is alive or not.") + (pong-timeout + (maybe-number 20) + "If a client fails to answer a PING with a PONG within this amount of +seconds, it will be disconnected by the server.") + (prefix ngircd-)) + +(define (serialize-ngircd-limits _ config) + #~(string-append + "\n[Limits]\n" + #$(serialize-configuration config ngircd-limits-fields))) + +(define-maybe ngircd-limits) + +(define-configuration ngircd-options ;[Options] + (allowed-channel-types + (maybe-string "#&+") + "List of allowed channel types (channel prefixes) for newly created +channels on the local server. By default, all supported channel types are +allowed.") + (allow-remote-oper? + (maybe-boolean #f) + "If this option is active, IRC operators connected to remote servers are +allowed to control this local server using administrative commands, for +example like CONNECT, DIE, SQUIT, etc.") + (connect-ipv4? + (maybe-boolean #t) + "Set to @code{#f} to prevent ngIRCd from connecting to other IRC servers +using the IPv4 protocol, allowed by default.") + (connect-ipv6? + (maybe-boolean #t) + "Set to @code{#f} to prevent ngIRCd from connecting to other IRC servers +using the IPv6 protocol, allowed by default.") + (dns? + (maybe-boolean #t) + "Set to @code{#f} to disable DNS lookups when clients connect. If you +configure the daemon to connect to other servers, ngIRCd may still perform a +DNS lookup if required.") + (more-privacy? + (maybe-boolean #f) + "Set this to @code{#t} to have ngIRCd censor user idle time, logon time as +well as the PART/QUIT messages (that sometimes used to inform everyone about +which client software is being used). WHOWAS requests are also silently +ignored, and NAMES output doesn't list any clients for non-members. This +option is most useful when ngIRCd is being used together with anonymizing +software such as TOR or I2P and one does not wish to make it too easy to +collect statistics on the users.") + (notice-before-registration? + (maybe-boolean #f) + "Normally ngIRCd doesn't send any messages to a client until it is +registered. Enable this option to let the daemon send @samp{NOTICE *} +messages to clients while connecting.") + (oper-can-use-mode? + (maybe-boolean #f) + "Should IRC Operators be allowed to use the MODE command even if they are +not(!) channel-operators?") + (oper-chan-p-auto-op? + (maybe-boolean #t) + "Should IRC Operators get AutoOp (+o) in persistent (+P) channels?") + (oper-server-mode? + (maybe-boolean #f) + "If @code{open-can-use-mode?} is @code{#t}, this may lead the compatibility +problems with servers that run the ircd-irc2 software. This option masks mode +requests by non-chanops as if they were coming from the server. Only enable +this if you have ircd-irc2 servers in your IRC network.") + (pam? + (maybe-boolean #t) + "Set to @code{#f} to disable all calls to the PAM library at runtime; all +users connecting without password are allowed to connect, all passwords given +will fail. Users identified without PAM are registered with a +tilde (@samp{~}) prepended to their user name.") + (pam-is-optional? + (maybe-boolean #f) + "Set to @code{#t} to make PAM authentication optional, causing clients not +sending a password to still be able to connect, but won't become identified +and keep the tilder (@samp{~}) character prepended to their supplied user +name.") + (require-auth-ping? + (maybe-boolean #f) + "Set to @code{#t} to have ngIRCd send an authentication PING when a new +client connects, and register this client only after receiving the +corresponding PONG reply.") + (prefix ngircd-)) + +(define (serialize-ngircd-options _ config) + #~(string-append + "\n[Options]\n" + #$(serialize-configuration config ngircd-options-fields))) + +(define-maybe ngircd-options) + +(define-configuration ngircd-ssl ;[SSL] + (cert-file + maybe-string + "SSL certificate file of the private server key.") + (key-file + maybe-string + "File name of the SSL Server Key to be used for SSL connections, which is +required for SSL/TLS support.") + (ca-file + (string "/etc/ssl/certs/ca-certificates.crt") + "A file listing all the certificates of the trusted Certificate +Authorities.") + (ports + maybe-list-of-ports + "Like the global configuration's @code{port} option, except that ngIRCd +will expect incoming connections to be SSL/TLS encrypted. Common port numbers +for SSL-encrypted IRC are 6669 and 6697.") + (cipher-list + maybe-string + "The GnuTLS cipher suites allowed for SSL/TLS connections, a value such as +@code{\"SECURE128:-VERS-SSL3.0\"}. Refer to @samp{man 3 gnutls_priority_init} +for details.") + (dh-file + maybe-file-like + "A file-like containing the Diffie-Hellman parameters, which can be created +with GnuTLS via @samp{certtool --generate-dh-params}. If this file is not +present, the Diffie-Hellman parameters will be computed on startup, which may +take some time.") + (prefix ngircd-)) + +(define (serialize-ngircd-ssl _ config) + #~(string-append + "\n[SSL]\n" + #$(serialize-configuration config ngircd-ssl-fields))) + +(define-maybe ngircd-ssl) + +(define-configuration ngircd-operator ;[Operator] + (name + string + "ID of the operator (may be different of the nickname).") + (password + string + "Password of the IRC operator.") + (mask + maybe-string + "Mask that is to be checked before an /OPER for this account is accepted, +for example: @code{\"nick!ident@@*.example.com\"}.") + (prefix ngircd-)) + +(define list-of-ngircd-operators? + (list-of ngircd-operator?)) + +(define (serialize-ngircd-operator _ operator) + #~(string-append + "\n[Operator]\n" + #$(serialize-configuration operator ngircd-operator-fields))) + +(define (serialize-list-of-ngircd-operators _ operators) + #~(string-append #$@(map (cut serialize-ngircd-operator #f <>) operators))) + +(define-maybe list-of-ngircd-operators) + +(define-configuration ngircd-server ;[Server] + (name + string + "IRC name of the remote server.") + (host + string + "Internet host name (or IP address) of the peer.") + (my-password + string + "Own password for this connection. This password has to be configured as +@code{peer-password} on the other server and must not have @samp{:} as first +character.") + (peer-password + string + "Foreign password for this connection. This password has to be configured +as @code{my-password} on the other server.") + (bind + maybe-string + "IP address to use as source IP for the outgoing connection. The default +is to let the operating system decide.") + (port + maybe-port + "Port of the remote server to which ngIRCd should connect (active). If no +port is assigned to a configured server, the daemon only waits for incoming +connections (passive, which is the default).") + (group + maybe-number + "Group of this server.") + (passive? + (maybe-boolean #f) + "Set to @code{#t} to disable automatic connection even if the port value is +specified.") + (ssl-connect? + (maybe-boolean #f) + "Connect to the remote server using TLS/SSL.") + (prefix ngircd-)) + +(define list-of-ngircd-servers? + (list-of ngircd-server?)) + +(define (serialize-ngircd-server _ server) + #~(string-append + "\n[Server]\n" + #$(serialize-configuration server ngircd-server-fields))) + +(define (serialize-list-of-ngircd-servers _ servers) + #~(string-append #$@(map (cut serialize-ngircd-server #f <>) servers))) + +(define-maybe list-of-ngircd-servers) + +(define-configuration ngircd-channel ;[Channel] + (name + string + "Name of the channel, including channel prefix (\"#\" or \"&\").") + (topic + maybe-string + "Topic for this channel.") + (modes + maybe-list-of-strings + "Initial channel modes, as used in MODE commands. Modifying lists (ban +list, invite list, exception list) is supported. If multiple MODE strings are +specified, they are evaluated in the order listed (left to right)." + (serializer (lambda (_ value) + ;; Special case: each mode string gets serialized to a + ;; separate option. + (format #f "~{Modes = ~a~%~}" value)))) + (key-file + maybe-file-like + "Path and file name of a ngIRCd key file containing individual channel keys +for different users. Refer to @samp{man 5 ngircd.conf} for more details.") + (prefix ngircd-)) + +(define list-of-ngircd-channels? + (list-of ngircd-channel?)) + +(define (serialize-ngircd-channel _ channel) + #~(string-append + "\n[Channel]\n" + #$(serialize-configuration channel ngircd-channel-fields))) + +(define (serialize-list-of-ngircd-channels _ channels) + #~(string-append #$@(map (cut serialize-ngircd-channel #f <>) channels))) + +(define-maybe list-of-ngircd-channels) + +(define-configuration ngircd-configuration + (ngircd + (file-like ngircd) + "The @code{ngircd} package to use.") + (debug? + (boolean #f) + "Turn on debugging messages." + (serializer empty-serializer)) + (global + ;; Always use a ngircd-global default to ensure the correct PidFile option + ;; is set, as it is required by the service. + (ngircd-global (ngircd-global)) + "A ngircd-global record object used to specify global options.") + (limits + maybe-ngircd-limits + "The ngircd-limits record object used to specify limits options.") + (options + maybe-ngircd-options + "The ngircd-options record object used to specify optional features and +configuration options.") + (ssl + maybe-ngircd-ssl + "The ngircd-ssl record object used to specify the SSL-related options.") + (operators + maybe-list-of-ngircd-operators + "A list of ngircd-operator record objects used to specify the operators.") + (servers + maybe-list-of-ngircd-servers + "A list of ngircd-server record objects used to specify other remote +servers to connect to.") + (channels + maybe-list-of-ngircd-channels + "A list of ngircd-channels record objects specifying pre-defined channels +to be created by the server when starting up.")) + +(define (ngircd-generate-documentation) + (configuration->documentation 'ngircd-configuration) + (configuration->documentation 'ngircd-global) + (configuration->documentation 'ngircd-limits) + (configuration->documentation 'ngircd-options) + (configuration->documentation 'ngircd-ssl) + (configuration->documentation 'ngircd-operator) + (configuration->documentation 'ngircd-server) + (configuration->documentation 'ngircd-channel)) + +(define (ngircd-user+group config) + "Return the Global->ServerUID and Global->ServerGID configuration options as +values." + (let* ((global (ngircd-configuration-global config)) + (user (ngircd-global-server-uid global)) + (group (ngircd-global-server-gid global))) + (values user group))) + +(define (ngircd-account config) + (let* ((user group (ngircd-user+group config)) + (group-name (if (string? group) + group + "ngircd")) + (user-name (if (string? user) + user + "ngircd")) + (gid (if (number? group) + group + #f)) + (uid (if (number? user) + user + #f))) + (list (user-group + (name group-name) + (id gid) + (system? #t)) + (user-account + (name user-name) + (uid uid) + (group group-name) + (system? #t) + (comment "Ngircd daemon user") + (home-directory "/var/empty") + (shell (file-append shadow "/sbin/nologin")))))) + +(define (serialize-ngircd-configuration config) + "Return a file-like object corresponding to the serialized +<ngircd-configuration> record." + (mixed-text-file "ngircd.conf" + (serialize-configuration + config ngircd-configuration-fields))) + +(define (ngircd-wrapper config) + "Take CONFIG, a <ngircd-configuration> object, and provide a least-authority +wrapper for the 'ngircd' command." + (let* ((ngircd.conf (serialize-ngircd-configuration config)) + (user group (ngircd-user+group config)) + (global (ngircd-configuration-global config)) + (pid-file (ngircd-global-pid-file global)) + (help-file (ngircd-global-help-file global)) + (motd-file (ngircd-global-motd-file global)) + (ssl (ngircd-configuration-ssl config)) + (ca-file (ngircd-ssl-ca-file ssl)) + (cert-file (ngircd-ssl-cert-file ssl)) + (key-file (ngircd-ssl-key-file ssl)) + (dh-file (ngircd-ssl-dh-file ssl)) + (channels (ngircd-configuration-channels config))) + (least-authority-wrapper + (file-append (ngircd-configuration-ngircd config) "/sbin/ngircd") + #:name "ngircd-pola-wrapper" + ;; Expose all needed files, such as all options corresponding to + ;; file-like objects and string file names. + #:mappings + (append + (list (file-system-mapping + (source "/dev/log") ;for syslog + (target source)) + (file-system-mapping + (source ngircd.conf) + (target source)) + (file-system-mapping + (source (string-append (dirname pid-file))) + (target source) + (writable? #t))) + (if (maybe-value-set? help-file) + (list (file-system-mapping + (source help-file) + (target source))) + '()) + (if (maybe-value-set? motd-file) + (list (file-system-mapping + (source motd-file) + (target source))) + '()) + (if (maybe-value-set? ssl) + ;; When SSL is used, expose the specified keys and certificates. + (append + (if (maybe-value-set? ca-file) + (list (file-system-mapping + (source ca-file) + (target source))) + '()) + (if (maybe-value-set? cert-file) + (list (file-system-mapping + (source cert-file) + (target source))) + '()) + (if (maybe-value-set? key-file) + (list (file-system-mapping + (source key-file) + (target source))) + '()) + (if (maybe-value-set? dh-file) + (list (file-system-mapping + (source dh-file) + (target source))) + '())) + '()) + (if (maybe-value-set? channels) + (filter-map (lambda (channel) + (let ((key-file (ngircd-channel-key-file channel))) + (and (maybe-value-set? key-file) + key-file))) + channels) + '())) + #:user user + #:group group + ;; ngircd wants to look up users in /etc/passwd so run in the global user + ;; namespace. Also preserve the PID namespaces otherwise the PID file + ;; would contain an unrelated PID number and confuse Shepherd. + #:namespaces (fold delq %namespaces '(net pid user))))) + +(define (ngircd-shepherd-service config) + (match-record config <ngircd-configuration> + (ngircd debug? global) + (let ((ngircd.conf (serialize-ngircd-configuration config)) + (ngircd (file-append ngircd "/sbin/ngircd")) + (pid-file (ngircd-global-pid-file global)) + (user group (ngircd-user+group config))) + (list (shepherd-service + (provision '(ngircd)) + (requirement '(user-processes networking syslogd)) + (actions (list (shepherd-configuration-action ngircd.conf))) + (start #~(make-forkexec-constructor + (append (list #$(ngircd-wrapper config) + "--nodaemon" "--syslog" + "--config" #$ngircd.conf) + (if #$debug? + '("--debug") + '())) + #:pid-file #$pid-file)) + + (stop #~(make-kill-destructor))))))) + +(define (ngircd-activation config) + (let* ((ngircd (file-append (ngircd-configuration-ngircd config))) + (pid-file (ngircd-global-pid-file + (ngircd-configuration-global config))) + (ngircd.conf (serialize-ngircd-configuration config)) + (user _ (ngircd-user+group config))) + #~(begin + (use-modules (guix build utils) + (ice-9 match)) + (define pw (match #$user + ((? number?) (getpwuid #$user)) + ((? string?) (getpwnam #$user)))) + (mkdir-p/perms #$(dirname pid-file) pw #o755) + (system (string-join + (list #$(file-append ngircd "/sbin/ngircd") + "--configtest" "--config" #$ngircd.conf + ;; Ensure stdin is not a TTY to avoid pausing for a key + ;; during boot when a problem is detected. + "<" "/dev/null")))))) + +(define ngircd-service-type + (service-type + (name 'ngircd) + (extensions + (list (service-extension shepherd-root-service-type + ngircd-shepherd-service) + (service-extension profile-service-type + (compose list ngircd-configuration-ngircd)) + (service-extension account-service-type + ngircd-account) + (service-extension activation-service-type + ngircd-activation))) + (description + "Run @url{https://ngircd.barton.de/, ngIRCd}, a lightweight @acronym{IRC, +Internet Relay Chat} daemon."))) + ;;; ;;; Quassel. diff --git a/gnu/tests/messaging.scm b/gnu/tests/messaging.scm index 9eae3f6049..ed31b16957 100644 --- a/gnu/tests/messaging.scm +++ b/gnu/tests/messaging.scm @@ -2,6 +2,7 @@ ;;; Copyright © 2017, 2018 Clément Lassieur <clement <at> lassieur.org> ;;; Copyright © 2017-2018, 2021-2022 Ludovic Courtès <ludo <at> gnu.org> ;;; Copyright © 2018 Efraim Flashner <efraim <at> flashner.co.il> +;;; Copyright © 2025 Maxim Cournoyer <maxim.cournoyer <at> gmail.com> ;;; ;;; This file is part of GNU Guix. ;;; @@ -31,6 +32,7 @@ (define-module (gnu tests messaging) #:use-module (guix modules) #:export (%test-prosody %test-bitlbee + %test-ngircd %test-quassel)) (define (run-xmpp-test name xmpp-service pid-file create-account) @@ -217,6 +219,77 @@ (define %test-bitlbee (description "Connect to a BitlBee IRC server.") (value (run-bitlbee-test)))) + +;;; +;;; ngIRCd. +;;; + +(define %ngircd-os + (marionette-operating-system + (simple-operating-system + (service dhcp-client-service-type) + (service ngircd-service-type + (ngircd-configuration + (debug? #t) + (global + (ngircd-global + (pid-file "/var/ngircd/ngircd.pid") + (server-uid 990) + (server-gid 990))) + ;; There is no need to serialize the following sections, which + ;; are all optional, but include them anyway to test the + ;; serializers. + (limits (ngircd-limits)) + (options (ngircd-options)) + (ssl (ngircd-ssl)) + (operators (list (ngircd-operator + (name "maxim") + (password "1234")))) + (channels (list (ngircd-channel + (name "#guix"))))))) + #:imported-modules (source-module-closure '((gnu services herd))))) + +(define (run-ngircd-test) + (define vm + (virtual-machine (operating-system %ngircd-os))) + + (define test + (with-imported-modules '((gnu build marionette)) + #~(begin + (use-modules (srfi srfi-64) + (gnu build marionette)) + + (define marionette + (make-marionette (list #$vm))) + + (test-runner-current (system-test-runner #$output)) + (test-begin "ngircd") + + (test-assert "ngircd service runs" + (marionette-eval + '(begin + (use-modules (gnu services herd)) + (wait-for-service 'ngircd)) + marionette)) + + (test-assert "ngircd listens on TCP port 6667" + (wait-for-tcp-port 6667 marionette)) + + (test-end)))) + + (gexp->derivation "ngircd-test" test)) + +(define %test-ngircd + (system-test + (name "ngircd") + (description "Connect to a ngircd IRC server.") + (value (run-ngircd-test)))) + + +;;; +;;; Quassel. +;;; + (define (run-quassel-test) (define os (marionette-operating-system base-commit: 8c43056aabc2d22da61dc86049b143f7ae1ef516 -- 2.49.0
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.