Skip to content

Instantly share code, notes, and snippets.

@rnewson
Created December 18, 2015 12:56
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save rnewson/37bc23b803ce10ce22b9 to your computer and use it in GitHub Desktop.
refuse to bind non-locally if there's no admin user
index ef89873..74a0964 100644
--- a/src/couch_httpd.erl
+++ b/src/couch_httpd.erl
@@ -1103,13 +1103,43 @@ check_for_last(#mp{buffer=Buffer, data_fun=DataFun}=Mp) ->
data_fun = DataFun2})
end.
-validate_bind_address(any) -> ok;
+validate_bind_address(any) ->
+ assert_admins_if_remote({0,0,0,0});
validate_bind_address(Address) ->
case inet_parse:address(Address) of
- {ok, _} -> ok;
- _ -> throw({error, invalid_bind_address})
+ {ok, Parsed} ->
+ assert_admins_if_remote(Parsed);
+ _ ->
+ throw({error, invalid_bind_address})
+ end.
+
+assert_admins_if_remote(Address) ->
+ case {couch_server:has_admins(), is_loopback(Address)} of
+ {false, false} ->
+ throw({error, <<"bind_address must be localhost until an admin user is created">>});
+ _ ->
+ ok
+ end.
+
+is_loopback(Address) ->
+ LoopbackIfs = loopback_ifaces(),
+ LoopbackAddresses = values(addr, LoopbackIfs),
+ lists:member(Address, LoopbackAddresses).
+
+loopback_ifaces() ->
+ {ok, IfList} = inet:getifaddrs(),
+ lists:filter(fun is_loopback_iface/1, IfList).
+
+is_loopback_iface({_Name, Options}) ->
+ case lists:keyfind(flags, 1, Options) of
+ {flags, Flags} ->
+ lists:member(loopback, Flags);
+ false ->
+ false
end.
+values(Key, TupleList) ->
+ [Value || {K, Value} <- TupleList, Key == K].
%%%%%%%% module tests below %%%%%%%%
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment