Skip to content

Commit 357da4e

Browse files
authored
Merge pull request #695 from aau-network-security/develop
File upload feature
2 parents a435eee + db5ed9a commit 357da4e

9 files changed

Lines changed: 166 additions & 12 deletions

File tree

daemon/config.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ type Config struct {
2727
Rechaptcha string `yaml:"recaptcha-key,omitempty"`
2828
APICreds APICreds `yaml:"api-creds,omitempty"`
2929
DockerRepositories []dockerclient.AuthConfiguration `yaml:"docker-repositories,omitempty"`
30+
FileTransferRoot FileTransferConf `yaml:"file-transfer-root,omitempty"`
3031
}
3132

3233
type APICreds struct {
@@ -68,3 +69,7 @@ type Files struct {
6869
ExercisesFile string `yaml:"exercises-file,omitempty"`
6970
FrontendsFile string `yaml:"frontends-file,omitempty"`
7071
}
72+
73+
type FileTransferConf struct {
74+
Path string `yaml:"path"`
75+
}

daemon/daemon.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,10 @@ func NewConfigFromFile(path string) (*Config, error) {
211211
}
212212

213213
func New(conf *Config) (*daemon, error) {
214+
err := vbox.CreateFileTransferRoot(conf.FileTransferRoot.Path)
215+
if err != nil {
216+
log.Fatal().Msgf("Error while creating file transfer root: %s", err)
217+
}
214218
uf, err := store.NewUserFile(conf.ConfFiles.UsersFile)
215219
if err != nil {
216220
return nil, errors.Wrap(err, fmt.Sprintf("unable to read users file: %s", conf.ConfFiles.UsersFile))

daemon/event.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"encoding/json"
66
"errors"
77
"fmt"
8+
"github.com/aau-network-security/haaukins/virtual/vbox"
89
"math"
910
"math/rand"
1011
"net/http"
@@ -375,6 +376,10 @@ func (d *daemon) StopEvent(req *pb.StopEventRequest, resp pb.Daemon_StopEventSer
375376
}
376377

377378
if (user.NPUser && user.Username == createdBy) || !user.NPUser {
379+
// remove the corrosponding event folder
380+
if err := vbox.RemoveEventFolder(string(evtag)); err != nil {
381+
//do nothing
382+
}
378383
_, err := d.dbClient.SetEventStatus(ctx, &pbc.SetEventStatusRequest{EventTag: string(evtag), Status: Closed})
379384
if err != nil {
380385
return fmt.Errorf("error happened on setting up status of event, err: %v", err)
@@ -702,6 +707,7 @@ func (d *daemon) closeEvent(ch chan guacamole.Event, wg *sync.WaitGroup) error {
702707
currentTime := strconv.Itoa(int(time.Now().Unix()))
703708
newEventTag := fmt.Sprintf("%s-%s", e.Tag, currentTime)
704709
event, err := d.eventPool.GetEvent(e.Tag)
710+
_ = vbox.RemoveEventFolder(string(e.Tag))
705711
if err != nil {
706712
log.Warn().Msgf("event pool get event error %v ", err)
707713
closeErr = err

daemon/instance.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ func (d *daemon) ResetFrontends(req *pb.ResetFrontendsRequest, stream pb.Daemon_
4545
continue
4646
}
4747

48-
if err := lab.ResetFrontends(stream.Context()); err != nil {
48+
if err := lab.ResetFrontends(stream.Context(), string(evtag), reqTeam.Id); err != nil {
4949
return err
5050
}
5151
stream.Send(&pb.ResetTeamStatus{TeamId: reqTeam.Id, Status: "ok"})
@@ -61,7 +61,7 @@ func (d *daemon) ResetFrontends(req *pb.ResetFrontendsRequest, stream pb.Daemon_
6161
continue
6262
}
6363

64-
if err := lab.ResetFrontends(stream.Context()); err != nil {
64+
if err := lab.ResetFrontends(stream.Context(), string(evtag), t.ID()); err != nil {
6565
return err
6666
}
6767
stream.Send(&pb.ResetTeamStatus{TeamId: t.ID(), Status: "ok"})

lab/lab.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ type Lab interface {
112112
Suspend(context.Context) error
113113
Resume(context.Context) error
114114
Environment() exercise.Environment
115-
ResetFrontends(ctx context.Context) error
115+
ResetFrontends(ctx context.Context, eventTag, teamId string) error
116116
RdpConnPorts() []uint
117117
Tag() string
118118
AddChallenge(ctx context.Context, confs ...store.Exercise) error
@@ -190,7 +190,7 @@ func (l *lab) Environment() exercise.Environment {
190190
return l.environment
191191
}
192192

193-
func (l *lab) ResetFrontends(ctx context.Context) error {
193+
func (l *lab) ResetFrontends(ctx context.Context, eventTag, teamId string) error {
194194
var errs []error
195195
for p, vmConf := range l.frontends {
196196
err := vmConf.vm.Close()
@@ -210,6 +210,11 @@ func (l *lab) ResetFrontends(ctx context.Context) error {
210210
errs = append(errs, err)
211211
continue
212212
}
213+
214+
err = vbox.CreateFolderLink(vm.Info().Id, eventTag, teamId)
215+
if err != nil {
216+
log.Logger.Debug().Msgf("Error creating shared folder link after vm reset: %s", err)
217+
}
213218
}
214219

215220
if len(errs) > 0 {

svcs/guacamole/event.go

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@ type labNetInfo struct {
268268
}
269269

270270
func NewEvent(ctx context.Context, e store.Event, hub lab.Hub, flags []store.ChildrenChalConfig, reCaptchaKey string) (Event, error) {
271-
guac, err := New(ctx, Config{}, e.OnlyVPN)
271+
guac, err := New(ctx, Config{}, e.OnlyVPN, string(e.Tag))
272272
if err != nil {
273273
return nil, err
274274
}
@@ -694,6 +694,10 @@ func removeVPNConfigs(confFile string) error {
694694

695695
func (ev *event) createGuacConn(t *store.Team, lab lab.Lab) error {
696696
enableWallPaper := true
697+
enableDrive := true
698+
createDrivePath := true
699+
// Drive path is the home folder inside the docker guacamole
700+
drivePath := "/home/" + t.ID()
697701
rdpPorts := lab.RdpConnPorts()
698702
if n := len(rdpPorts); n == 0 {
699703
log.
@@ -717,7 +721,6 @@ func (ev *event) createGuacConn(t *store.Team, lab lab.Lab) error {
717721
}
718722

719723
ev.guacUserStore.CreateUserForTeam(t.ID(), u)
720-
721724
hostIp, err := ev.dockerHost.GetDockerHostIP()
722725
if err != nil {
723726
return err
@@ -736,10 +739,20 @@ func (ev *event) createGuacConn(t *store.Team, lab lab.Lab) error {
736739
Username: &u.Username,
737740
Password: &u.Password,
738741
EnableWallPaper: &enableWallPaper,
742+
EnableDrive: &enableDrive,
743+
CreateDrivePath: &createDrivePath,
744+
DrivePath: &drivePath,
739745
}); err != nil {
740746
return err
741747
}
742748
}
749+
750+
instanceInfo := lab.InstanceInfo()
751+
// Will not handle error below since this is not a critical function
752+
_ = vbox.CreateUserFolder(t.ID(), string(ev.store.Tag))
753+
754+
_ = vbox.CreateFolderLink(instanceInfo[0].Id, string(ev.store.Tag), t.ID())
755+
743756
return nil
744757
}
745758

@@ -909,7 +922,7 @@ func (ev *event) Handler() http.Handler {
909922
if !ok {
910923
return fmt.Errorf("Not found suitable team for given id: %s", t.ID())
911924
}
912-
if err := teamLab.ResetFrontends(context.Background()); err != nil {
925+
if err := teamLab.ResetFrontends(context.Background(), string(ev.store.Tag), t.ID()); err != nil {
913926
return fmt.Errorf("Reset frontends hook error %v", err)
914927
}
915928
return nil

svcs/guacamole/guacamole.go

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,12 @@ import (
1616
"net/http/cookiejar"
1717
"net/http/httputil"
1818
"net/url"
19+
"os"
1920
"strings"
2021
"time"
2122

23+
"github.com/aau-network-security/haaukins/virtual/vbox"
24+
2225
"github.com/aau-network-security/haaukins/store"
2326

2427
"github.com/aau-network-security/haaukins/svcs"
@@ -101,7 +104,7 @@ type Guacamole interface {
101104
ProxyHandler(us *GuacUserStore, klp KeyLoggerPool, am *amigo.Amigo, event Event) svcs.ProxyConnector
102105
}
103106

104-
func New(ctx context.Context, conf Config, onlyVPN int32) (Guacamole, error) {
107+
func New(ctx context.Context, conf Config, onlyVPN int32, eventTag string) (Guacamole, error) {
105108
jar, err := cookiejar.New(nil)
106109
if err != nil {
107110
return nil, err
@@ -125,7 +128,7 @@ func New(ctx context.Context, conf Config, onlyVPN int32) (Guacamole, error) {
125128
conf: conf,
126129
}
127130
if onlyVPN != docker.OnlyVPN {
128-
if err := guac.create(ctx); err != nil {
131+
if err := guac.create(ctx, eventTag); err != nil {
129132
return nil, err
130133
}
131134
}
@@ -147,14 +150,23 @@ func (guac *guacamole) GetPort() uint {
147150
return guac.webPort
148151
}
149152

150-
func (guac *guacamole) create(ctx context.Context) error {
153+
func (guac *guacamole) create(ctx context.Context, eventTag string) error {
154+
_ = vbox.CreateEventFolder(eventTag)
155+
156+
user := fmt.Sprintf("%d:%d", os.Getuid(), os.Getgid())
157+
log.Debug().Str("user", user).Msg("starting guacd")
158+
151159
containers := map[string]docker.Container{}
152160
containers["guacd"] = docker.NewContainer(docker.ContainerConfig{
153161
Image: "guacamole/guacd:1.2.0",
154162
UseBridge: true,
155163
Labels: map[string]string{
156164
"hkn": "guacamole_guacd",
157165
},
166+
Mounts: []string{
167+
vbox.FileTransferRoot + "/" + eventTag + "/:/home/",
168+
},
169+
User: user,
158170
})
159171

160172
mysqlPass := uuid.New().String()
@@ -570,6 +582,7 @@ type createRDPConnConf struct {
570582
SFTPAliveInterval *uint `json:"sftp-server-alive-interval"`
571583
SwapRedBlue *bool `json:"swap-red-blue"`
572584
CreateDrivePath *bool `json:"create-drive-path"`
585+
DrivePath *string `json:"drive-path"`
573586
Username *string `json:"username,omitempty"`
574587
Password *string `json:"password,omitempty"`
575588
}
@@ -586,6 +599,9 @@ type CreateRDPConnOpts struct {
586599
ResolutionHeight uint
587600
MaxConn uint
588601
ColorDepth uint
602+
EnableDrive *bool
603+
CreateDrivePath *bool
604+
DrivePath *string
589605
}
590606

591607
func (guac *guacamole) CreateRDPConn(opts CreateRDPConnOpts) error {
@@ -617,7 +633,7 @@ func (guac *guacamole) CreateRDPConn(opts CreateRDPConnOpts) error {
617633
if opts.ColorDepth == 0 {
618634
opts.ColorDepth = 16
619635
}
620-
636+
log.Debug().Str("drive-path", *opts.DrivePath).Msg("Drivepath for user is")
621637
conf := createRDPConnConf{
622638
Hostname: &opts.Host,
623639
Width: &opts.ResolutionWidth,
@@ -627,6 +643,9 @@ func (guac *guacamole) CreateRDPConn(opts CreateRDPConnOpts) error {
627643
Username: opts.Username,
628644
Password: opts.Password,
629645
EnableWallpaper: opts.EnableWallPaper,
646+
EnableDrive: opts.EnableDrive,
647+
CreateDrivePath: opts.CreateDrivePath,
648+
DrivePath: opts.DrivePath,
630649
}
631650

632651
data := struct {
@@ -650,7 +669,6 @@ func (guac *guacamole) CreateRDPConn(opts CreateRDPConnOpts) error {
650669

651670
action := func(t string) (*http.Response, error) {
652671
endpoint := guac.baseUrl() + "/guacamole/api/session/data/mysql/connections?token=" + t
653-
654672
req, err := http.NewRequest("POST", endpoint, bytes.NewBuffer(jsonData))
655673
if err != nil {
656674
return nil, err

virtual/docker/docker.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ type ContainerConfig struct {
136136
PortBindings map[string]string
137137
Labels map[string]string
138138
Mounts []string
139+
User string
139140
Resources *Resources
140141
Cmd []string
141142
DNS []string
@@ -312,6 +313,7 @@ func (c *container) getCreateConfig() (*docker.CreateContainerOptions, error) {
312313
return &docker.CreateContainerOptions{
313314
Name: uuid.New().String(),
314315
Config: &docker.Config{
316+
User: c.conf.User,
315317
Image: c.conf.Image,
316318
Env: env,
317319
Cmd: c.conf.Cmd,

virtual/vbox/vbox.go

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ const (
4141
vboxShowVMInfo = "showvminfo"
4242
)
4343

44+
var FileTransferRoot string
45+
4446
func init() {
4547
zerolog.SetGlobalLevel(zerolog.Disabled)
4648
}
@@ -257,6 +259,11 @@ func SetLocalRDP(ip string, port uint) VMOpt {
257259
return err
258260
}
259261

262+
_, err = VBoxCmdContext(ctx, vboxModVM, vm.id, "--vrdemulticon", "on")
263+
if err != nil {
264+
return err
265+
}
266+
260267
return nil
261268
}
262269
}
@@ -503,3 +510,97 @@ func VBoxCmdContext(ctx context.Context, cmd string, cmds ...string) ([]byte, er
503510

504511
return out, nil
505512
}
513+
514+
func CreateFileTransferRoot(path string) error {
515+
FileTransferRoot = path
516+
if _, err := os.Stat(path); !os.IsNotExist(err) {
517+
//If path exists
518+
log.Info().Str("transfer-root", path).Msg("File transfer root already exists... Continuing.")
519+
return nil
520+
}
521+
log.Info().Str("transfer-root", path).Msg("File transfer root does not exists... Creating folder")
522+
err := os.MkdirAll(path, 0777)
523+
if err != nil {
524+
log.Warn().Msgf("Error creating file transfer root: %s", err)
525+
return err
526+
}
527+
err = os.Chmod(path, os.ModePerm)
528+
if err != nil {
529+
log.Warn().Msgf("Error setting folder perms on: %s error: %s", path, err)
530+
return err
531+
}
532+
log.Info().Msg("File transfer root succesfully created!")
533+
return nil
534+
}
535+
536+
func CreateEventFolder(tag string) error {
537+
path := FileTransferRoot + "/" + tag
538+
if _, err := os.Stat(path); !os.IsNotExist(err) {
539+
//If path exists
540+
log.Info().Str("event-root", path).Msg("Event root already exists... Continuing.")
541+
return nil
542+
}
543+
log.Info().Str("event-root", path).Msg("Event root does not exists... Creating folder")
544+
err := os.MkdirAll(path, os.ModePerm)
545+
if err != nil {
546+
log.Warn().Msgf("Error creating event root: %s", err)
547+
return err
548+
}
549+
err = os.Chmod(path, os.ModePerm)
550+
if err != nil {
551+
log.Warn().Msgf("Error setting folder perms on: %s error: %s", path, err)
552+
return err
553+
}
554+
log.Info().Msg("Event root succesfully created!")
555+
return nil
556+
}
557+
558+
func RemoveEventFolder(eventTag string) error {
559+
path := FileTransferRoot + "/" + eventTag
560+
if _, err := os.Stat(path); !os.IsNotExist(err) {
561+
//If path exists
562+
log.Info().Str("Event-folder", path).Msg("Event-folder exists... Deleting.")
563+
err := os.RemoveAll(path)
564+
if err != nil {
565+
log.Warn().Msgf("Error deleting event folder: %s with error: %s", path, err)
566+
return err
567+
}
568+
return nil
569+
} else {
570+
log.Info().Str("Event-folder", path).Msg("Event-folder does not exists... Continueing")
571+
return nil
572+
}
573+
}
574+
575+
func CreateUserFolder(teamId string, eventTag string) error {
576+
path := FileTransferRoot + "/" + eventTag + "/" + teamId
577+
if _, err := os.Stat(path); !os.IsNotExist(err) {
578+
//If path exists
579+
log.Info().Str("User-folder", path).Msg("User-folder already exists... Continuing.")
580+
return nil
581+
}
582+
log.Info().Str("User-folder", path).Msg("User-folder does not exists... Creating folder")
583+
err := os.MkdirAll(path, 0777)
584+
if err != nil {
585+
log.Warn().Msgf("Error creating User-folder: %s", err)
586+
return err
587+
}
588+
err = os.Chmod(path, os.ModePerm)
589+
if err != nil {
590+
log.Warn().Msgf("Error setting folder perms on: %s error: %s", path, err)
591+
return err
592+
}
593+
log.Info().Msg("User-folder succesfully created!")
594+
return nil
595+
}
596+
597+
func CreateFolderLink(vm string, eventTag string, teamId string) error {
598+
log.Debug().Msgf("Trying to link shared folder to vm: %s", vm)
599+
//todo Figure out a way to add the new folder and general setup of filetransfer folder and how to manage its content.
600+
_, err := VBoxCmdContext(context.Background(), "sharedfolder", "add", vm, "--name", "filetransfer", "-hostpath", FileTransferRoot+"/"+eventTag+"/"+teamId, "-transient", "-automount")
601+
if err != nil {
602+
log.Warn().Msgf("Error creating shared folder link: %s", err)
603+
return err
604+
}
605+
return nil
606+
}

0 commit comments

Comments
 (0)