luci-app-openvpn: "final" changeset
[oweals/luci.git] / applications / luci-app-openvpn / luasrc / model / cbi / openvpn-advanced.lua
1 -- Copyright 2008 Steven Barth <steven@midlink.org>
2 -- Licensed to the public under the Apache License 2.0.
3
4 local fs = require("nixio.fs")
5
6 local knownParams = {
7         --
8         --Widget
9         --      Name
10         --      Default(s)
11         --      Description
12         --      Option(s)
13
14         { "Service", {
15         -- initialisation and daemon options
16                 { ListValue,
17                         "verb",
18                         { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 },
19                         translate("Set output verbosity") },
20                 { Flag,
21                         "mlock",
22                         0,
23                         translate("Disable Paging") },
24                 { Flag,
25                         "disable_occ",
26                         0,
27                         translate("Disable options consistency check") },
28         --      { Value,
29         --              "user",
30         --              "root",
31         --              translate("Set UID to user") },
32         --      { Value,
33         --              "group",
34         --              "root",
35         --              translate("Set GID to group") },
36                 { Value,
37                         "cd",
38                         "/etc/openvpn",
39                         translate("Change to directory before initialization") },
40                 { Value,
41                         "chroot",
42                         "/var/run",
43                         translate("Chroot to directory after initialization") },
44         --      { Value,
45         --              "daemon",
46         --              "Instance-Name",
47         --              translate("Daemonize after initialization") },
48         --      { Value,
49         --              "syslog",
50         --              "Instance-Name",
51         --              translate("Output to syslog and do not daemonize") },
52                 { Flag,
53                         "passtos",
54                         0,
55                         translate("TOS passthrough (applies to IPv4 only)") },
56         --      { Value,
57         --              "inetd",
58         --              "nowait Instance-Name",
59         --              translate("Run as an inetd or xinetd server") },
60                 { Value,
61                         "log",
62                         "/var/log/openvpn.log",
63                         translate("Write log to file") },
64                 { Value,
65                         "log_append",
66                         "/var/log/openvpn.log",
67                         translate("Append log to file") },
68                 { Flag,
69                         "suppress_timestamps",
70                         0,
71                         translate("Don't log timestamps") },
72         --      { Value,
73         --              "writepid",
74         --              "/var/run/openvpn.pid",
75         --              translate("Write process ID to file") },
76                 { Value,
77                         "nice",
78                         0,
79                         translate("Change process priority") },
80                 { Flag,
81                         "fast_io",
82                         0,
83                         translate("Optimize TUN/TAP/UDP writes") },
84                 { Value,
85                         "echo",
86                         "some params echoed to log",
87                         translate("Echo parameters to log") },
88                 { ListValue,
89                         "remap_usr1",
90                         { "SIGHUP", "SIGTERM" },
91                         translate("Remap SIGUSR1 signals") },
92                 { Value,
93                         "status",
94                         "/var/run/openvpn.status 5",
95                         translate("Write status to file every n seconds") },
96                 { Value,
97                         "status_version",
98                         { 1, 2 },
99                         translate("Status file format version") },      -- status
100                 { Value,
101                         "mute",
102                         5,
103                         translate("Limit repeated log messages") },
104                 { Value,
105                         "up",
106                         "/usr/bin/ovpn-up",
107                         translate("Shell cmd to execute after tun device open") },
108                 { Value,
109                         "up_delay",
110                         5,
111                         translate("Delay tun/tap open and up script execution") },
112                 { Value,
113                         "down",
114                         "/usr/bin/ovpn-down",
115                         translate("Shell cmd to run after tun device close") },
116                 { Flag,
117                         "down_pre",
118                         0,
119                         translate("Call down cmd/script before TUN/TAP close") },
120                 { Flag,
121                         "up_restart",
122                         0,
123                         translate("Run up/down scripts for all restarts") },
124                 { Value,
125                         "route_up",
126                         "/usr/bin/ovpn-routeup",
127                         translate("Execute shell cmd after routes are added") },
128                 { Value,
129                         "ipchange",
130                         "/usr/bin/ovpn-ipchange",
131                         translate("Execute shell command on remote ip change"),
132                         { mode="p2p" } },
133                 { DynamicList,
134                         "setenv",
135                         { "VAR1 value1", "VAR2 value2" },
136                         translate("Pass environment variables to script") },
137                 { Value,
138                         "tls_verify",
139                         "/usr/bin/ovpn-tlsverify",
140                         translate("Shell command to verify X509 name") },
141                 { Value,
142                         "client_connect",
143                         "/usr/bin/ovpn-clientconnect",
144                         translate("Run script cmd on client connection") },
145                 { Flag,
146                         "client_disconnect",
147                         0,
148                         translate("Run script cmd on client disconnection") },
149                 { Value,
150                         "learn_address",
151                         "/usr/bin/ovpn-learnaddress",
152                         translate("Executed in server mode whenever an IPv4 address/route or MAC address is added to OpenVPN's internal routing table") },
153                 { Value,
154                         "auth_user_pass_verify",
155                         "/usr/bin/ovpn-userpass via-env",
156                         translate("Executed in server mode on new client connections, when the client is still untrusted") },
157                 { ListValue,
158                         "script_security",
159                         { 0, 1, 2, 3 },
160                         translate("Policy level over usage of external programs and scripts") },
161         } },
162
163         { "Networking", {
164         -- socket config
165                 { ListValue,
166                         "mode",
167                         { "p2p", "server" },
168                         translate("Major mode") },
169                 { Value,
170                         "local",
171                         "0.0.0.0",
172                         translate("Local host name or ip address") },
173                 { Value,
174                         "port",
175                         1194,
176                         translate("TCP/UDP port # for both local and remote") },
177                 { Value,
178                         "lport",
179                         1194,
180                         translate("TCP/UDP port # for local (default=1194)") },
181                 { Value,
182                         "rport",
183                         1194,
184                         translate("TCP/UDP port # for remote (default=1194)") },
185                 { Flag,
186                         "float",
187                         0,
188                         translate("Allow remote to change its IP or port") },
189                 { Flag,
190                         "nobind",
191                         0,
192                         translate("Do not bind to local address and port") },
193                 { Value,
194                         "dev",
195                         "tun0",
196                         translate("tun/tap device") },
197                 { ListValue,
198                         "dev_type",
199                         { "tun", "tap" },
200                         translate("Type of used device") },
201                 { Value,
202                         "dev_node",
203                         "/dev/net/tun",
204                         translate("Use tun/tap device node") },
205                 { Value,
206                         "ifconfig",
207                         "10.200.200.3 10.200.200.1",
208                         translate("Set tun/tap adapter parameters") },
209                 { Flag,
210                         "ifconfig_noexec",
211                         0,
212                         translate("Don't actually execute ifconfig") },
213                 { Flag,
214                         "ifconfig_nowarn",
215                         0,
216                         translate("Don't warn on ifconfig inconsistencies") },
217                 { DynamicList,
218                         "route",
219                         "10.123.0.0 255.255.0.0",
220                         translate("Add route after establishing connection") },
221                 { Value,
222                         "route_gateway",
223                         "10.234.1.1",
224                         translate("Specify a default gateway for routes") },
225                 { Value,
226                         "route_delay",
227                         0,
228                         translate("Delay n seconds after connection") },
229                 { Flag,
230                         "route_noexec",
231                         0,
232                         translate("Don't add routes automatically") },
233                 { Flag,
234                         "route_nopull",
235                         0,
236                         translate("Don't pull routes automatically") },
237                 { ListValue,
238                         "mtu_disc",
239                         { "yes", "maybe", "no" },
240                         translate("Enable Path MTU discovery") },
241                 { Flag,
242                         "mtu_test",
243                         0,
244                         translate("Empirically measure MTU") },
245                 { Value,
246                         "link_mtu",
247                         1500,
248                         translate("Set TCP/UDP MTU") },
249                 { Value,
250                         "tun_mtu",
251                         1500,
252                         translate("Set tun/tap device MTU") },
253                 { Value,
254                         "tun_mtu_extra",
255                         1500,
256                         translate("Set tun/tap device overhead") },
257                 { Value,
258                         "fragment",
259                         1500,
260                         translate("Enable internal datagram fragmentation"),
261                         { proto="udp" } },
262                 { Value,
263                         "mssfix",
264                         1500,
265                         translate("Set upper bound on TCP MSS"),
266                         { proto="udp" } },
267                 { Value,
268                         "sndbuf",
269                         65536,
270                         translate("Set the TCP/UDP send buffer size") },
271                 { Value,
272                         "rcvbuf",
273                         65536,
274                         translate("Set the TCP/UDP receive buffer size") },
275                 { Value,
276                         "txqueuelen",
277                         100,
278                         translate("Set tun/tap TX queue length") },
279                 { Value,
280                         "shaper",
281                         10240,
282                         translate("Shaping for peer bandwidth") },
283                 { Value,
284                         "inactive",
285                         240,
286                         translate("tun/tap inactivity timeout") },
287                 { Value,
288                         "keepalive",
289                         "10 60",
290                         translate("Helper directive to simplify the expression of --ping and --ping-restart in server mode configurations") },
291                 { Value,
292                         "ping",
293                         30,
294                         translate("Ping remote every n seconds over TCP/UDP port") },
295                 { Value,
296                         "ping_exit",
297                         120,
298                         translate("Remote ping timeout") },
299                 { Value,
300                         "ping_restart",
301                         60,
302                         translate("Restart after remote ping timeout") },
303                 { Flag,
304                         "ping_timer_rem",
305                         0,
306                         translate("Only process ping timeouts if routes exist") },
307                 { Flag,
308                         "persist_tun",
309                         0,
310                         translate("Keep tun/tap device open on restart") },
311                 { Flag,
312                         "persist_key",
313                         0,
314                         translate("Don't re-read key on restart") },
315                 { Flag,
316                         "persist_local_ip",
317                         0,
318                         translate("Keep local IP address on restart") },
319                 { Flag,
320                         "persist_remote_ip",
321                         0,
322                         translate("Keep remote IP address on restart") },
323         -- management channel
324                 { Value,
325                         "management",
326                         "127.0.0.1 31194 /etc/openvpn/mngmt-pwds",
327                         translate("Enable management interface on <em>IP</em> <em>port</em>") },
328         -- management
329                 { Flag,
330                         "management_query_passwords",
331                         0,
332                         translate("Query management channel for private key") },
333         -- management
334                 { Flag,
335                         "management_hold",
336                         0,
337                         translate("Start OpenVPN in a hibernating state") },
338         -- management
339                 { Value,
340                         "management_log_cache",
341                         100,
342                         translate("Number of lines for log file history") },
343                 { ListValue,
344                         "topology",
345                         { "net30", "p2p", "subnet" },
346                         translate("'net30', 'p2p', or 'subnet'"),
347                         {dev_type="tun" } },
348         } },
349
350         { "VPN", {
351                 { Value,
352                         "server",
353                         "10.200.200.0 255.255.255.0",
354                         translate("Configure server mode"),
355                         { client="0" }, { client="" } },
356                 { Value,
357                         "server_bridge",
358                         "10.200.200.1 255.255.255.0 10.200.200.200 10.200.200.250",
359                         translate("Configure server bridge"),
360                         { client="0" }, { client="" } },
361                 { DynamicList,
362                         "push",
363                         { "redirect-gateway" },
364                         translate("Push options to peer"),
365                         { client="0" }, { client="" } },
366                 { Flag,
367                         "push_reset",
368                         0,
369                         translate("Don't inherit global push options"),
370                         { client="0" }, { client="" } },
371                 { Flag,
372                         "disable",
373                         0,
374                         translate("Client is disabled"),
375                         { client="0" }, { client="" } },
376                 { Value,
377                         "ifconfig_pool",
378                         "10.200.200.100 10.200.200.150 255.255.255.0",
379                         translate("Set aside a pool of subnets"),
380                         { client="0" }, { client="" } },
381                 { Value,
382                         "ifconfig_pool_persist",
383                         "/etc/openvpn/ipp.txt 600",
384                         translate("Persist/unpersist ifconfig-pool"),
385                         { client="0" }, { client="" } },
386                 { Value,
387                         "ifconfig_push",
388                         "10.200.200.1 255.255.255.255",
389                         translate("Push an ifconfig option to remote"),
390                         { client="0" }, { client="" } },
391                 { Value,
392                         "iroute",
393                         "10.200.200.0 255.255.255.0",
394                         translate("Route subnet to client"),
395                         { client="0" }, { client="" } },
396                 { Flag,
397                         "client_to_client",
398                         0,
399                         translate("Allow client-to-client traffic"),
400                         { client="0" }, { client="" } },
401                 { Flag,
402                         "duplicate_cn",
403                         0,
404                         translate("Allow multiple clients with same certificate"),
405                         { client="0" }, { client="" } },
406                 { Value,
407                         "client_config_dir",
408                         "/etc/openvpn/ccd",
409                         translate("Directory for custom client config files"),
410                         { client="0" }, { client="" } },
411                 { Flag,
412                         "ccd_exclusive",
413                         0,
414                         translate("Refuse connection if no custom client config"),
415                         { client="0" }, { client="" } },
416                 { Value,
417                         "tmp_dir",
418                         "/var/run/openvpn",
419                         translate("Temporary directory for client-connect return file"),
420                         { client="0" }, { client="" } },
421                 { Value,
422                         "hash_size",
423                         "256 256",
424                         translate("Set size of real and virtual address hash tables"),
425                         { client="0" }, { client="" } },
426                 { Value,
427                         "bcast_buffers",
428                         256,
429                         translate("Number of allocated broadcast buffers"),
430                         { client="0" }, { client="" } },
431                 { Value,
432                         "tcp_queue_limit",
433                         64,
434                         translate("Maximum number of queued TCP output packets"),
435                         { client="0" }, { client="" } },
436                 { Value,
437                         "max_clients",
438                         10,
439                         translate("Allowed maximum of connected clients"),
440                         { client="0" }, { client="" } },
441                 { Value,
442                         "max_routes_per_client",
443                         256,
444                         translate("Allowed maximum of internal"),
445                         { client="0" }, { client="" } },
446                 { Value,
447                         "connect_freq",
448                         "3 10",
449                         translate("Allowed maximum of new connections"),
450                         { client="0" }, { client="" } },
451                 { Flag,
452                         "username_as_common_name",
453                         0,
454                         translate("Use username as common name"),
455                         { client="0" }, { client="" } },
456                 { Flag,
457                         "client",
458                         0,
459                         translate("Configure client mode") },
460                 { Flag,
461                         "pull",
462                         0,
463                         translate("Accept options pushed from server"),
464                         { client="1" } },
465                 { FileUpload,
466                         "auth_user_pass",
467                         "/etc/openvpn/userpass.txt",
468                         translate("Authenticate using username/password"),
469                         { client="1" } },
470                 { ListValue,
471                         "auth_retry",
472                         { "none", "nointeract", "interact" },
473                         translate("Handling of authentication failures"),
474                         { client="1" } },
475                 { Value,
476                         "explicit_exit_notify",
477                         1,
478                         translate("Send notification to peer on disconnect"),
479                         { client="1" } },
480                 { DynamicList,
481                         "remote",
482                         "1.2.3.4",
483                         translate("Remote host name or ip address"),
484                         { client="1" } },
485                 { Flag,
486                         "remote_random",
487                         0,
488                         translate("Randomly choose remote server"),
489                         { client="1" } },
490                 { ListValue,
491                         "proto",
492                         { "udp", "tcp-client", "tcp-server" },
493                         translate("Use protocol"),
494                         { client="1" } },
495                 { Value,
496                         "connect_retry",
497                         5,
498                         translate("Connection retry interval"),
499                         { proto="tcp-client" }, { client="1" } },
500                 { Value,
501                         "http_proxy",
502                         "192.168.1.100 8080",
503                         translate("Connect to remote host through an HTTP proxy"),
504                         { client="1" } },
505                 { Flag,
506                         "http_proxy_retry",
507                         0,
508                         translate("Retry indefinitely on HTTP proxy errors"),
509                         { client="1" } },
510                 { Value,
511                         "http_proxy_timeout",
512                         5,
513                         translate("Proxy timeout in seconds"),
514                         { client="1" } },
515                 { DynamicList,
516                         "http_proxy_option",
517                         { "VERSION 1.0", "AGENT OpenVPN/2.0.9" },
518                         translate("Set extended HTTP proxy options"),
519                         { client="1" } },
520                 { Value,
521                         "socks_proxy",
522                         "192.168.1.200 1080",
523                         translate("Connect through Socks5 proxy"),
524                         { client="1" } },
525         -- client && socks_proxy
526                 { Value,
527                         "socks_proxy_retry",
528                         5,
529                         translate("Retry indefinitely on Socks proxy errors"),
530                         { client="1" } },
531                 { Value,
532                         "resolv_retry",
533                         "infinite",
534                         translate("If hostname resolve fails, retry"),
535                         { client="1" } },
536                 { ListValue,
537                         "redirect_gateway",
538                         { "", "local", "def1", "local def1" },
539                         translate("Automatically redirect default route"),
540                         { client="1" } },
541         } },
542
543         { "Cryptography", {
544                 { FileUpload,
545                         "secret",
546                         "/etc/openvpn/secret.key",
547                         translate("Enable Static Key encryption mode (non-TLS)") },
548         -- parse
549                 { Value,
550                         "auth",
551                         "SHA1",
552                         translate("HMAC authentication for packets") },
553         -- parse
554                 { Value,
555                         "cipher",
556                         "BF-CBC",
557                         translate("Encryption cipher for packets") },
558         -- parse
559                 { Value,
560                         "keysize",
561                         1024,
562                         translate("Size of cipher key") },
563         -- parse
564                 { Value,
565                         "engine",
566                         "dynamic",
567                         translate("Enable OpenSSL hardware crypto engines") },
568                 { Value,
569                         "replay_window",
570                         "64 15",
571                         translate("Replay protection sliding window size") },
572                 { Flag,
573                         "mute_replay_warnings",
574                         0,
575                         translate("Silence the output of replay warnings") },
576                 { Value,
577                         "replay_persist",
578                         "/var/run/openvpn-replay-state",
579                         translate("Persist replay-protection state") },
580                 { Flag,
581                         "tls_server",
582                         0,
583                         translate("Enable TLS and assume server role"),
584                         { tls_client="" }, { tls_client="0" } },
585                 { Flag,
586                         "tls_client",
587                         0,
588                         translate("Enable TLS and assume client role"),
589                         { tls_server="" }, { tls_server="0" } },
590                 { FileUpload,
591                         "ca",
592                         "/etc/easy-rsa/keys/ca.crt",
593                         translate("Certificate authority") },
594                 { FileUpload,
595                         "dh",
596                         "/etc/easy-rsa/keys/dh1024.pem",
597                         translate("Diffie Hellman parameters") },
598                 { FileUpload,
599                         "cert",
600                         "/etc/easy-rsa/keys/some-client.crt",
601                         translate("Local certificate") },
602                 { FileUpload,
603                         "key",
604                         "/etc/easy-rsa/keys/some-client.key",
605                         translate("Local private key") },
606                 { FileUpload,
607                         "pkcs12",
608                         "/etc/easy-rsa/keys/some-client.pk12",
609                         translate("PKCS#12 file containing keys") },
610                 { ListValue,
611                         "key_method",
612                         { 1, 2 },
613                         translate("Enable TLS and assume client role") },
614                 { Value,
615                         "tls_cipher",
616                         "DHE-RSA-AES256-SHA:DHE-DSS-AES256-SHA:AES256-SHA:EDH-RSA-DES-CBC3-SHA:EDH-DSS-DES-CBC3-SHA:DES-CBC3-SHA:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA:AES128-SHA:RC4-SHA:RC4-MD5:EDH-RSA-DES-CBC-SHA:EDH-DSS-DES-CBC-SHA:DES-CBC-SHA:EXP-EDH-RSA-DES-CBC-SHA:EXP-EDH-DSS-DES-CBC-SHA:EXP-DES-CBC-SHA:EXP-RC2-CBC-MD5:EXP-RC4-MD5",
617                         translate("TLS cipher") },
618                 { Value,
619                         "tls_timeout",
620                         2,
621                         translate("Retransmit timeout on TLS control channel") },
622                 { Value,
623                         "reneg_bytes",
624                         1024,
625                         translate("Renegotiate data chan. key after bytes") },
626                 { Value,
627                         "reneg_pkts",
628                         100,
629                         translate("Renegotiate data chan. key after packets") },
630                 { Value,
631                         "reneg_sec",
632                         3600,
633                         translate("Renegotiate data chan. key after seconds") },
634                 { Value,
635                         "hand_window",
636                         60,
637                         translate("Timeframe for key exchange") },
638                 { Value,
639                         "tran_window",
640                         3600,
641                         translate("Key transition window") },
642                 { Flag,
643                         "single_session",
644                         0,
645                         translate("Allow only one session") },
646                 { Flag,
647                         "tls_exit",
648                         0,
649                         translate("Exit on TLS negotiation failure") },
650                 { Value,
651                         "tls_auth",
652                         "/etc/openvpn/tlsauth.key",
653                         translate("Additional authentication over TLS") },
654                 { Value,
655                         "tls_crypt",
656                         "/etc/openvpn/tlscrypt.key",
657                         translate("Encrypt and authenticate all control channel packets with the key") },
658         --      { Value,
659         --              "askpass",
660         --              "[file]",
661         --              translate("Get PEM password from controlling tty before we daemonize") },
662                 { Flag,
663                         "auth_nocache",
664                         0,
665                         translate("Don't cache --askpass or --auth-user-pass passwords") },
666                 { Value,
667                         "tls_remote",
668                         "remote_x509_name",
669                         translate("Only accept connections from given X509 name") },
670                 { ListValue,
671                         "ns_cert_type",
672                         { "client", "server" },
673                         translate("Require explicit designation on certificate") },
674                 { ListValue,
675                         "remote_cert_tls",
676                         { "client", "server" },
677                         translate("Require explicit key usage on certificate") },
678                 { Value,
679                         "crl_verify",
680                         "/etc/easy-rsa/keys/crl.pem",
681                         translate("Check peer certificate against a CRL") },
682                 { Value,
683                         "tls_version_min",
684                         "1.0",
685                         translate("The lowest supported TLS version") },
686                 { Value,
687                         "tls_version_max",
688                         "1.2",
689                         translate("The highest supported TLS version") },
690                 { ListValue,
691                         "key_direction",
692                         { 0, 1 },
693                         translate("The key direction for 'tls-auth' and 'secret' options") },
694         } }
695 }
696
697
698 local cts = { }
699 local params = { }
700
701 local m = Map("openvpn")
702 m.redirect = luci.dispatcher.build_url("admin", "services", "openvpn")
703 m.apply_on_parse = true
704
705 local p = m:section( SimpleSection )
706 p.template = "openvpn/pageswitch"
707 p.mode     = "advanced"
708 p.instance = arg[1]
709 p.category = arg[2] or "Service"
710
711 for _, c in ipairs(knownParams) do
712         cts[#cts+1] = c[1]
713         if c[1] == p.category then params = c[2] end
714 end
715
716 p.categories = cts
717
718
719 local s = m:section(
720         NamedSection, arg[1], "openvpn",
721         translate("%s" % arg[2])
722 )
723
724 s.title     = translate("%s" % arg[2])
725 s.addremove = false
726 s.anonymous = true
727
728
729 for _, option in ipairs(params) do
730         local o = s:option(
731                 option[1], option[2],
732                 option[2], option[4]
733         )
734
735         o.optional = true
736
737         if option[1] == DummyValue then
738                 o.value = option[3]
739         elseif option[1] == FileUpload then
740
741                 function o.cfgvalue(self, section)
742                         local cfg_val = AbstractValue.cfgvalue(self, section)
743
744                         if cfg_val then
745                                 return cfg_val
746                         end
747                 end
748
749                 function o.formvalue(self, section)
750                         local sel_val = AbstractValue.formvalue(self, section)
751                         local txt_val = luci.http.formvalue("cbid."..self.map.config.."."..section.."."..self.option..".textbox")
752
753                         if sel_val and sel_val ~= "" then
754                                 return sel_val
755                         end
756
757                         if txt_val and txt_val ~= "" then
758                                 return txt_val
759                         end
760                 end
761
762                 function o.remove(self, section)
763                         local cfg_val = AbstractValue.cfgvalue(self, section)
764                         local txt_val = luci.http.formvalue("cbid."..self.map.config.."."..section.."."..self.option..".textbox")
765                         
766                         if cfg_val and fs.access(cfg_val) and txt_val == "" then
767                                 fs.unlink(cfg_val)
768                         end
769                         return AbstractValue.remove(self, section)
770                 end
771         elseif option[1] == Flag then
772                 o.default = nil
773         else
774                 if option[1] == DynamicList then
775                         function o.cfgvalue(...)
776                                 local val = AbstractValue.cfgvalue(...)
777                                 return ( val and type(val) ~= "table" ) and { val } or val
778                         end
779                 end
780
781                 if type(option[3]) == "table" then
782                         if o.optional then o:value("", "-- remove --") end
783                         for _, v in ipairs(option[3]) do
784                                 v = tostring(v)
785                                 o:value(v)
786                         end
787                         o.default = tostring(option[3][1])
788                 else
789                         o.default = tostring(option[3])
790                 end
791         end
792
793         for i=5,#option do
794                 if type(option[i]) == "table" then
795                         o:depends(option[i])
796                 end
797         end
798 end
799
800 return m