install.go 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. package cwhub
  2. import (
  3. "fmt"
  4. "os"
  5. "path/filepath"
  6. log "github.com/sirupsen/logrus"
  7. "github.com/crowdsecurity/crowdsec/pkg/csconfig"
  8. )
  9. func purgeItem(hub *csconfig.HubCfg, target Item) (Item, error) {
  10. itempath := hub.HubDir + "/" + target.RemotePath
  11. // disable hub file
  12. if err := os.Remove(itempath); err != nil {
  13. return target, fmt.Errorf("while removing file: %w", err)
  14. }
  15. target.Downloaded = false
  16. log.Infof("Removed source file [%s]: %s", target.Name, itempath)
  17. hubIdx.Items[target.Type][target.Name] = target
  18. return target, nil
  19. }
  20. // DisableItem to disable an item managed by the hub, removes the symlink if purge is true
  21. func DisableItem(hub *csconfig.HubCfg, target *Item, purge bool, force bool) error {
  22. var err error
  23. // already disabled, noop unless purge
  24. if !target.Installed {
  25. if purge {
  26. *target, err = purgeItem(hub, *target)
  27. if err != nil {
  28. return err
  29. }
  30. }
  31. return nil
  32. }
  33. if target.Local {
  34. return fmt.Errorf("%s isn't managed by hub. Please delete manually", target.Name)
  35. }
  36. if target.Tainted && !force {
  37. return fmt.Errorf("%s is tainted, use '--force' to overwrite", target.Name)
  38. }
  39. // for a COLLECTIONS, disable sub-items
  40. if target.Type == COLLECTIONS {
  41. for idx, ptr := range [][]string{target.Parsers, target.PostOverflows, target.Scenarios, target.Collections} {
  42. ptrtype := ItemTypes[idx]
  43. for _, p := range ptr {
  44. if val, ok := hubIdx.Items[ptrtype][p]; ok {
  45. // check if the item doesn't belong to another collection before removing it
  46. toRemove := true
  47. for _, collection := range val.BelongsToCollections {
  48. if collection != target.Name {
  49. toRemove = false
  50. break
  51. }
  52. }
  53. if toRemove {
  54. err = DisableItem(hub, &val, purge, force)
  55. if err != nil {
  56. return fmt.Errorf("while disabling %s: %w", p, err)
  57. }
  58. } else {
  59. log.Infof("%s was not removed because it belongs to another collection", val.Name)
  60. }
  61. } else {
  62. log.Errorf("Referred %s %s in collection %s doesn't exist.", ptrtype, p, target.Name)
  63. }
  64. }
  65. }
  66. }
  67. syml, err := filepath.Abs(hub.InstallDir + "/" + target.Type + "/" + target.Stage + "/" + target.FileName)
  68. if err != nil {
  69. return err
  70. }
  71. stat, err := os.Lstat(syml)
  72. if os.IsNotExist(err) {
  73. // we only accept to "delete" non existing items if it's a forced purge
  74. if !purge && !force {
  75. return fmt.Errorf("can't delete %s : %s doesn't exist", target.Name, syml)
  76. }
  77. } else {
  78. // if it's managed by hub, it's a symlink to csconfig.GConfig.hub.HubDir / ...
  79. if stat.Mode()&os.ModeSymlink == 0 {
  80. log.Warningf("%s (%s) isn't a symlink, can't disable", target.Name, syml)
  81. return fmt.Errorf("%s isn't managed by hub", target.Name)
  82. }
  83. hubpath, err := os.Readlink(syml)
  84. if err != nil {
  85. return fmt.Errorf("while reading symlink: %w", err)
  86. }
  87. absPath, err := filepath.Abs(hub.HubDir + "/" + target.RemotePath)
  88. if err != nil {
  89. return fmt.Errorf("while abs path: %w", err)
  90. }
  91. if hubpath != absPath {
  92. log.Warningf("%s (%s) isn't a symlink to %s", target.Name, syml, absPath)
  93. return fmt.Errorf("%s isn't managed by hub", target.Name)
  94. }
  95. // remove the symlink
  96. if err = os.Remove(syml); err != nil {
  97. return fmt.Errorf("while removing symlink: %w", err)
  98. }
  99. log.Infof("Removed symlink [%s] : %s", target.Name, syml)
  100. }
  101. target.Installed = false
  102. if purge {
  103. *target, err = purgeItem(hub, *target)
  104. if err != nil {
  105. return err
  106. }
  107. }
  108. hubIdx.Items[target.Type][target.Name] = *target
  109. return nil
  110. }
  111. // creates symlink between actual config file at hub.HubDir and hub.ConfigDir
  112. // Handles collections recursively
  113. func EnableItem(hub *csconfig.HubCfg, target *Item) error {
  114. var err error
  115. parentDir := filepath.Clean(hub.InstallDir + "/" + target.Type + "/" + target.Stage + "/")
  116. // create directories if needed
  117. if target.Installed {
  118. if target.Tainted {
  119. return fmt.Errorf("%s is tainted, won't enable unless --force", target.Name)
  120. }
  121. if target.Local {
  122. return fmt.Errorf("%s is local, won't enable", target.Name)
  123. }
  124. // if it's a collection, check sub-items even if the collection file itself is up-to-date
  125. if target.UpToDate && target.Type != COLLECTIONS {
  126. log.Tracef("%s is installed and up-to-date, skip.", target.Name)
  127. return nil
  128. }
  129. }
  130. if _, err = os.Stat(parentDir); os.IsNotExist(err) {
  131. log.Infof("%s doesn't exist, create", parentDir)
  132. if err = os.MkdirAll(parentDir, os.ModePerm); err != nil {
  133. return fmt.Errorf("while creating directory: %w", err)
  134. }
  135. }
  136. // install sub-items if it's a collection
  137. if target.Type == COLLECTIONS {
  138. for idx, ptr := range [][]string{target.Parsers, target.PostOverflows, target.Scenarios, target.Collections} {
  139. ptrtype := ItemTypes[idx]
  140. for _, p := range ptr {
  141. val, ok := hubIdx.Items[ptrtype][p]
  142. if !ok {
  143. return fmt.Errorf("required %s %s of %s doesn't exist, abort", ptrtype, p, target.Name)
  144. }
  145. err = EnableItem(hub, &val)
  146. if err != nil {
  147. return fmt.Errorf("while installing %s: %w", p, err)
  148. }
  149. }
  150. }
  151. }
  152. // check if file already exists where it should in configdir (eg /etc/crowdsec/collections/)
  153. if _, err = os.Lstat(parentDir + "/" + target.FileName); !os.IsNotExist(err) {
  154. log.Infof("%s already exists.", parentDir+"/"+target.FileName)
  155. return nil
  156. }
  157. // hub.ConfigDir + target.RemotePath
  158. srcPath, err := filepath.Abs(hub.HubDir + "/" + target.RemotePath)
  159. if err != nil {
  160. return fmt.Errorf("while getting source path: %w", err)
  161. }
  162. dstPath, err := filepath.Abs(parentDir + "/" + target.FileName)
  163. if err != nil {
  164. return fmt.Errorf("while getting destination path: %w", err)
  165. }
  166. if err = os.Symlink(srcPath, dstPath); err != nil {
  167. return fmt.Errorf("while creating symlink from %s to %s: %w", srcPath, dstPath, err)
  168. }
  169. log.Infof("Enabled %s : %s", target.Type, target.Name)
  170. target.Installed = true
  171. hubIdx.Items[target.Type][target.Name] = *target
  172. return nil
  173. }