mirror of
https://github.com/laurivosandi/certidude
synced 2024-12-22 08:15:18 +00:00
Bugfixes, OU support and image builder fixes
This commit is contained in:
parent
388f58574b
commit
5cb7f89c1b
@ -44,6 +44,7 @@ class SessionResource(object):
|
||||
except IOError:
|
||||
submission_hostname = None
|
||||
yield dict(
|
||||
server = authority.server_flags(common_name),
|
||||
submitted = submitted,
|
||||
common_name = common_name,
|
||||
address = submission_address,
|
||||
@ -103,6 +104,7 @@ class SessionResource(object):
|
||||
|
||||
yield dict(
|
||||
serial = "%x" % cert.serial_number,
|
||||
organizational_unit = cert.subject.native.get("organizational_unit_name"),
|
||||
common_name = common_name,
|
||||
# TODO: key type, key length, key exponent, key modulo
|
||||
signed = signed,
|
||||
@ -158,10 +160,8 @@ class SessionResource(object):
|
||||
request_subnets = config.REQUEST_SUBNETS or None,
|
||||
admin_subnets=config.ADMIN_SUBNETS or None,
|
||||
signature = dict(
|
||||
server_certificate_lifetime=config.SERVER_CERTIFICATE_LIFETIME,
|
||||
client_certificate_lifetime=config.CLIENT_CERTIFICATE_LIFETIME,
|
||||
revocation_list_lifetime=config.REVOCATION_LIST_LIFETIME,
|
||||
profiles = [dict(organizational_unit=ou, flags=f, lifetime=lt) for f, lt, ou in config.PROFILES.values()]
|
||||
profiles = [dict(name=k, server=v[0]=="server", lifetime=v[1], organizational_unit=v[2], title=v[3]) for k,v in config.PROFILES.items()]
|
||||
)
|
||||
) if req.context.get("user").is_admin() else None,
|
||||
features=dict(
|
||||
|
@ -21,6 +21,7 @@ class ImageBuilderResource(object):
|
||||
suffix = config.cp2.get(profile, "filename")
|
||||
|
||||
build = "/var/lib/certidude/builder/" + profile
|
||||
log_path = build + "/build.log"
|
||||
if not os.path.exists(build + "/overlay/etc/uci-defaults"):
|
||||
os.makedirs(build + "/overlay/etc/uci-defaults")
|
||||
os.system("rsync -av " + overlay_path + "/ " + build + "/overlay/")
|
||||
@ -31,12 +32,16 @@ class ImageBuilderResource(object):
|
||||
fh.write(template.render(authority_name=const.FQDN))
|
||||
|
||||
proc = subprocess.Popen(("/bin/bash", build_script_path),
|
||||
stdout=open(build + "/build.log", "w"), stderr=subprocess.STDOUT,
|
||||
stdout=open(log_path, "w"), stderr=subprocess.STDOUT,
|
||||
close_fds=True, shell=False,
|
||||
cwd=build,
|
||||
env={"PROFILE":model, "PATH":"/usr/sbin:/usr/bin:/sbin:/bin"},
|
||||
cwd=os.path.dirname(os.path.realpath(build_script_path)),
|
||||
env={"PROFILE":model, "PATH":"/usr/sbin:/usr/bin:/sbin:/bin",
|
||||
"BUILD":build, "OVERLAY":build + "/overlay/"},
|
||||
startupinfo=None, creationflags=0)
|
||||
proc.communicate()
|
||||
if proc.returncode:
|
||||
logger.info("Build script finished with non-zero exitcode, see %s for more information" % log_path)
|
||||
raise falcon.HTTPInternalServerError("Build script finished with non-zero exitcode")
|
||||
|
||||
for dname in os.listdir(build):
|
||||
if dname.startswith("lede-imagebuilder-"):
|
||||
|
@ -33,6 +33,11 @@ class LeaseResource(object):
|
||||
@authorize_server
|
||||
def on_post(self, req, resp):
|
||||
client_common_name = req.get_param("client", required=True)
|
||||
if "=" in client_common_name: # It's actually DN, resolve it to CN
|
||||
_, client_common_name = client_common_name.split(" CN=", 1)
|
||||
if "," in client_common_name:
|
||||
client_common_name, _ = client_common_name.split(",", 1)
|
||||
|
||||
path, buf, cert, signed, expires = authority.get_signed(client_common_name) # TODO: catch exceptions
|
||||
if req.get_param("serial") and cert.serial_number != req.get_param_as_int("serial"): # OCSP-ish solution for OpenVPN, not exposed for StrongSwan
|
||||
raise falcon.HTTPForbidden("Forbidden", "Invalid serial number supplied")
|
||||
|
@ -225,7 +225,10 @@ class RequestDetailResource(object):
|
||||
Sign a certificate signing request
|
||||
"""
|
||||
try:
|
||||
cert, buf = authority.sign(cn, ou=req.get_param("ou"), overwrite=True, signer=req.context.get("user").name)
|
||||
cert, buf = authority.sign(cn,
|
||||
profile=req.get_param("profile", default="default"),
|
||||
overwrite=True,
|
||||
signer=req.context.get("user").name)
|
||||
# Mailing and long poll publishing implemented in the function above
|
||||
except EnvironmentError: # no such CSR
|
||||
raise falcon.HTTPNotFound()
|
||||
|
@ -38,6 +38,7 @@ class SignedCertificateDetailResource(object):
|
||||
common_name = cn,
|
||||
signer = signer_username,
|
||||
serial_number = "%x" % cert.serial_number,
|
||||
organizational_unit = cert.subject.native.get("organizational_unit_name"),
|
||||
signed = cert["tbs_certificate"]["validity"]["not_before"].native.strftime("%Y-%m-%dT%H:%M:%S.%f")[:-3] + "Z",
|
||||
expires = cert["tbs_certificate"]["validity"]["not_after"].native.strftime("%Y-%m-%dT%H:%M:%S.%f")[:-3] + "Z",
|
||||
sha256sum = hashlib.sha256(buf).hexdigest()))
|
||||
|
@ -55,7 +55,7 @@ def self_enroll():
|
||||
fh.write(asymmetric.dump_private_key(private_key, None))
|
||||
else:
|
||||
now = datetime.utcnow()
|
||||
if now - timedelta(days=1) < expires:
|
||||
if now + timedelta(days=1) < expires:
|
||||
click.echo("Certificate %s still valid, delete to self-enroll again" % path)
|
||||
return
|
||||
|
||||
@ -307,7 +307,7 @@ def delete_request(common_name):
|
||||
config.LONG_POLL_PUBLISH % hashlib.sha256(buf).hexdigest(),
|
||||
headers={"User-Agent": "Certidude API"})
|
||||
|
||||
def sign(common_name, skip_notify=False, skip_push=False, overwrite=False, ou=None, signer=None):
|
||||
def sign(common_name, skip_notify=False, skip_push=False, overwrite=False, profile="default", signer=None):
|
||||
"""
|
||||
Sign certificate signing request by it's common name
|
||||
"""
|
||||
@ -320,13 +320,15 @@ def sign(common_name, skip_notify=False, skip_push=False, overwrite=False, ou=No
|
||||
|
||||
|
||||
# Sign with function below
|
||||
cert, buf = _sign(csr, csr_buf, skip_notify, skip_push, overwrite, ou, signer)
|
||||
cert, buf = _sign(csr, csr_buf, skip_notify, skip_push, overwrite, profile, signer)
|
||||
|
||||
os.unlink(req_path)
|
||||
return cert, buf
|
||||
|
||||
def _sign(csr, buf, skip_notify=False, skip_push=False, overwrite=False, ou=None, signer=None):
|
||||
def _sign(csr, buf, skip_notify=False, skip_push=False, overwrite=False, profile="default", signer=None):
|
||||
# TODO: CRLDistributionPoints, OCSP URL, Certificate URL
|
||||
if profile not in config.PROFILES:
|
||||
raise ValueError("Invalid profile supplied '%s'" % profile)
|
||||
|
||||
assert buf.startswith(b"-----BEGIN CERTIFICATE REQUEST-----")
|
||||
assert isinstance(csr, CertificationRequest)
|
||||
@ -367,8 +369,9 @@ def _sign(csr, buf, skip_notify=False, skip_push=False, overwrite=False, ou=None
|
||||
|
||||
# Sign via signer process
|
||||
dn = {u'common_name': common_name }
|
||||
if ou:
|
||||
dn["organizational_unit"] = ou
|
||||
profile_server_flags, lifetime, dn["organizational_unit_name"], _ = config.PROFILES[profile]
|
||||
lifetime = int(lifetime)
|
||||
|
||||
builder = CertificateBuilder(dn, csr_pubkey)
|
||||
builder.serial_number = random.randint(
|
||||
0x1000000000000000000000000000000000000000,
|
||||
@ -376,16 +379,14 @@ def _sign(csr, buf, skip_notify=False, skip_push=False, overwrite=False, ou=None
|
||||
|
||||
now = datetime.utcnow()
|
||||
builder.begin_date = now - timedelta(minutes=5)
|
||||
builder.end_date = now + timedelta(days=config.SERVER_CERTIFICATE_LIFETIME
|
||||
if server_flags(common_name)
|
||||
else config.CLIENT_CERTIFICATE_LIFETIME)
|
||||
builder.end_date = now + timedelta(days=lifetime)
|
||||
builder.issuer = certificate
|
||||
builder.ca = False
|
||||
builder.key_usage = set(["digital_signature", "key_encipherment"])
|
||||
|
||||
# OpenVPN uses CN while StrongSwan uses SAN
|
||||
if server_flags(common_name):
|
||||
builder.subject_alt_domains = [common_name]
|
||||
# If we have FQDN and profile suggests server flags, enable them
|
||||
if server_flags(common_name) and profile_server_flags:
|
||||
builder.subject_alt_domains = [common_name] # OpenVPN uses CN while StrongSwan uses SAN to match hostname of the server
|
||||
builder.extended_key_usage = set(["server_auth", "1.3.6.1.5.5.8.2.2", "client_auth"])
|
||||
else:
|
||||
builder.extended_key_usage = set(["client_auth"])
|
||||
|
@ -1312,7 +1312,7 @@ def certidude_list(verbose, show_key_type, show_extensions, show_path, show_sign
|
||||
def certidude_sign(common_name, overwrite):
|
||||
from certidude import authority
|
||||
drop_privileges()
|
||||
cert = authority.sign(common_name, overwrite)
|
||||
cert = authority.sign(common_name, overwrite=overwrite)
|
||||
|
||||
|
||||
@click.command("revoke", help="Revoke certificate")
|
||||
|
@ -60,8 +60,6 @@ USER_MULTIPLE_CERTIFICATES = {
|
||||
cp.get("authority", "user enrollment")]
|
||||
|
||||
REQUEST_SUBMISSION_ALLOWED = cp.getboolean("authority", "request submission allowed")
|
||||
CLIENT_CERTIFICATE_LIFETIME = cp.getint("signature", "client certificate lifetime")
|
||||
SERVER_CERTIFICATE_LIFETIME = cp.getint("signature", "server certificate lifetime")
|
||||
AUTHORITY_CERTIFICATE_URL = cp.get("signature", "authority certificate url")
|
||||
AUTHORITY_CRL_URL = cp.get("signature", "revoked url")
|
||||
AUTHORITY_OCSP_URL = cp.get("signature", "responder url")
|
||||
|
@ -118,7 +118,7 @@ function onRequestSubmitted(e) {
|
||||
console.info("Going to prepend:", request);
|
||||
onRequestDeleted(e); // Delete any existing ones just in case
|
||||
$("#pending_requests").prepend(
|
||||
env.render('views/request.html', { request: request }));
|
||||
env.render('views/request.html', { request: request, session: session }));
|
||||
$("#pending_requests time").timeago();
|
||||
},
|
||||
error: function(response) {
|
||||
|
@ -28,23 +28,105 @@ curl -f -L -H "Content-type: application/pkcs10" --data-binary @client_req.pem \
|
||||
http://{{ window.location.hostname }}/api/request/?wait=yes > client_cert.pem</code></pre>
|
||||
</div>
|
||||
|
||||
<h5>Vanilla OpenWrt/LEDE</h5>
|
||||
<h5>OpenVPN gateway on OpenWrt/LEDE router</h5>
|
||||
|
||||
<p>On OpenWrt/LEDE router to convert it into VPN gateway:</p>
|
||||
<p>First enroll certificates:</p>
|
||||
<div class="highlight">
|
||||
<pre class="code"><code>mkdir -p /var/lib/certidude/{{ window.location.hostname }}; \
|
||||
grep -c certidude /etc/sysupgrade.conf || echo /var/lib/certidude >> /etc/sysupgrade.conf; \
|
||||
curl -f http://{{ window.location.hostname }}/api/certificate/ -o /var/lib/certidude/{{ window.location.hostname }}/ca_cert.pem; \
|
||||
test -e /var/lib/certidude/{{ window.location.hostname }}/client_key.pem || openssl genrsa -out /var/lib/certidude/{{ window.location.hostname }}/client_key.pem 2048; \
|
||||
test -e /var/lib/certidude/{{ window.location.hostname }}/client_req.pem || read -p "Enter FQDN: " NAME; openssl req -new -sha256 \
|
||||
-key /var/lib/certidude/{{ window.location.hostname }}/client_key.pem \
|
||||
-out /var/lib/certidude/{{ window.location.hostname }}/client_req.pem -subj "/CN=$NAME"; \
|
||||
<pre class="code"><code># Derive FQDN from WAN interface's reverse DNS record
|
||||
FQDN=$(nslookup $(uci get network.wan.ipaddr) | grep "name =" | head -n1 | cut -d "=" -f 2 | xargs)
|
||||
|
||||
mkdir -p /etc/certidude/authority/{{ window.location.hostname }}; \
|
||||
grep -c certidude /etc/sysupgrade.conf || echo /etc/certidude >> /etc/sysupgrade.conf; \
|
||||
curl -f http://{{ window.location.hostname }}/api/certificate/ -o /etc/certidude/authority/{{ window.location.hostname }}/ca_cert.pem; \
|
||||
test -e /etc/certidude/authority/{{ window.location.hostname }}/server_key.pem \
|
||||
|| openssl genrsa -out /etc/certidude/authority/{{ window.location.hostname }}/server_key.pem 2048; \
|
||||
test -e /etc/certidude/authority/{{ window.location.hostname }}/server_req.pem \
|
||||
|| openssl req -new -sha256 \
|
||||
-key /etc/certidude/authority/{{ window.location.hostname }}/server_key.pem \
|
||||
-out /etc/certidude/authority/{{ window.location.hostname }}/server_req.pem -subj "/CN=$FQDN"; \
|
||||
curl -f -L -H "Content-type: application/pkcs10" \
|
||||
--data-binary @/var/lib/certidude/{{ window.location.hostname }}/client_req.pem \
|
||||
-o /var/lib/certidude/{{ window.location.hostname }}/client_cert.pem \
|
||||
--data-binary @/etc/certidude/authority/{{ window.location.hostname }}/server_req.pem \
|
||||
-o /etc/certidude/authority/{{ window.location.hostname }}/server_cert.pem \
|
||||
http://{{ window.location.hostname }}/api/request/?wait=yes</code></pre>
|
||||
</div>
|
||||
|
||||
<p>Then set up service:</p>
|
||||
<div class="highlight">
|
||||
<pre class="code"><code># Create VPN gateway up/down script for reporting client IP addresses to CA
|
||||
cat <<\EOF > /etc/certidude/updown
|
||||
#!/bin/sh
|
||||
CURL="curl -f --key /etc/certidude/authority/{{ window.location.hostname }}/server_key.pem --cert /etc/certidude/authority/{{ window.location.hostname }}/server_cert.pem --cacert /etc/certidude/authority/{{ window.location.hostname }}/ca_cert.pem https://{{ window.location.hostname }}:8443/api/lease/"
|
||||
|
||||
case $PLUTO_VERB in
|
||||
up-client|down-client) $CURL --data "outer_address=$PLUTO_PEER&inner_address=$PLUTO_PEER_SOURCEIP&client=$PLUTO_PEER_ID" ;;
|
||||
*) $CURL --data "client=$X509_0_CN&outer_address=$untrusted_ip&inner_address=$ifconfig_pool_remote_ip&serial=$tls_serial_0" ;;
|
||||
esac
|
||||
EOF
|
||||
|
||||
chmod +x /etc/certidude/updown
|
||||
|
||||
|
||||
# Generate Diffie-Hellman parameters file for OpenVPN
|
||||
test -e /etc/certidude/dh.pem \
|
||||
|| openssl dhparam 2048 -out /etc/certidude/dh.pem
|
||||
|
||||
# Create interface definition for tunnel
|
||||
uci set network.vpn=interface
|
||||
uci set network.vpn.name='vpn'
|
||||
uci set network.vpn.ifname=tun_s2c
|
||||
uci set network.vpn.proto='none'
|
||||
|
||||
# Create zone definition for VPN interface
|
||||
uci set firewall.vpn=zone
|
||||
uci set firewall.vpn.name='vpn'
|
||||
uci set firewall.vpn.input='ACCEPT'
|
||||
uci set firewall.vpn.forward='ACCEPT'
|
||||
uci set firewall.vpn.output='ACCEPT'
|
||||
uci set firewall.vpn.network='vpn'
|
||||
|
||||
# Allow UDP 1194 on WAN interface
|
||||
uci set firewall.openvpn=rule
|
||||
uci set firewall.openvpn.name='Allow OpenVPN'
|
||||
uci set firewall.openvpn.src='wan'
|
||||
uci set firewall.openvpn.dest_port=1194
|
||||
uci set firewall.openvpn.proto='udp'
|
||||
uci set firewall.openvpn.target='ACCEPT'
|
||||
|
||||
# Forward traffic from VPN to LAN
|
||||
uci set firewall.c2s=forwarding
|
||||
uci set firewall.c2s.src='vpn'
|
||||
uci set firewall.c2s.dest='lan'
|
||||
|
||||
# Permit DNS queries from VPN
|
||||
uci set dhcp.@dnsmasq[0].localservice='0'
|
||||
|
||||
touch /etc/config/openvpn
|
||||
uci set openvpn.s2c=openvpn
|
||||
uci set openvpn.s2c.local=$(uci get network.wan.ipaddr)
|
||||
uci set openvpn.s2c.script_security=2
|
||||
uci set openvpn.s2c.client_connect='/etc/certidude/updown'
|
||||
uci set openvpn.s2c.tls_version_min='1.2'
|
||||
uci set openvpn.s2c.tls_cipher='TLS-DHE-RSA-WITH-AES-256-GCM-SHA384'
|
||||
uci set openvpn.s2c.cipher='AES-256-CBC'
|
||||
uci set openvpn.s2c.auth='SHA384'
|
||||
uci set openvpn.s2c.dev=tun_s2c
|
||||
uci set openvpn.s2c.server='10.179.43.0 255.255.255.0'
|
||||
uci set openvpn.s2c.key='/etc/certidude/authority/{{ window.location.hostname }}/server_key.pem'
|
||||
uci set openvpn.s2c.cert='/etc/certidude/authority/{{ window.location.hostname }}/server_cert.pem'
|
||||
uci set openvpn.s2c.ca='/etc/certidude/authority/{{ window.location.hostname }}/ca_cert.pem'
|
||||
uci set openvpn.s2c.dh='/etc/certidude/dh.pem'
|
||||
uci set openvpn.s2c.enabled=1
|
||||
uci set openvpn.s2c.comp_lzo=yes
|
||||
uci add_list openvpn.s2c.push="route-metric 1000"
|
||||
uci add_list openvpn.s2c.push="route $(uci get network.lan.ipaddr) $(uci get network.lan.netmask)"
|
||||
uci add_list openvpn.s2c.push="dhcp-option DNS $(uci get network.lan.ipaddr)"
|
||||
uci add_list openvpn.s2c.push="dhcp-option DOMAIN $(uci get dhcp.@dnsmasq[0].domain)"
|
||||
|
||||
/etc/init.d/openvpn restart
|
||||
/etc/init.d/firewall restart</code></pre>
|
||||
</div>
|
||||
|
||||
|
||||
{% if session.authority.builder %}
|
||||
<h5>OpenWrt/LEDE image builder</h5>
|
||||
<p>Hit a link to generate machine specific image. Note that this might take couple minutes to finish.</p>
|
||||
|
@ -30,10 +30,11 @@
|
||||
</button>
|
||||
<div class="dropdown-menu">
|
||||
{% for p in session.authority.signature.profiles %}
|
||||
<a class="dropdown-item" href="/api/request/?organizational_unit={{ p.organizational_unit }}&lifetime={{ p.lifetime }}&flags={{ p.flags }}">
|
||||
{% if p.organizational_unit %}
|
||||
{{ p.organizational_unit }} ({{ p.flags }}){% else %}
|
||||
{{ p.flags | capitalize }}{% endif %}, expires in {{ p.lifetime }} days</a>
|
||||
<a class="dropdown-item{% if p.server and not request.server %} disabled{% endif %}"
|
||||
{% if p.server and not request.server %}title="Resubmit with FQDN as common name"{% endif %}
|
||||
href="#" onclick="javascript:$.ajax({url:'/api/request/{{request.common_name}}/?sha256sum={{ request.sha256sum }}&profile={{ p.name }}',type:'post'});">
|
||||
{% if p.title %}{{ p.title }} ({% if p.server %}server{% else %}client{% endif %}){% else %}
|
||||
{% if p.server %}Server{% else %}Client{% endif %}{% endif %}, expires in {{ p.lifetime }} days</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,6 +1,10 @@
|
||||
<p>
|
||||
<div id="certificate-{{ certificate.common_name | replace('@', '--') | replace('.', '-') }}" class="card">
|
||||
<div class="card-header">
|
||||
{% if certificate.organizational_unit %}
|
||||
<i class="fa fa-folder" aria-hidden="true"></i>
|
||||
{{ certificate.organizational_unit }} /
|
||||
{% endif %}
|
||||
{% if certificate.server %}
|
||||
<i class="fa fa-server"></i>
|
||||
{% else %}
|
||||
@ -17,12 +21,9 @@
|
||||
</span>
|
||||
|
||||
Signed
|
||||
<time class="timeago" datetime="{{ certificate.signed }}">Certificate was signed {{ certificate.signed }}</time>,
|
||||
<time class="timeago" datetime="{{ certificate.signed }}">Certificate was signed {{ certificate.signed }}</time>{% if certificate.signer %} by {{ certificate.signer }}{% endif %},
|
||||
expires
|
||||
<time class="timeago" datetime="{{ certificate.expires }}">Certificate expires {{ certificate.expires }}</time>.
|
||||
{% if certificate.organizational_unit %}
|
||||
Part of {{ certificate.organizational_unit }} organizational unit.
|
||||
{% endif %}
|
||||
</p>
|
||||
<p>
|
||||
{% if session.authority.tagging %}
|
||||
@ -91,10 +92,10 @@ curl --cert client_cert.pem https://{{ window.location.hostname }}:8443/api/sign
|
||||
<div style="overflow: auto; max-width: 100%;">
|
||||
<table class="table" id="signed_certificates">
|
||||
<tbody>
|
||||
<tr><th>Common name</th><td>{{ certificate.common_name }}</td></tr>
|
||||
<tr><th>Organizational unit</th><td>{% if certificate.organizational_unit %}{{ certificate.organizational_unit }}{% else %}-{% endif %}</td></tr>
|
||||
<tr><th>Common name</th><td>{{ certificate.common_name }}</td></tr>
|
||||
<tr><th>Organizational unit</th><td>{% if certificate.organizational_unit %}{{ certificate.organizational_unit }}{% else %}-{% endif %}</td></tr>
|
||||
<tr><th>Serial number</th><td style="word-wrap:break-word;">{{ certificate.serial | serial }}</td></tr>
|
||||
<tr><th>Signed</th><td>{{ certificate.signed | datetime }}{% if certificate.signer %}, by {{ certificate.signer }}{% endif %}</td></tr>
|
||||
<tr><th>Signed</th><td>{{ certificate.signed | datetime }}{% if certificate.signer %} by {{ certificate.signer }}{% endif %}</td></tr>
|
||||
<tr><th>Expires</th><td>{{ certificate.expires | datetime }}</td></tr>
|
||||
{% if certificate.lease %}
|
||||
<tr><th>Lease</th><td><a href="http://{{ certificate.lease.inner_address }}">{{ certificate.lease.inner_address }}</a> at {{ certificate.lease.last_seen | datetime }}
|
||||
|
@ -191,13 +191,13 @@ lifetime = 30
|
||||
# Secret for generating and validating tokens, regenerate occasionally
|
||||
secret = {{ token_secret }}
|
||||
|
||||
|
||||
[profile]
|
||||
# title, flags, lifetime, organizational unit
|
||||
default = client, 120,
|
||||
srv = server, 365, Server
|
||||
gw = server, 3, Gateway
|
||||
ap = client, 1825, Access Point
|
||||
# name, flags, lifetime, organizational unit, title
|
||||
default = client, 120, Roadwarrior, Roadwarrior
|
||||
gw = server, 30, Gateway, Gateway
|
||||
srv = server, 365, Server,
|
||||
ap = client, 1825, Access Point, Access Point
|
||||
mfp = client, 30, MFP, Printers
|
||||
|
||||
[script]
|
||||
# Path to the folder with scripts that can be served to the clients, set none to disable scripting
|
||||
|
Loading…
Reference in New Issue
Block a user