Permission revocation
[hcoop/domtool2.git] / src / main.sml
index a3b78e8..9204159 100644 (file)
@@ -58,17 +58,13 @@ fun basis () =
        if !ErrorMsg.anyErrors then
            Env.empty
        else
-           foldl (fn (fname, G) => check' G fname) Env.empty files
+           (Tycheck.allowExterns ();
+            foldl (fn (fname, G) => check' G fname) Env.empty files
+            before Tycheck.disallowExterns ())
     end
 
 fun check fname =
     let
-       val uid = Posix.ProcEnv.getuid ()
-       val user = Posix.SysDB.Passwd.name (Posix.SysDB.getpwuid uid)
-
-       val () = Acl.read Config.aclFile
-       val () = Domain.setUser user
-
        val _ = ErrorMsg.reset ()
        val _ = Env.preTycheck ()
 
@@ -78,6 +74,7 @@ fun check fname =
            raise ErrorMsg.Error
        else
            let
+               val _ = Tycheck.disallowExterns ()
                val _ = ErrorMsg.reset ()
                val prog = Parse.parse fname
            in
@@ -128,27 +125,33 @@ fun eval fname =
 val dispatcher =
     Config.dispatcher ^ ":" ^ Int.toString Config.dispatcherPort
 
-fun hostname () =
-    let
-       val inf = TextIO.openIn "/etc/hostname"
-    in
-       case TextIO.inputLine inf of
-           NONE => (TextIO.closeIn inf; raise Fail "No line in /etc/hostname")
-         | SOME line => (TextIO.closeIn inf; String.substring (line, 0, size line - 1))
-    end
-
-fun request fname =
+fun requestContext f =
     let
-       val _ = check fname
-
        val uid = Posix.ProcEnv.getuid ()
        val user = Posix.SysDB.Passwd.name (Posix.SysDB.getpwuid uid)
+                  
+       val () = Acl.read Config.aclFile
+       val () = Domain.setUser user
+                
+       val () = f ()
 
        val context = OpenSSL.context (Config.certDir ^ "/" ^ user ^ ".pem",
                                       Config.keyDir ^ "/" ^ user ^ "/key.pem",
                                       Config.trustStore)
+    in
+       (user, context)
+    end
 
-       val bio = OpenSSL.connect (context, dispatcher)
+fun requestBio f =
+    let
+       val (user, context) = requestContext f
+    in
+       (user, OpenSSL.connect (context, dispatcher))
+    end
+
+fun request fname =
+    let
+       val (user, bio) = requestBio (fn () => ignore (check fname))
 
        val inf = TextIO.openIn fname
 
@@ -172,6 +175,36 @@ fun request fname =
     end
     handle ErrorMsg.Error => ()
 
+fun requestGrant acl =
+    let
+       val (user, bio) = requestBio (fn () => ())
+    in
+       Msg.send (bio, MsgGrant acl);
+       case Msg.recv bio of
+           NONE => print "Server closed connection unexpectedly.\n"
+         | SOME m =>
+           case m of
+               MsgOk => print "Grant succeeded.\n"
+             | MsgError s => print ("Grant failed: " ^ s ^ "\n")
+             | _ => print "Unexpected server reply.\n";
+       OpenSSL.close bio
+    end
+
+fun requestRevoke acl =
+    let
+       val (user, bio) = requestBio (fn () => ())
+    in
+       Msg.send (bio, MsgRevoke acl);
+       case Msg.recv bio of
+           NONE => print "Server closed connection unexpectedly.\n"
+         | SOME m =>
+           case m of
+               MsgOk => print "Revoke succeeded.\n"
+             | MsgError s => print ("Revoke failed: " ^ s ^ "\n")
+             | _ => print "Unexpected server reply.\n";
+       OpenSSL.close bio
+    end
+
 fun service () =
     let
        val () = Acl.read Config.aclFile
@@ -212,22 +245,71 @@ fun service () =
                                    TextIO.closeOut outf;
                                    (eval outname;
                                     Msg.send (bio, MsgOk))
-                                    handle ErrorMsg.Error =>
-                                           (print "Compilation error\n";
+                                   handle ErrorMsg.Error =>
+                                          (print "Compilation error\n";
+                                           Msg.send (bio,
+                                                     MsgError "Error during configuration evaluation"))
+                                        | OpenSSL.OpenSSL s =>
+                                          (print "OpenSSL error\n";
+                                           Msg.send (bio,
+                                                     MsgError
+                                                         ("Error during configuration evaluation: "
+                                                          ^ s)));
+                                   OS.FileSys.remove outname;
+                                   (ignore (OpenSSL.readChar bio);
+                                    OpenSSL.close bio)
+                                   handle OpenSSL.OpenSSL _ => ();
+                                   loop ()
+                               end
+
+                             | MsgGrant acl =>
+                               if Acl.query {user = user, class = "group", value = "root"} then
+                                   ((Acl.grant acl;
+                                     Acl.write Config.aclFile;
+                                     Msg.send (bio, MsgOk);
+                                     print ("Granted permission " ^ #value acl ^ " to " ^ #user acl ^ " in " ^ #class acl ^ ".\n"))
+                                    handle OpenSSL.OpenSSL s =>
+                                           (print "OpenSSL error\n";
                                             Msg.send (bio,
-                                                      MsgError "Error during configuration evaluation"))
-                                         | OpenSSL.OpenSSL s =>
+                                                      MsgError
+                                                          ("Error during granting: "
+                                                           ^ s)));
+                                   (ignore (OpenSSL.readChar bio);
+                                    OpenSSL.close bio)
+                                   handle OpenSSL.OpenSSL _ => ();
+                                   loop ())
+                               else
+                                   ((Msg.send (bio, MsgError "Not authorized to grant privileges");
+                                     print "Unauthorized user asked to grant a permission!\n";
+                                     ignore (OpenSSL.readChar bio);
+                                     OpenSSL.close bio)
+                                    handle OpenSSL.OpenSSL _ => ();
+                                    loop ())
+
+                             | MsgRevoke acl =>
+                               if Acl.query {user = user, class = "group", value = "root"} then
+                                   ((Acl.revoke acl;
+                                     Acl.write Config.aclFile;
+                                     Msg.send (bio, MsgOk);
+                                     print ("Revoked permission " ^ #value acl ^ " from " ^ #user acl ^ " in " ^ #class acl ^ ".\n"))
+                                    handle OpenSSL.OpenSSL s =>
                                            (print "OpenSSL error\n";
                                             Msg.send (bio,
                                                       MsgError
-                                                          ("Error during configuration evaluation: "
+                                                          ("Error during revocation: "
                                                            ^ s)));
-                                   OS.FileSys.remove outname;
                                    (ignore (OpenSSL.readChar bio);
                                     OpenSSL.close bio)
                                    handle OpenSSL.OpenSSL _ => ();
-                                   loop ()
-                               end
+                                   loop ())
+                               else
+                                   ((Msg.send (bio, MsgError "Not authorized to revoke privileges");
+                                     print "Unauthorized user asked to revoke a permission!\n";
+                                     ignore (OpenSSL.readChar bio);
+                                     OpenSSL.close bio)
+                                    handle OpenSSL.OpenSSL _ => ();
+                                    loop ())
+
                              | _ =>
                                (Msg.send (bio, MsgError "Unexpected command")
                                 handle OpenSSL.OpenSSL _ => ();
@@ -237,6 +319,16 @@ fun service () =
                in
                    cmdLoop ()
                end
+                   handle OpenSSL.OpenSSL s =>
+                          (print ("OpenSSL error: " ^ s ^ "\n");
+                           OpenSSL.close bio
+                           handle OpenSSL.OpenSSL _ => ();
+                           loop ())
+                        | OS.SysErr (s, _) =>
+                          (print ("System error: " ^ s ^ "\n");
+                           OpenSSL.close bio
+                           handle OpenSSL.OpenSSL _ => ();
+                           loop ())
     in
        print "Listening for connections....\n";
        loop ();
@@ -245,7 +337,7 @@ fun service () =
 
 fun slave () =
     let
-       val host = hostname ()
+       val host = Slave.hostname ()
 
        val context = OpenSSL.context (Config.certDir ^ "/" ^ host ^ ".pem",
                                       Config.keyDir ^ "/" ^ host ^ "/key.pem",
@@ -287,6 +379,11 @@ fun slave () =
                            OpenSSL.close bio
                                          handle OpenSSL.OpenSSL _ => ();
                            loop ())
+                        | OS.SysErr (s, _) =>
+                          (print ("System error: "^ s ^ "\n");
+                           OpenSSL.close bio
+                           handle OpenSSL.OpenSSL _ => ();
+                           loop ())
     in
        loop ();
        OpenSSL.shutdown sock