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