val queryAll : string -> (string * string list) list
(* What are all of a user's permissions, by class? *)
+ val whoHas : {class : string, value : string} -> string list
+ (* Which users have a permission? *)
+
val class : {user : string, class : string} -> DataStructures.StringSet.set
(* For what objects does the user have the permission? *)
(class, SS.foldr (op::) [] values) :: out)
[] classes
+fun whoHas {class, value} =
+ SM.foldri (fn (user, classes, users) =>
+ case SM.find (classes, class) of
+ NONE => users
+ | SOME values =>
+ if SS.member (values, value) then
+ user :: users
+ else
+ users) [] (!acl)
+
fun class {user, class} =
case SM.find (!acl, user) of
NONE => SS.empty
| ["revoke", user, class, value] => Main.requestRevoke {user = user, class = class, value = value}
| ["perms", user] => requestPerms user
| ["perms"] => requestPerms (Posix.SysDB.Passwd.name (Posix.SysDB.getpwuid (Posix.ProcEnv.getuid ())))
+ | ["whohas", class, value] =>
+ (case Main.requestWhoHas {class = class, value = value} of
+ NONE => ()
+ | SOME users =>
+ (print ("whohas " ^ class ^ " / " ^ value ^ ":");
+ app (fn user => print (" " ^ user)) users;
+ print "\n"))
| _ => print "Invalid command-line arguments\n"
val requestGrant : Acl.acl -> unit
val requestRevoke : Acl.acl -> unit
val requestListPerms : string -> (string * string list) list option
+ val requestWhoHas : {class : string, value : string} -> string list option
val service : unit -> unit
val slave : unit -> unit
before OpenSSL.close bio
end
+fun requestWhoHas perm =
+ let
+ val (_, bio) = requestBio (fn () => ())
+ in
+ Msg.send (bio, MsgWhoHas perm);
+ (case Msg.recv bio of
+ NONE => (print "Server closed connection unexpectedly.\n";
+ NONE)
+ | SOME m =>
+ case m of
+ MsgWhoHasResponse users => SOME users
+ | MsgError s => (print ("whohas failed: " ^ s ^ "\n");
+ NONE)
+ | _ => (print "Unexpected server reply.\n";
+ NONE))
+ before OpenSSL.close bio
+ end
+
fun service () =
let
val () = Acl.read Config.aclFile
handle OpenSSL.OpenSSL _ => ();
loop ())
+ | MsgWhoHas perm =>
+ ((Msg.send (bio, MsgWhoHasResponse (Acl.whoHas perm));
+ print ("Sent whohas response for " ^ #class perm ^ " / " ^ #value perm ^ ".\n"))
+ handle OpenSSL.OpenSSL s =>
+ (print "OpenSSL error\n";
+ Msg.send (bio,
+ MsgError
+ ("Error during whohas: "
+ ^ s)));
+ (ignore (OpenSSL.readChar bio);
+ OpenSSL.close bio)
+ handle OpenSSL.OpenSSL _ => ();
+ loop ())
+
| _ =>
(Msg.send (bio, MsgError "Unexpected command")
handle OpenSSL.OpenSSL _ => ();
OpenSSL.writeString (bio, value))) values;
OpenSSL.writeInt (bio, 0))) classes;
OpenSSL.writeInt (bio, 0))
+ | MsgWhoHas {class, value} => (OpenSSL.writeInt (bio, 10);
+ OpenSSL.writeString (bio, class);
+ OpenSSL.writeString (bio, value))
+ | MsgWhoHasResponse users => (OpenSSL.writeInt (bio, 11);
+ app (fn user =>
+ (OpenSSL.writeInt (bio, 1);
+ OpenSSL.writeString (bio, user))) users;
+ OpenSSL.writeInt (bio, 0))
fun checkIt v =
case v of
in
loop []
end
+ | 10 => (case (OpenSSL.readString bio, OpenSSL.readString bio) of
+ (SOME class, SOME value) => SOME (MsgWhoHas {class = class, value = value})
+ | _ => NONE)
+ | 11 => let
+ fun loop users =
+ case OpenSSL.readInt bio of
+ SOME 0 => SOME (MsgWhoHasResponse (rev users))
+ | SOME 1 =>
+ (case OpenSSL.readString bio of
+ SOME user => loop (user :: users)
+ | NONE => NONE)
+ | _ => NONE
+ in
+ loop []
+ end
| _ => NONE)
end
| MsgPerms of (string * string list) list
(* A response to MsgListPerms, giving a permission class and all values
* for which the user is authorized in that class *)
+ | MsgWhoHas of {class : string, value : string}
+ (* Which users have this permission? *)
+ | MsgWhoHasResponse of string list
+ (* These are the users! *)
+
end