1{ config, lib, pkgs, ... }:
2
3with lib;
4
5let
6 cfg = config.services.xrdp;
7 confDir = pkgs.runCommand "xrdp.conf" { } ''
8 mkdir $out
9
10 cp ${cfg.package}/etc/xrdp/{km-*,xrdp,sesman,xrdp_keyboard}.ini $out
11
12 cat > $out/startwm.sh <<EOF
13 #!/bin/sh
14 . /etc/profile
15 ${cfg.defaultWindowManager}
16 EOF
17 chmod +x $out/startwm.sh
18
19 substituteInPlace $out/xrdp.ini \
20 --replace "#rsakeys_ini=" "rsakeys_ini=/var/run/xrdp/rsakeys.ini" \
21 --replace "certificate=" "certificate=${cfg.sslCert}" \
22 --replace "key_file=" "key_file=${cfg.sslKey}" \
23 --replace LogFile=xrdp.log LogFile=/dev/null \
24 --replace EnableSyslog=true EnableSyslog=false
25
26 substituteInPlace $out/sesman.ini \
27 --replace LogFile=xrdp-sesman.log LogFile=/dev/null \
28 --replace EnableSyslog=1 EnableSyslog=0
29 '';
30in
31{
32
33 ###### interface
34
35 options = {
36
37 services.xrdp = {
38
39 enable = mkEnableOption "Whether xrdp should be run on startup.";
40
41 package = mkOption {
42 type = types.package;
43 default = pkgs.xrdp;
44 defaultText = "pkgs.xrdp";
45 description = ''
46 The package to use for the xrdp daemon's binary.
47 '';
48 };
49
50 port = mkOption {
51 type = types.int;
52 default = 3389;
53 description = ''
54 Specifies on which port the xrdp daemon listens.
55 '';
56 };
57
58 sslKey = mkOption {
59 type = types.str;
60 default = "/etc/xrdp/key.pem";
61 example = "/path/to/your/key.pem";
62 description = ''
63 ssl private key path
64 A self-signed certificate will be generated if file not exists.
65 '';
66 };
67
68 sslCert = mkOption {
69 type = types.str;
70 default = "/etc/xrdp/cert.pem";
71 example = "/path/to/your/cert.pem";
72 description = ''
73 ssl certificate path
74 A self-signed certificate will be generated if file not exists.
75 '';
76 };
77
78 defaultWindowManager = mkOption {
79 type = types.str;
80 default = "xterm";
81 example = "xfce4-session";
82 description = ''
83 The script to run when user log in, usually a window manager, e.g. "icewm", "xfce4-session"
84 This is per-user overridable, if file ~/startwm.sh exists it will be used instead.
85 '';
86 };
87
88 };
89 };
90
91
92 ###### implementation
93
94 config = mkIf cfg.enable {
95
96 # copied from <nixos/modules/services/x11/xserver.nix>
97 # xrdp can run X11 program even if "services.xserver.enable = false"
98 environment.pathsToLink =
99 [ "/etc/xdg" "/share/xdg" "/share/applications" "/share/icons" "/share/pixmaps" ];
100
101 systemd = {
102 services.xrdp = {
103 wantedBy = [ "multi-user.target" ];
104 after = [ "network.target" ];
105 description = "xrdp daemon";
106 requires = [ "xrdp-sesman.service" ];
107 preStart = ''
108 # prepare directory for unix sockets (the sockets will be owned by loggedinuser:xrdp)
109 mkdir -p /tmp/.xrdp || true
110 chown xrdp:xrdp /tmp/.xrdp
111 chmod 3777 /tmp/.xrdp
112
113 # generate a self-signed certificate
114 if [ ! -s ${cfg.sslCert} -o ! -s ${cfg.sslKey} ]; then
115 mkdir -p $(dirname ${cfg.sslCert}) || true
116 mkdir -p $(dirname ${cfg.sslKey}) || true
117 ${pkgs.openssl.bin}/bin/openssl req -x509 -newkey rsa:2048 -sha256 -nodes -days 365 \
118 -subj /C=US/ST=CA/L=Sunnyvale/O=xrdp/CN=www.xrdp.org \
119 -config ${cfg.package}/share/xrdp/openssl.conf \
120 -keyout ${cfg.sslKey} -out ${cfg.sslCert}
121 chown root:xrdp ${cfg.sslKey} ${cfg.sslCert}
122 chmod 440 ${cfg.sslKey} ${cfg.sslCert}
123 fi
124 if [ ! -s /var/run/xrdp/rsakeys.ini ]; then
125 mkdir -p /var/run/xrdp
126 ${cfg.package}/bin/xrdp-keygen xrdp /var/run/xrdp/rsakeys.ini
127 fi
128 '';
129 serviceConfig = {
130 User = "xrdp";
131 Group = "xrdp";
132 PermissionsStartOnly = true;
133 ExecStart = "${cfg.package}/bin/xrdp --nodaemon --port ${toString cfg.port} --config ${confDir}/xrdp.ini";
134 };
135 };
136
137 services.xrdp-sesman = {
138 wantedBy = [ "multi-user.target" ];
139 after = [ "network.target" ];
140 description = "xrdp session manager";
141 restartIfChanged = false; # do not restart on "nixos-rebuild switch". like "display-manager", it can have many interactive programs as children
142 serviceConfig = {
143 ExecStart = "${cfg.package}/bin/xrdp-sesman --nodaemon --config ${confDir}/sesman.ini";
144 ExecStop = "${pkgs.coreutils}/bin/kill -INT $MAINPID";
145 };
146 };
147
148 };
149
150 users.users.xrdp = {
151 description = "xrdp daemon user";
152 isSystemUser = true;
153 group = "xrdp";
154 };
155 users.groups.xrdp = {};
156
157 security.pam.services.xrdp-sesman = { allowNullPassword = true; startSession = true; };
158 };
159
160}