summaryrefslogtreecommitdiffstats
path: root/raddb/policy.d/filter
diff options
context:
space:
mode:
Diffstat (limited to 'raddb/policy.d/filter')
-rw-r--r--raddb/policy.d/filter211
1 files changed, 211 insertions, 0 deletions
diff --git a/raddb/policy.d/filter b/raddb/policy.d/filter
new file mode 100644
index 0000000..ff8f531
--- /dev/null
+++ b/raddb/policy.d/filter
@@ -0,0 +1,211 @@
+#
+# Example of forbidding all attempts to login via
+# realms.
+#
+deny_realms {
+ if (&User-Name && (&User-Name =~ /@|\\/)) {
+ reject
+ }
+}
+
+#
+# Filter the username
+#
+# Force some sanity on User-Name. This helps to avoid issues
+# issues where the back-end database is "forgiving" about
+# what constitutes a user name.
+#
+filter_username {
+ if (&User-Name) {
+ #
+ # reject mixed case e.g. "UseRNaMe"
+ #
+ #if (&User-Name != "%{tolower:%{User-Name}}") {
+ # reject
+ #}
+
+ #
+ # reject all whitespace
+ # e.g. "user@ site.com", or "us er", or " user", or "user "
+ #
+ if (&User-Name =~ / /) {
+ update request {
+ &Module-Failure-Message += 'Rejected: User-Name contains whitespace'
+ }
+ reject
+ }
+
+ #
+ # reject Multiple @'s
+ # e.g. "user@site.com@site.com"
+ #
+ if (&User-Name =~ /@[^@]*@/ ) {
+ update request {
+ &Module-Failure-Message += 'Rejected: Multiple @ in User-Name'
+ }
+ reject
+ }
+
+ #
+ # reject double dots
+ # e.g. "user@site..com"
+ #
+ if (&User-Name =~ /\.\./ ) {
+ update request {
+ &Module-Failure-Message += 'Rejected: User-Name contains multiple ..s'
+ }
+ reject
+ }
+
+ #
+ # must have at least 1 string-dot-string after @
+ # e.g. "user@site.com"
+ #
+ if ((&User-Name =~ /@/) && (&User-Name !~ /@(.+)\.(.+)$/)) {
+ update request {
+ &Module-Failure-Message += 'Rejected: Realm does not have at least one dot separator'
+ }
+ reject
+ }
+
+ #
+ # Realm ends with a dot
+ # e.g. "user@site.com."
+ #
+ if (&User-Name =~ /\.$/) {
+ update request {
+ &Module-Failure-Message += 'Rejected: Realm ends with a dot'
+ }
+ reject
+ }
+
+ #
+ # Realm begins with a dot
+ # e.g. "user@.site.com"
+ #
+ if (&User-Name =~ /@\./) {
+ update request {
+ &Module-Failure-Message += 'Rejected: Realm begins with a dot'
+ }
+ reject
+ }
+ }
+}
+
+#
+# Filter the User-Password
+#
+# Some equipment sends passwords with embedded zeros.
+# This policy filters them out.
+#
+filter_password {
+ if (&User-Password && \
+ (&User-Password != "%{string:User-Password}")) {
+ update request {
+ &Tmp-String-0 := "%{string:User-Password}"
+ &User-Password := "%{string:Tmp-String-0}"
+ &Tmp-String-0 !* ""
+ }
+ }
+}
+
+filter_inner_identity {
+ #
+ # No names, reject.
+ #
+ if (!&outer.request:User-Name || !&User-Name) {
+ update request {
+ Module-Failure-Message = "User-Name is required for tunneled authentication"
+ }
+ reject
+ }
+
+ #
+ # Do detailed checks only if the inner and outer
+ # NAIs are different.
+ #
+ # If the NAIs are the same, it violates user privacy,
+ # but is allowed.
+ #
+ if (&outer.request:User-Name != &User-Name) {
+ #
+ # Get the outer realm.
+ #
+ if (&outer.request:User-Name =~ /@([^@]+)$/) {
+ update request {
+ Outer-Realm-Name = "%{1}"
+ }
+
+ #
+ # When we have an outer realm name, the user portion
+ # MUST either be empty, or begin with "anon".
+ #
+ # We don't check for the full "anonymous", because
+ # some vendors don't follow the standards.
+ #
+ if (&outer.request:User-Name !~ /^(anon|@)/) {
+ update request {
+ Module-Failure-Message = "User-Name is not anonymized"
+ }
+ reject
+ }
+ }
+
+ #
+ # There's no outer realm. The outer NAI is different from the
+ # inner NAI. The User-Name MUST be anonymized.
+ #
+ # Otherwise, you could log in as outer "bob", and inner "doug",
+ # and we'd have no idea which one was correct.
+ #
+ elsif (&outer.request:User-Name !~ /^anon/) {
+ update request {
+ Module-Failure-Message = "User-Name is not anonymized"
+ }
+ reject
+ }
+
+ #
+ # Get the inner realm.
+ #
+ if (&User-Name =~ /@([^@]+)$/) {
+ update request {
+ Inner-Realm-Name = "%{1}"
+ }
+
+ #
+ # Note that we do EQUALITY checks for realm names.
+ # There is no simple way to do case insensitive checks
+ # on internationalized domain names. There is no reason
+ # to allow outer "anonymous@EXAMPLE.COM" and inner
+ # "user@example.com". The user should enter the same
+ # realm for both identities.
+ #
+ # If the inner realm isn't the same as the outer realm,
+ # the inner realm MUST be a subdomain of the outer realm.
+ #
+ if (&Outer-Realm-Name && \
+ (&Inner-Realm-Name != &Outer-Realm-Name) && \
+ (&Inner-Realm-Name !~ /\.%{Outer-Realm-Name}$/)) {
+ update request {
+ Module-Failure-Message = "Inner realm '%{Inner-Realm-Name}' and outer realm '%{Outer-Realm-Name}' are not from the same domain."
+ }
+ reject
+ }
+
+ #
+ # It's OK to have an inner realm and no outer realm.
+ #
+ # That won't work for roaming, but the local RADIUS server
+ # can still authenticate the user.
+ #
+ }
+
+ #
+ # It's OK to have an outer realm and no inner realm.
+ #
+ # It will work for roaming, and the local RADIUS server
+ # can authenticate the user without the realm.
+ #
+ }
+}