package samba import ( "encoding/json" "log" "net/http" "path/filepath" "strings" "imuslab.com/arozos/mod/utils" ) // Get current samba service status func (s *ShareManager) SmbdStates(w http.ResponseWriter, r *http.Request) { set, err := utils.PostPara(r, "set") if err != nil { //return the current smbd states smbdRunning, err := IsSmbdRunning() if err != nil { utils.SendErrorResponse(w, err.Error()) return } js, _ := json.Marshal(smbdRunning) utils.SendJSONResponse(w, string(js)) return } else if set == "enable" { //Set smbd to enable err = SetSmbdEnableState(true) if err != nil { utils.SendErrorResponse(w, err.Error()) return } utils.SendOK(w) return } else if set == "disable" { //Set smbd to disable err = SetSmbdEnableState(false) if err != nil { utils.SendErrorResponse(w, err.Error()) return } utils.SendOK(w) return } utils.SendErrorResponse(w, "not support set state: "+set+". Only support enable /disable") } // List all the samba shares func (s *ShareManager) ListSambaShares(w http.ResponseWriter, r *http.Request) { shares, err := s.ReadSambaShares() if err != nil { utils.SendErrorResponse(w, err.Error()) return } //Remove those shares that is reserved by systems shares = s.FilterSystemCreatedShares(shares) js, _ := json.Marshal(shares) utils.SendJSONResponse(w, string(js)) } // Add a samba share func (s *ShareManager) AddSambaShare(w http.ResponseWriter, r *http.Request) { shareName, err := utils.PostPara(r, "name") if err != nil { utils.SendErrorResponse(w, "share name not given") return } shareName = strings.TrimSpace(shareName) //Check if this share name already been used shareNameExists, err := s.ShareNameExists(shareName) if err != nil { utils.SendErrorResponse(w, err.Error()) return } if shareNameExists { utils.SendErrorResponse(w, "share with identical name already exists") return } sharePath, err := utils.PostPara(r, "path") if err != nil { utils.SendErrorResponse(w, "share path not given") return } //Parse the path to absolute path absoluteSharePath, err := filepath.Abs(sharePath) if err != nil { utils.SendErrorResponse(w, err.Error()) return } //Check if path exists if !utils.FileExists(absoluteSharePath) { utils.SendErrorResponse(w, "target path not exists") return } //Check if target path is a folder if !utils.IsDir(absoluteSharePath) { utils.SendErrorResponse(w, "target path is not a directory") return } //Check if it is a reserved / protected path if isPathInsideImportantFolders(absoluteSharePath) { utils.SendErrorResponse(w, "system reserved path cannot be shared") return } validUsersJSON, err := utils.PostPara(r, "users") if err != nil { utils.SendErrorResponse(w, "no valid user givens") return } //Parse valid users into string slice validUsers := []string{} err = json.Unmarshal([]byte(validUsersJSON), &validUsers) if err != nil { utils.SendErrorResponse(w, "unable to parse JSON for valid users") return } //Check if all the users exists in the host OS for _, validUser := range validUsers { thisUnixUserExists, err := s.SambaUserExists(validUser) if err != nil { utils.SendErrorResponse(w, err.Error()) return } if !thisUnixUserExists { //This user not exists utils.SendErrorResponse(w, validUser+" is not a valid unix user") return } } readOnly, err := utils.PostBool(r, "readonly") if err != nil { readOnly = false } browseable, err := utils.PostBool(r, "browseable") if err != nil { browseable = true } allowGuest, err := utils.PostBool(r, "guestok") if err != nil { allowGuest = false } shareToCreate := ShareConfig{ Name: shareName, Path: absoluteSharePath, ValidUsers: validUsers, ReadOnly: readOnly, Browseable: browseable, GuestOk: allowGuest, } //Add the new share to smb.conf err = s.CreateNewSambaShare(&shareToCreate) if err != nil { utils.SendErrorResponse(w, err.Error()) return } //Restart smbd err = restartSmbd() if err != nil { utils.SendErrorResponse(w, err.Error()) return } utils.SendOK(w) } // Remove a samba share by name func (s *ShareManager) DelSambaShare(w http.ResponseWriter, r *http.Request) { shareName, err := utils.PostPara(r, "name") if err != nil { utils.SendErrorResponse(w, "share name not given") return } //Check if share exists shareExists, err := s.ShareExists(shareName) if err != nil { utils.SendErrorResponse(w, err.Error()) return } if !shareExists { utils.SendErrorResponse(w, "share to be remove not exists") return } //Remove the share from config file err = s.RemoveSambaShareConfig(shareName) if err != nil { utils.SendErrorResponse(w, err.Error()) return } //Restart smbd err = restartSmbd() if err != nil { utils.SendErrorResponse(w, err.Error()) return } utils.SendOK(w) } // Add a new samba user func (s *ShareManager) NewSambaUser(w http.ResponseWriter, r *http.Request) { username, err := utils.PostPara(r, "username") if err != nil { utils.SendErrorResponse(w, "username not given") return } password, err := utils.PostPara(r, "password") if err != nil { utils.SendErrorResponse(w, "password not set") return } err = s.AddSambaUser(username, password) if err != nil { utils.SendErrorResponse(w, err.Error()) return } utils.SendOK(w) } // Remove a samba user, check for admin before calling func (s *ShareManager) DelSambaUser(w http.ResponseWriter, r *http.Request) { username, err := utils.PostPara(r, "username") if err != nil { utils.SendErrorResponse(w, "username not given") return } //Remove the samba user err = s.RemoveSmbUser(username) if err != nil { utils.SendErrorResponse(w, err.Error()) return } utils.SendOK(w) } // List all samba users info func (s *ShareManager) ListSambaUsers(w http.ResponseWriter, r *http.Request) { userInfo, err := s.ListSambaUsersInfo() if err != nil { utils.SendErrorResponse(w, err.Error()) return } js, _ := json.Marshal(userInfo) utils.SendJSONResponse(w, string(js)) } // Activate a user account from arozos into samba user func (s *ShareManager) ActivateUserAccount(w http.ResponseWriter, r *http.Request, username string, password string) { //Register this user to samba if not exists sambaUserExists, err := s.SambaUserExists(username) if err != nil { utils.SendErrorResponse(w, err.Error()) return } userInfo, _ := s.UserHandler.GetUserInfoFromRequest(w, r) if !sambaUserExists { //This user account not activated yet. Activate it err = s.AddSambaUser(userInfo.Username, password) if err != nil { utils.SendErrorResponse(w, err.Error()) return } } //Create the user root share folders for _, fsh := range userInfo.GetAllAccessibleFileSystemHandler() { if fsh.IsLocalDrive() { //Samba can only work with drives locally hosted on this server fshID := fsh.UUID fshSharePath := fsh.Path if fsh.RequierUserIsolation() { //User seperated storage. Only mount the user one fshID = fsh.UUID + "_" + userInfo.Username fshSharePath = filepath.Join(fsh.Path, "/users/", userInfo.Username+"/") } fshID = sanitizeShareName(fshID) //Check if the share already exists shareExists, err := s.ShareExists(fshID) if err != nil { continue } if !shareExists { //Try to create the share fshShareAbsolutePath, err := filepath.Abs(fshSharePath) if err != nil { log.Println("[Samba] Unable to generate share config for path: " + fshSharePath) continue } //Check if that folder exists if utils.FileExists(fshShareAbsolutePath) { //Folder not exists. Continue log.Println("[Samba] Path not exists for file system handler: " + fshSharePath) continue } //Ok! Create the share with this username err = s.CreateNewSambaShare(&ShareConfig{ Name: fshID, Path: fshShareAbsolutePath, ValidUsers: []string{userInfo.Username}, ReadOnly: false, Browseable: true, GuestOk: false, }) if err != nil { log.Println("[Samba] Failed to create share: " + err.Error()) utils.SendErrorResponse(w, err.Error()) return } } else { //Share exists. Add this user to such share err = s.AddUserToSambaShare(fshID, userInfo.Username) if err != nil { log.Println("[Samba] Failed to add user " + userInfo.Username + " to share " + fshID + ": " + err.Error()) utils.SendErrorResponse(w, err.Error()) return } } } } utils.SendOK(w) }