at 24.11-pre 6.9 kB view raw
1{ config, lib, pkgs, ... }: 2 3with lib; 4 5let 6 cfg = config.services.xrdp; 7 8 confDir = pkgs.runCommand "xrdp.conf" { preferLocalBuild = true; } '' 9 mkdir -p $out 10 11 cp -r ${cfg.package}/etc/xrdp/* $out 12 chmod -R +w $out 13 14 cat > $out/startwm.sh <<EOF 15 #!/bin/sh 16 . /etc/profile 17 ${lib.optionalString cfg.audio.enable "${cfg.audio.package}/libexec/pulsaudio-xrdp-module/pulseaudio_xrdp_init"} 18 ${cfg.defaultWindowManager} 19 EOF 20 chmod +x $out/startwm.sh 21 22 substituteInPlace $out/xrdp.ini \ 23 --replace "#rsakeys_ini=" "rsakeys_ini=/run/xrdp/rsakeys.ini" \ 24 --replace "certificate=" "certificate=${cfg.sslCert}" \ 25 --replace "key_file=" "key_file=${cfg.sslKey}" \ 26 --replace LogFile=xrdp.log LogFile=/dev/null \ 27 --replace EnableSyslog=true EnableSyslog=false 28 29 substituteInPlace $out/sesman.ini \ 30 --replace LogFile=xrdp-sesman.log LogFile=/dev/null \ 31 --replace EnableSyslog=1 EnableSyslog=0 \ 32 --replace startwm.sh $out/startwm.sh \ 33 --replace reconnectwm.sh $out/reconnectwm.sh \ 34 35 # Ensure that clipboard works for non-ASCII characters 36 sed -i -e '/.*SessionVariables.*/ a\ 37 LANG=${config.i18n.defaultLocale}\ 38 LOCALE_ARCHIVE=${config.i18n.glibcLocales}/lib/locale/locale-archive 39 ' $out/sesman.ini 40 41 ${cfg.extraConfDirCommands} 42 ''; 43in 44{ 45 46 ###### interface 47 48 options = { 49 50 services.xrdp = { 51 52 enable = mkEnableOption "xrdp, the Remote Desktop Protocol server"; 53 54 package = mkPackageOptionMD pkgs "xrdp" { }; 55 56 audio = { 57 enable = mkEnableOption "audio support for xrdp sessions. So far it only works with PulseAudio sessions on the server side. No PipeWire support yet"; 58 package = mkPackageOptionMD pkgs "pulseaudio-module-xrdp" {}; 59 }; 60 61 port = mkOption { 62 type = types.port; 63 default = 3389; 64 description = '' 65 Specifies on which port the xrdp daemon listens. 66 ''; 67 }; 68 69 openFirewall = mkOption { 70 default = false; 71 type = types.bool; 72 description = "Whether to open the firewall for the specified RDP port."; 73 }; 74 75 sslKey = mkOption { 76 type = types.str; 77 default = "/etc/xrdp/key.pem"; 78 example = "/path/to/your/key.pem"; 79 description = '' 80 ssl private key path 81 A self-signed certificate will be generated if file not exists. 82 ''; 83 }; 84 85 sslCert = mkOption { 86 type = types.str; 87 default = "/etc/xrdp/cert.pem"; 88 example = "/path/to/your/cert.pem"; 89 description = '' 90 ssl certificate path 91 A self-signed certificate will be generated if file not exists. 92 ''; 93 }; 94 95 defaultWindowManager = mkOption { 96 type = types.str; 97 default = "xterm"; 98 example = "xfce4-session"; 99 description = '' 100 The script to run when user log in, usually a window manager, e.g. "icewm", "xfce4-session" 101 This is per-user overridable, if file ~/startwm.sh exists it will be used instead. 102 ''; 103 }; 104 105 confDir = mkOption { 106 type = types.path; 107 default = confDir; 108 internal = true; 109 description = '' 110 Configuration directory of xrdp and sesman. 111 112 Changes to this must be made through extraConfDirCommands. 113 ''; 114 readOnly = true; 115 }; 116 117 extraConfDirCommands = mkOption { 118 type = types.str; 119 default = ""; 120 description = '' 121 Extra commands to run on the default confDir derivation. 122 ''; 123 example = '' 124 substituteInPlace $out/sesman.ini \ 125 --replace LogLevel=INFO LogLevel=DEBUG \ 126 --replace LogFile=/dev/null LogFile=/var/log/xrdp.log 127 ''; 128 }; 129 }; 130 }; 131 132 ###### implementation 133 134 config = lib.mkMerge [ 135 (mkIf cfg.audio.enable { 136 environment.systemPackages = [ cfg.audio.package ]; # needed for autostart 137 138 hardware.pulseaudio.extraModules = [ cfg.audio.package ]; 139 }) 140 141 (mkIf cfg.enable { 142 143 networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ cfg.port ]; 144 145 # xrdp can run X11 program even if "services.xserver.enable = false" 146 xdg = { 147 autostart.enable = true; 148 menus.enable = true; 149 mime.enable = true; 150 icons.enable = true; 151 }; 152 153 fonts.enableDefaultPackages = mkDefault true; 154 155 environment.etc."xrdp".source = "${confDir}/*"; 156 157 systemd = { 158 services.xrdp = { 159 wantedBy = [ "multi-user.target" ]; 160 after = [ "network.target" ]; 161 description = "xrdp daemon"; 162 requires = [ "xrdp-sesman.service" ]; 163 preStart = '' 164 # prepare directory for unix sockets (the sockets will be owned by loggedinuser:xrdp) 165 mkdir -p /tmp/.xrdp || true 166 chown xrdp:xrdp /tmp/.xrdp 167 chmod 3777 /tmp/.xrdp 168 169 # generate a self-signed certificate 170 if [ ! -s ${cfg.sslCert} -o ! -s ${cfg.sslKey} ]; then 171 mkdir -p $(dirname ${cfg.sslCert}) || true 172 mkdir -p $(dirname ${cfg.sslKey}) || true 173 ${lib.getExe pkgs.openssl} req -x509 -newkey rsa:2048 -sha256 -nodes -days 365 \ 174 -subj /C=US/ST=CA/L=Sunnyvale/O=xrdp/CN=www.xrdp.org \ 175 -config ${cfg.package}/share/xrdp/openssl.conf \ 176 -keyout ${cfg.sslKey} -out ${cfg.sslCert} 177 chown root:xrdp ${cfg.sslKey} ${cfg.sslCert} 178 chmod 440 ${cfg.sslKey} ${cfg.sslCert} 179 fi 180 if [ ! -s /run/xrdp/rsakeys.ini ]; then 181 mkdir -p /run/xrdp 182 ${pkgs.xrdp}/bin/xrdp-keygen xrdp /run/xrdp/rsakeys.ini 183 fi 184 ''; 185 serviceConfig = { 186 User = "xrdp"; 187 Group = "xrdp"; 188 PermissionsStartOnly = true; 189 ExecStart = "${pkgs.xrdp}/bin/xrdp --nodaemon --port ${toString cfg.port} --config ${confDir}/xrdp.ini"; 190 }; 191 }; 192 193 services.xrdp-sesman = { 194 wantedBy = [ "multi-user.target" ]; 195 after = [ "network.target" ]; 196 description = "xrdp session manager"; 197 restartIfChanged = false; # do not restart on "nixos-rebuild switch". like "display-manager", it can have many interactive programs as children 198 serviceConfig = { 199 ExecStart = "${pkgs.xrdp}/bin/xrdp-sesman --nodaemon --config ${confDir}/sesman.ini"; 200 ExecStop = "${pkgs.coreutils}/bin/kill -INT $MAINPID"; 201 }; 202 }; 203 204 }; 205 206 users.users.xrdp = { 207 description = "xrdp daemon user"; 208 isSystemUser = true; 209 group = "xrdp"; 210 }; 211 users.groups.xrdp = {}; 212 213 security.pam.services.xrdp-sesman = { 214 allowNullPassword = true; 215 startSession = true; 216 }; 217 218 }) 219 ]; 220 221}