anchor.diff:      %% single user
       add_grant([User], Bucket, Grants).
   
  -add_grant_int([], _, _) ->
  -    ok;
  -add_grant_int([User|Users], Bucket, Permissions) ->
  -    BucketPermissions = case riak_core_metadata:get({<<"security">>, <<"grants">>},
  -                                               {User, Bucket}) of
  -                            undefined ->
  -                                [];
  -                            Perms ->
  -                                Perms
  -                        end,
  -    NewPerms = lists:umerge(lists:sort(BucketPermissions),
  -                            lists:sort(Permissions)),
  -    riak_core_metadata:put({<<"security">>, <<"grants">>}, {User, Bucket},
  -                           NewPerms),
  -    add_grant_int(Users, Bucket, Permissions).
   
   add_revoke(all, Bucket, Revokes) ->
       %% all is always valid
  
positive.code: %% -------------------------------------------------------------------
  -module(riak_core_security).
  
  %% TODO
  -compile(export_all).
  
  initial_config() ->
      %[{users, [{"andrew", [{password, "foo"}]}]},
      [{users, []},
       {sources, []},
       {grants, []},
       {revokes, []},
       {epoch, os:timestamp()}
      ].
  
  get_meta() ->
      {ok, Ring} = riak_core_ring_manager:get_my_ring(),
      case riak_core_ring:get_meta(?MODULE, Ring) of
          undefined ->
              initial_config();
          {ok, Meta} ->
              Meta
      end.
  
  put_meta(Meta) ->
      riak_core_ring_manager:ring_trans(fun(Ring, M) ->
                  {new_ring, riak_core_ring:update_meta(?MODULE, M, Ring)}
          end, Meta).
  
  %% lookup a key in a list of key/value tuples. Like proplists:get_value but
  %% faster.
  lookup(Key, List, Default) ->
      case lists:keyfind(Key, 1, List) of
          false ->
              Default;
          {Key, Value} ->
              Value
      end.
  
  lookup(Key, List) ->
      lookup(Key, List, undefined).
  
  stash(Key, Value, List) ->
      lists:keystore(Key, 1, List, Value).
  
  %% @doc Get the subnet mask as an integer, stolen from an old post on
  %%      erlang-questions.
  mask_address(Addr={_, _, _, _}, Maskbits) ->
      B = list_to_binary(tuple_to_list(Addr)),
      <<Subnet:Maskbits, _Host/bitstring>> = B,
      Subnet;
  mask_address({A, B, C, D, E, F, G, H}, Maskbits) ->
      <<Subnet:Maskbits, _Host/bitstring>> = <<A:16, B:16, C:16, D:16, E:16,
                                               F:16, G:16, H:16>>,
      Subnet.
  
  %% @doc returns the real bottom of a netmask. Eg if 192.168.1.1/16 is
  %% provided, return 192.168.0.0/16
  anchor_mask(Addr={_, _, _, _}, Maskbits) ->
      M = mask_address(Addr, Maskbits),
      Rem = 32 - Maskbits,
      <<A:8, B:8, C:8, D:8>> = <<M:Maskbits, 0:Rem>>,
      {{A, B, C, D}, Maskbits};
  anchor_mask(Addr={_, _, _, _, _, _, _, _}, Maskbits) ->
      M = mask_address(Addr, Maskbits),
      Rem = 128 - Maskbits,
      <<A:16, B:16, C:16, D:16, E:16, F:16, G:16, H:16>> = <<M:Maskbits, 0:Rem>>,
      {{A, B, C, D, E, F, G, H}, Maskbits}.
  
  anchor_mask({Addr, Mask}) ->
      anchor_mask(Addr, Mask).
  
  prettyprint_cidr({Addr, Mask}) ->
      io_lib:format("~s/~B", [inet_parse:ntoa(Addr), Mask]).
  
  prettyprint_users([all]) ->
      "all";
  
negative.code:         false ->
              %% no applicable grant
              {false, io_lib:format("Permission denied: User '~s' does not have"
                                    "'~s' on ANY", [Context#context.username,
                                                   Permission]), Context}
      end;
  check_permission({Permission, Bucket}, Context0) ->
      Context = maybe_refresh_context(Context0),
      MatchG = match_grant(Bucket, Context#context.grants),
      case MatchG /= undefined andalso
           (lists:member(Permission, MatchG) orelse MatchG == 'all') of
          true ->
  