helpers.go 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. package samba
  2. import (
  3. "bytes"
  4. "fmt"
  5. "os/exec"
  6. "path/filepath"
  7. "strings"
  8. "unicode"
  9. )
  10. // convertShareConfigToString converts a ShareConfig to its string representation for smb.conf
  11. func convertShareConfigToString(share *ShareConfig) string {
  12. var builder strings.Builder
  13. builder.WriteString(fmt.Sprintf("\n[%s]\n", share.Name))
  14. builder.WriteString(fmt.Sprintf(" path = %s\n", share.Path))
  15. if len(share.ValidUsers) > 0 {
  16. builder.WriteString(fmt.Sprintf(" valid users = %s\n", strings.Join(share.ValidUsers, " ")))
  17. }
  18. builder.WriteString(fmt.Sprintf(" read only = %s\n", boolToYesNo(share.ReadOnly)))
  19. builder.WriteString(fmt.Sprintf(" browseable = %s\n", boolToYesNo(share.Browseable)))
  20. builder.WriteString(fmt.Sprintf(" guest ok = %s\n", boolToYesNo(share.GuestOk)))
  21. builder.WriteString(" create mask = 0644\n")
  22. builder.WriteString(" directory mask = 0755\n")
  23. folderOwner, err := getOwner(share.Path)
  24. if err == nil {
  25. builder.WriteString(fmt.Sprintf(" force user = %s\n", folderOwner))
  26. }
  27. return builder.String()
  28. }
  29. // Get the folder owner for samba to know which user to use for accessing the folder permission
  30. func getOwner(folderPath string) (string, error) {
  31. cmd := exec.Command("bash", "-c", fmt.Sprintf("ls -ld %s", folderPath))
  32. var out bytes.Buffer
  33. cmd.Stdout = &out
  34. err := cmd.Run()
  35. if err != nil {
  36. return "", fmt.Errorf("failed to execute command: %v", err)
  37. }
  38. output := out.String()
  39. fields := strings.Fields(output)
  40. if len(fields) < 3 {
  41. return "", fmt.Errorf("unexpected output format: %s", output)
  42. }
  43. owner := fields[2]
  44. return owner, nil
  45. }
  46. // boolToYesNo converts a boolean to "yes" or "no"
  47. func boolToYesNo(value bool) string {
  48. if value {
  49. return "yes"
  50. }
  51. return "no"
  52. }
  53. // RestartSmbd restarts the smbd service using systemctl
  54. func restartSmbd() error {
  55. cmd := exec.Command("sudo", "systemctl", "restart", "smbd")
  56. output, err := cmd.CombinedOutput()
  57. if err != nil {
  58. return fmt.Errorf("failed to restart smbd: %v - %s", err, output)
  59. }
  60. return nil
  61. }
  62. // Check if a samba username exists (unix username only)
  63. func (s *ShareManager) SambaUserExists(username string) (bool, error) {
  64. userInfos, err := s.ListSambaUsersInfo()
  65. if err != nil {
  66. return false, err
  67. }
  68. for _, userInfo := range userInfos {
  69. if userInfo.UnixUsername == username {
  70. return true, nil
  71. }
  72. }
  73. return false, nil
  74. }
  75. // List of important folders not to be shared via SMB
  76. var importantFolders = []string{
  77. "/bin",
  78. "/boot",
  79. "/dev",
  80. "/etc",
  81. "/lib",
  82. "/lib64",
  83. "/proc",
  84. "/root",
  85. "/sbin",
  86. "/sys",
  87. "/tmp",
  88. "/usr",
  89. "/var",
  90. }
  91. // IsPathInsideImportantFolders checks if the given path is inside one of the important folders
  92. func isPathInsideImportantFolders(path string) bool {
  93. // Clean the given path
  94. cleanedPath := filepath.Clean(path)
  95. // Iterate over the important folders
  96. for _, folder := range importantFolders {
  97. // Clean the important folder path
  98. cleanedFolder := filepath.Clean(folder)
  99. // Check if the cleaned path is inside the cleaned folder
  100. if strings.HasPrefix(cleanedPath, cleanedFolder) {
  101. return true
  102. }
  103. }
  104. return false
  105. }
  106. // Clean and make sure the share name is valid
  107. func sanitizeShareName(input string) string {
  108. var result strings.Builder
  109. for _, char := range input {
  110. if unicode.IsLetter(char) || unicode.IsDigit(char) {
  111. result.WriteRune(char)
  112. } else if unicode.IsSpace(char) {
  113. result.WriteRune(' ')
  114. } else if char == '_' {
  115. result.WriteRune('_')
  116. } else if char == '-' {
  117. result.WriteRune('-')
  118. }
  119. }
  120. return result.String()
  121. }
  122. // Sometime the share name in file doesnt match for sharename in smb.conf
  123. // this function load the smb.conf and get the correct case for the name of the share
  124. // return empty string if not found
  125. func (s *ShareManager) getCorrectCaseForShareName(sharename string) string {
  126. targetShare, err := s.GetShareByName(sharename)
  127. if err != nil {
  128. return ""
  129. }
  130. return targetShare.Name
  131. }