package main import ( "encoding/json" "fmt" "host_service/utils" "io" "log" "net" "os" "os/exec" "strings" ) const SOCKET_PATH = "/var/run/usermgmt.sock" type Command struct { Action string `json:"action"` Params map[string]interface{} `json:"params"` } type Response struct { Success bool `json:"success"` Data interface{} `json:"data"` Error string `json:"error,omitempty"` } func main() { // Ensure socket file does not exist if err := exec.Command("rm", "-f", SOCKET_PATH).Run(); err != nil { log.Fatal(err) } listener, err := net.Listen("unix", SOCKET_PATH) if err != nil { log.Fatal(err) } defer listener.Close() // Change socket permissions to allow Docker container access if err := exec.Command("chmod", "777", SOCKET_PATH).Run(); err != nil { log.Fatal(err) } log.Printf("Listening on %s", SOCKET_PATH) for { conn, err := listener.Accept() if err != nil { log.Printf("Accept error: %v", err) continue } go handleConnection(conn) } } func execCommand(name string, args ...string) error { cmd := exec.Command(name, args...) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr return cmd.Run() } func checkGroupExists(group string) bool { err := exec.Command("getent", "group", group).Run() return err == nil } func handleConnection(conn net.Conn) { defer conn.Close() decoder := json.NewDecoder(conn) encoder := json.NewEncoder(conn) var cmd Command if err := decoder.Decode(&cmd); err != nil { encoder.Encode(Response{Success: false, Error: err.Error()}) return } var result Response switch cmd.Action { case "get_users": output, err := exec.Command("bash", "-c", "getent passwd | awk -F: '$3 >= 1000 && $7 !~ /(false)/ {print $0}'").CombinedOutput() if err != nil { result = Response{Success: false, Error: err.Error()} } else { result = Response{Success: true, Data: string(output)} } case "create_user": username := cmd.Params["username"].(string) password := cmd.Params["password"].(string) group := cmd.Params["group"].(string) shell := cmd.Params["shell"].(string) isAdmin := cmd.Params["is_admin"].(bool) err := createUser(username, password, group, shell, isAdmin) if err != nil { result = Response{Success: false, Error: err.Error()} } else { result = Response{Success: true} } case "modify_user_passwd": username := cmd.Params["username"].(string) password := cmd.Params["password"].(string) result = modifyUserPassword(username, password) case "delete_user": username := cmd.Params["username"].(string) output, err := exec.Command("sudo", "deluser", username).CombinedOutput() if err != nil { result = Response{Success: false, Data: fmt.Sprintf("error delete user: %s", err)} } else { result = Response{Success: true, Data: string(output)} } case "get_samba_status": output, err := exec.Command("smbstatus", "-f").CombinedOutput() if err != nil { result = Response{Success: false, Error: err.Error()} } else { result = Response{Success: true, Data: string(output)} } case "get_groups": output, err := exec.Command("bash", "-c", "getent group | awk -F: '$3 >= 1000 {print $1}'").CombinedOutput() if err != nil { result = Response{Success: false, Error: err.Error()} } else { result = Response{Success: true, Data: strings.TrimSpace(string(output))} } case "get_user_groups": username := cmd.Params["username"].(string) // Get all groups for the user groupOutput, err := exec.Command("groups", username).CombinedOutput() if err != nil { result = Response{Success: false, Error: err.Error()} break } // Get group details with GIDs allGroupsOutput, err := exec.Command("bash", "-c", "getent group | awk -F: '$3 >= 1000 {print $1}'").CombinedOutput() if err != nil { result = Response{Success: false, Error: err.Error()} break } // Extract user groups and filter against user-created groups userGroups := strings.Fields(string(groupOutput))[2:] userCreatedGroups := strings.Split(strings.TrimSpace(string(allGroupsOutput)), "\n") // Filter user groups to include only those in user-created groups var filteredGroups []string for _, group := range userGroups { for _, userGroup := range userCreatedGroups { if group == userGroup { filteredGroups = append(filteredGroups, group) break } } } result = Response{Success: true, Data: filteredGroups} case "add_user_to_group": username := cmd.Params["username"].(string) group := cmd.Params["group"].(string) err := addUserToGroup(username, group) if err != nil { result = Response{Success: false, Error: err.Error()} } else { result = Response{Success: true} } case "remove_user_from_group": username := cmd.Params["username"].(string) group := cmd.Params["group"].(string) err := removeUserFromGroup(username, group) if err != nil { result = Response{Success: false, Error: err.Error()} } else { result = Response{Success: true} } case "get_samba_settings": result = getSambaSettings() case "update_section_setting": jsonConfig, ok := cmd.Params["config"].(string) if !ok { result = Response{Success: false, Error: "Invalid or missing config parameter"} break } result = updateSectionSetting(jsonConfig) case "get_samba_service_info": result = getSambaServiceInfo() case "restart_samba_service": result = restartSambaService() } encoder.Encode(result) } func modifyUserPassword(username string, password string) Response { cmd := exec.Command("sudo", "chpasswd") cmd.Stdin = strings.NewReader(fmt.Sprintf("%s:%s", username, password)) cmd = exec.Command("sudo", "smbpasswd", "-a", username) // Create a pipe to handle multiple password inputs r, w := io.Pipe() cmd.Stdin = r // Write passwords to pipe go func() { defer w.Close() w.Write([]byte(fmt.Sprintf("%s\n%s\n", password, password))) }() if err := cmd.Run(); err != nil { return Response{Success: false, Data: fmt.Sprintf("error changing password: %s", err)} } if err := cmd.Run(); err != nil { return Response{Success: false, Data: fmt.Sprintf("error changing password: %s", err)} } return Response{Success: true, Data: "Change password success"} } func createUser(username, password, group string, shell string, isAdmin bool) error { if group == "" { group = "sambashare" } if err := execCommand("sudo", "useradd", "-M", "-s", shell, "-g", group, username); err != nil { return fmt.Errorf("error creating user: %w", err) } cmd := exec.Command("sudo", "chpasswd") cmd.Stdin = strings.NewReader(fmt.Sprintf("%s:%s", username, password)) if err := cmd.Run(); err != nil { return fmt.Errorf("error setting user password: %w", err) } if checkGroupExists(group) { if err := execCommand("sudo", "usermod", "-aG", group, username); err != nil { return fmt.Errorf("error adding user to group: %w", err) } } else { fmt.Printf("Warning: Group '%s' does not exist.\n", group) } if err := execCommand("sudo", "usermod", "-L", username); err != nil { return fmt.Errorf("error locking user account: %w", err) } if err := execCommand("sudo", "usermod", "-s", shell, username); err != nil { return fmt.Errorf("error setting shell: %w", err) } // Add user to Samba smbCmd := exec.Command("sudo", "smbpasswd", "-a", username) smbCmd.Stdin = strings.NewReader(fmt.Sprintf("%s\n%s\n", password, password)) if err := smbCmd.Run(); err != nil { return fmt.Errorf("error adding user to Samba: %w", err) } fmt.Printf("User '%s' created successfully and configured for Samba access.\n", username) return nil } func addUserToGroup(username, group string) error { // Use gpasswd to add the user to the group cmd := exec.Command("sudo", "gpasswd", "-a", username, group) if err := cmd.Run(); err != nil { return fmt.Errorf("error adding user to group: %w", err) } fmt.Printf("User '%s' added to group '%s'.\n", username, group) return nil } func removeUserFromGroup(username, group string) error { // Use gpasswd to remove the user from the group cmd := exec.Command("sudo", "gpasswd", "-d", username, group) if err := cmd.Run(); err != nil { return fmt.Errorf("error removing user from group: %w", err) } fmt.Printf("User '%s' removed from group '%s'.\n", username, group) return nil } func getSambaSettings() Response { config, err := utils.NewSambaConfig("/etc/samba/smb.conf") if err != nil { return Response{Success: false, Error: fmt.Sprintf("Error creating config: %v", err)} } if err := config.LoadConfig(); err != nil { return Response{Success: false, Error: fmt.Sprintf("Error loading config: %v", err)} } jsonData, err := json.Marshal(config) if err != nil { return Response{Success: false, Error: fmt.Sprintf("Error converting to JSON: %v", err)} } return Response{Success: true, Data: string(jsonData)} } func updateSectionSetting(jsonConfig string) Response { config, err := utils.NewSambaConfig("/etc/samba/smb.conf") if err != nil { return Response{Success: false, Error: fmt.Sprintf("Error creating config: %v", err)} } if err := config.SaveConfig(jsonConfig); err != nil { return Response{Success: false, Error: fmt.Sprintf("Error saving config: %v", err)} } return Response{Success: true, Data: "Configuration updated successfully"} } func getSambaServiceInfo() Response { // service smbd restart output, err := exec.Command("sudo", "smbstatus", "-j").CombinedOutput() if err != nil { return Response{Success: false, Data: fmt.Errorf("error to get samba status infomation: %w", err)} } fmt.Println("Success getting smb status") return Response{Success: true, Data: string(output)} } func restartSambaService() Response { // service smbd restart cmd := exec.Command("sudo", "service", "smbd", "restart") if err := cmd.Run(); err != nil { return Response{Success: false, Data: fmt.Errorf("error to restart smbd service: %w", err)} } fmt.Println("Success restart samba service") return Response{Success: true, Data: "Success restart samba service"} }