#!/bin/env ruby

require 'socket'
hostname = Socket.gethostname

require 'pp'

# TODO handle #<uid>
def sudo_parse(files)
  newfiles = Array.new
  File.open(file).each_line do |line|
    line.chomp!
    # Handle include files and directories
    if line =~ /^[\t ]*#(include(?:dir)?)[\t ]+([a-zA-Z0-9_.%-]+)/
      type = $1
      node = $2
      node.gsub(/%h/, hostname)   # include file param may include hostname substitution
      if !File.exists?(node)
        next
      elsif type == 'include' and File.file?(node)
        newfiles.push(node)
      elsif type == 'includedir' and File.directory?(node)
        newfiles.push(*Dir.entries(node))
      end
    # Skip comments and blank lines
    elsif line =~ /^[\t ]*(#|$)/
      next
    # Handle Defaults
    elsif line =~ /^[\t ]*Defaults(@|[\t ]*)([^\t ]+)/
      puts "Defaults IFS [#{$1}] str [#{$2}]"
    # Handle aliases
    elsif line =~ /^[\t ]*(User|Runas|Host|Cmnd)_Alias[\t ](.+)$/
      puts "type [$1] string [$2]"
    # Handle definition lines
    elsif cap = (line.match(/^\ *
      (?<type>%)?                             # "%" indicates a group
      (?<name>[a-zA-Z][a-zA-Z0-9_.-]*)        # user or group name
      [\t\ ]+
      (?<host>[a-zA-Z0-9_.-]+)                # hostname
      [\t\ ]*=[\t\ ]*                         # "="
      (?:                                     # alternate user/group is optional
        \([\t\ ]*                             # start runas list
        (?<runas>[a-zA-Z0-9_.,\ -]+)          # runas users - will need to split on ","
        (?::                                  # possibly with groups
          (?<runas_group>[a-zA-Z0-9_.,\ -]+)  # runas groups - will need to split on ","
        )?
        [\t\ ]*\)                             # end runas list
      )?
      [\t\ ]*
      (?<tags>[A-Z:]+:)?                      # optional settings - will need to split on ':' and ends with ':'
      [\t\ ]*
      (?<command>[a-zA-Z0-9_.,\/\ -]+)        # list of commands - split on ","
    /x))
      puts "* #{cap['name']} command [#{cap['command']}]"
      pp cap
    end
  end
  return newfiles
end

sourced = sudo_parse('/etc/sudoers')

loop do
  if !sourced.length?
    break
  end
  new_files = Array.new
  sourced.each do |file|
    tmp_list = sudo_parse(file)
    if tmp_list.length?
      new_files.push(*tmp_list)
    end
  end
  sourced = new_files
end

