func (s *Server) users() string { logger.Info("Getting users.") users, err := s.Provider.Users() if err != nil { return marshalError(err) } var buf bytes.Buffer buf.WriteString("200") for _, u := range users { buf.WriteString("\n") buf.WriteString(marshalUser(u)) } logger.Info("Request succeeded.") return buf.String() }
func (s *Server) groups() string { logger.Info("Getting groups.") groups, err := s.Provider.Groups() if err != nil { return marshalError(err) } var buf bytes.Buffer buf.WriteString("200") for _, g := range groups { buf.WriteString("\n") buf.WriteString(marshalGroup(g)) } logger.Info("Request succeeded.") return buf.String() }
func (s *Server) names() string { logger.Info("Getting names.") names, err := s.Provider.Names() if err != nil { return marshalError(err) } var buf bytes.Buffer buf.WriteString("200") for _, n := range names { buf.WriteString("\n") buf.WriteString(n) } logger.Info("Request succeeded.") return buf.String() }
func main() { flag.Parse() logger.Info("Starting daemon.") interrupt := make(chan os.Signal, 1) signal.Notify(interrupt, os.Interrupt, os.Kill, syscall.SIGTERM) api, err := apiclient.New(&apiclient.Config{ APIBase: *apiBase, InstanceBase: *instanceBase, UserAgent: userAgent, Timeout: apiTimeout, }) if err != nil { logger.Fatalf("Init failed: %v.", err) } srv := &server.Server{store.New(api, &store.Config{ AccountRefreshFrequency: accountRefreshFrequency, AccountRefreshCooldown: accountRefreshCooldown, KeyRefreshFrequency: keyRefreshFrequency, KeyRefreshCooldown: keyRefreshCooldown, })} go func() { err := srv.Serve() logger.Fatalf("Server failed: %v.", err) }() for { select { case sig := <-interrupt: logger.Fatalf("Got interrupt: %v.", sig) } } }
func (s *Server) isName(args []string) string { name, err := parseName(args) if err != nil { logger.Errorf("Invalid name: %v.", err) return "400" } logger.Infof("Checking name: %v.", name) is, err := s.Provider.IsName(name) if err != nil { return marshalError(err) } else if is { logger.Info("Valid name.") return "200" } else { logger.Info("Invalid name.") return "404" } }
// GroupByName satisfies AccountProvider. func (s *cachingStore) GroupByName(name string) (*accounts.Group, error) { s.RLock() defer s.RUnlock() g, ok := s.groupsByName[name] if ok { return g, nil } ch := make(chan struct{}) logger.Info("Triggering refresh due to missing group.") go func() { s.updateWaiters <- ch }() // Do not block on update. return nil, accounts.GroupNameNotFound(name) }
func (s *Server) userByName(args []string) string { name, err := parseName(args) if err != nil { logger.Errorf("Invalid name for user: %v.", err) return "400" } logger.Infof("Getting user by name: %v.", name) user, err := s.Provider.UserByName(name) if err != nil { return marshalError(err) } logger.Info("Request succeeded.") return fmt.Sprintf("200\n%v", marshalUser(user)) }
func (s *Server) groupByGID(args []string) string { gid, err := parseID(args) if err != nil { logger.Errorf("Invalid GID for group: %v.", err) return "400" } logger.Infof("Getting group by GID: %v.", gid) group, err := s.Provider.GroupByGID(gid) if err != nil { return marshalError(err) } logger.Info("Request succeeded.") return fmt.Sprintf("200\n%v", marshalGroup(group)) }
func (s *Server) groupByName(args []string) string { name, err := parseName(args) if err != nil { logger.Errorf("Invalid name for group: %v.", err) return "400" } logger.Infof("Getting group by name: %v.", name) group, err := s.Provider.GroupByName(name) if err != nil { return marshalError(err) } logger.Info("Request succeeded.") return fmt.Sprintf("200\n%v", marshalGroup(group)) }
func (s *Server) userByUID(args []string) string { uid, err := parseID(args) if err != nil { logger.Errorf("Invalid UID for user: %v.", err) return "400" } logger.Infof("Getting user by UID: %v.", uid) user, err := s.Provider.UserByUID(uid) if err != nil { return marshalError(err) } logger.Info("Request succeeded.") return fmt.Sprintf("200\n%v", marshalUser(user)) }
// GroupByName satisfies AccountProvider. func (s *cachingStore) GroupByName(name string) (*accounts.Group, error) { s.RLock() defer s.RUnlock() if name == sudoersGroupName { return s.sudoersGroup(), nil } g, ok := s.groupsByName[name] if ok { return g, nil } logger.Info("Triggering refresh due to missing group.") // Do not block on update. go func() { s.updateWaiters <- nil }() return nil, accounts.GroupNameNotFound(name) }
// UsersAndGroups satisfies APIClient. func (c *googleAPIClient) UsersAndGroups() ([]*cua.LinuxUserView, []*cua.LinuxGroupView, error) { logger.Info("Fetching users and groups.") p, z, i, err := c.instanceInfo() if err != nil { return nil, nil, err } view, err := c.service.Linux.GetLinuxAccountViews(p, z, i).Do() if err != nil { return nil, nil, err } else if view.Resource == nil { // No users or groups. return nil, nil, nil } else { return view.Resource.UserViews, view.Resource.GroupViews, nil } }
func (s *Server) handle(conn net.Conn) { defer conn.Close() deadline := time.Now().Add(serverTimeout) conn.SetReadDeadline(deadline) data := make([]byte, maxRequestSize) n, err := conn.Read(data) if err != nil { logger.Errorf("Failed to read request: %v.", err) return } resp := s.respond(string(data[:n])) deadline = time.Now().Add(serverTimeout) conn.SetWriteDeadline(deadline) _, err = conn.Write([]byte(resp)) if err != nil { logger.Errorf("Failed to write response: %v.", err) } logger.Info("Request completed.") }
func updateTask(s *cachingStore) { var lastRefresh time.Time for { var ch chan struct{} select { case ch = <-s.updateWaiters: case <-timeAfter(s.config.AccountRefreshFrequency): } if nowOutsideTimespan(lastRefresh, s.config.AccountRefreshCooldown) { logger.Info("Refreshing users and groups.") updateAccounts(s) lastRefresh = timeNow() } go updateKeys(s) if ch != nil { close(ch) } } }
func updateAccounts(s *cachingStore) { users, groups, err := s.apiClient.UsersAndGroups() if err != nil { logger.Errorf("Failed refresh: %v.", err) return } s.Lock() defer s.Unlock() oldUsers := s.usersByName s.usersByName = make(map[string]*cachedUser) s.usersByUID = make(map[uint32]*cachedUser) s.groupsByName = make(map[string]*accounts.Group) s.groupsByGID = make(map[uint32]*accounts.Group) for _, u := range users { user := &accounts.User{ Name: u.Username, UID: uint32(u.Uid), GID: uint32(u.Gid), Gecos: u.Gecos, HomeDirectory: u.HomeDirectory, Shell: u.Shell, } cu := &cachedUser{user: user} if old, ok := oldUsers[user.Name]; ok { cu.keyRefreshTime = old.keyRefreshTime cu.keys = old.keys cu.sudoer = old.sudoer } s.usersByName[user.Name] = cu s.usersByUID[user.UID] = cu } for _, g := range groups { group := &accounts.Group{ Name: g.GroupName, GID: uint32(g.Gid), Members: g.Members, } s.groupsByName[group.Name] = group s.groupsByGID[group.GID] = group } logger.Info("Refreshing users and groups succeeded.") }
// Serve begins serving accounts information through a socket forever. func (s *Server) Serve() error { os.Remove(socketPath) sock, err := net.ListenUnix("unix", &net.UnixAddr{socketPath, "unix"}) if err != nil { return err } // Make the socket readable and writeable by all. os.Chmod(socketPath, os.ModePerm) listeningCallback() logger.Infof("Listening for connections at %v.", socketPath) for { conn, err := sock.Accept() if err != nil { logger.Errorf("Failed to accept connection: %v.", err) continue } logger.Info("Accepted connection.") go s.handle(conn) } }
func (s *Server) authorizedKeys(args []string) string { username, err := parseName(args) if err != nil { logger.Errorf("Invalid username for keys: %v.", err) return "400" } logger.Infof("Getting keys for user: %v.", username) keys, err := s.Provider.AuthorizedKeys(username) if err != nil { return marshalError(err) } var buf bytes.Buffer buf.WriteString("200") for _, k := range keys { buf.WriteString("\n") buf.WriteString(k) } logger.Info("Request succeeded.") return buf.String() }