From 442a0edc90451478d560c2d185e411afbcc1181c Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Fri, 26 Oct 2018 01:47:04 +0200 Subject: util/sidparse: add cli SID utility --- util/sidparse.ml | 135 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 util/sidparse.ml (limited to 'util') diff --git a/util/sidparse.ml b/util/sidparse.ml new file mode 100644 index 0000000..e99d27f --- /dev/null +++ b/util/sidparse.ml @@ -0,0 +1,135 @@ +let err q v = + match q, v with + | true, _ -> Printf.ifprintf stdout + | _ -> Printf.eprintf +and out q v = + match q, v with + | true, _ + | _, true -> Printf.ifprintf stdout + | _ -> Printf.printf + +let header q v = + out q v "SID \ + IDAUTH \ + NSUB SUBAUTHS\n%!" + +let emit q v s = + let ss = Sid.to_string s + and ia = Sid.get_ident_auth s + and sas = Sid.get_sub_auths s in + out q v "%-30s %-15s %-4d %s\n" + ss + (Stdint.Uint64.to_string ia) + (Array.length sas) + (Array.map Stdint.Uint32.to_string sas + |> Array.to_list + |> String.concat " ") + +let handle_input q v s = + match String.trim s with + | "" -> `Nothing + | s -> + try `Done (Sid.of_string s) + with Invalid_argument e -> err q v "ERROR: %s\n%!" e; `Junk + +let from_argv sids = + let rest = ref sids in + let next () = + match !rest with + | [] -> `Done + | hd::tl -> + rest := tl; + `Sid hd + in + next + +let from_stdin () = + try `Sid (input_line stdin) + with End_of_file -> `Done + +let traverse q v next = + let rec aux n ne = + match next () with + | `Done -> if ne = 0 then Ok n else Error (n, ne) + | `Sid s -> begin + match handle_input q v s with + | `Nothing -> aux n ne + | `Junk -> aux (n + 1) (ne + 1) + | `Done s -> begin + if n = 0 then header q v; + emit q v s; + aux (n + 1) ne + end + end + in + aux 0 0 + +let sidparse validate quiet args = + let next = + match args with + | [] -> begin + if Unix.(isatty stdin) then + err quiet validate "reading input from stdin\n%!"; + from_stdin + end + | sids -> from_argv sids + in + match traverse quiet validate next with + | Ok _ -> 0 + | Error (n, ne) -> + if not quiet then + err quiet validate "processed %d items with %d errors\n" n ne; + -1 + +open Cmdliner + +let arg_validate = + let doc = "Do not print table of constituent parts, only error messages." in + Arg.(value & flag & info ["v"; "validate"] ~doc) + +let arg_quiet = + let doc = "Do not print anything at all." in + Arg.(value & flag & info ["q"; "quiet"] ~doc) + +let arg_sid = + let doc = "Inputs specified on command line as positional arguments." in + Arg.(value & (pos_all string []) & info [] ~docv:"SID" ~doc) + +let cmd_sidparse = + let exits = Term.exit_info ~doc:"errors occurred" (-1) :: Term.default_exits in + let doc = "Process Windows security identifiers." in + let man = + [ `P "This command will parse SIDs (security identifiers) \ + from the command line and standard input." + ; `P "The input is expected to consist of one SID per argument or \ + line, respectively, in “string format” (cf. [MS-DTYP] 2.4.21)." + ; `S Manpage.s_see_also + ; `P "Consult Microsoft’s documentation for more information. \ + SIDs are specified in MS-DTYP \ + (https://msdn.microsoft.com/en-us/library/cc230273.aspx) \ + with references to the Open Group RPC standard \ + (http://www.opengroup.org/dce/download/)." + ; `S Manpage.s_examples + ; `P "Parse a number of SIDs supplied on command line:" + ; `Pre "$ sidparse S-1-0 S-1-1\n\ + SID IDAUTH NSUB SUBAUTHS\n\ + S-1-0 0 0\n\ + S-1-1 1 0\n" + ; `P "Parse a number of SIDs from standard input:" + ; `Pre "$ sidparse < Term.exit_status +;; + -- cgit v1.2.3