|
@@ -1,129 +1,290 @@
|
|
|
-package main
|
|
|
-
|
|
|
-import (
|
|
|
- "encoding/json"
|
|
|
- "log"
|
|
|
- "net/http"
|
|
|
- "os"
|
|
|
- "os/signal"
|
|
|
- "syscall"
|
|
|
-
|
|
|
- "git.arozos.com/ArSamba/apt"
|
|
|
-
|
|
|
- "git.arozos.com/ArSamba/aroz"
|
|
|
-)
|
|
|
-
|
|
|
-var (
|
|
|
- handler *aroz.ArozHandler
|
|
|
-)
|
|
|
-
|
|
|
-func SetupCloseHandler() {
|
|
|
- c := make(chan os.Signal, 2)
|
|
|
- signal.Notify(c, os.Interrupt, syscall.SIGTERM)
|
|
|
- go func() {
|
|
|
- <-c
|
|
|
- log.Println("\r- Shutting down ArSamba module.")
|
|
|
-
|
|
|
- os.Exit(0)
|
|
|
- }()
|
|
|
-}
|
|
|
-
|
|
|
-func main() {
|
|
|
- //If you have other flags, please add them here
|
|
|
-
|
|
|
- //Start the aoModule pipeline (which will parse the flags as well). Pass in the module launch information
|
|
|
- handler = aroz.HandleFlagParse(aroz.ServiceInfo{
|
|
|
- Name: "ArSamba",
|
|
|
- Desc: "arozos Samba Setting Subservice",
|
|
|
- Group: "System Settings",
|
|
|
- IconPath: "arsamba/img/icon.png",
|
|
|
- Version: "1.0",
|
|
|
- StartDir: "arsamba/index.html",
|
|
|
- SupportFW: true,
|
|
|
- LaunchFWDir: "arsamba/index.html",
|
|
|
- InitFWSize: []int{350, 560},
|
|
|
- })
|
|
|
-
|
|
|
- //Install samba if it is not installed
|
|
|
- pm := apt.NewPackageManager(true)
|
|
|
- pm.InstallIfNotExists("samba", true)
|
|
|
-
|
|
|
- //Register the standard web services urls
|
|
|
- fs := http.FileServer(http.Dir("./web"))
|
|
|
- http.HandleFunc("/create", handleNewUser)
|
|
|
- http.HandleFunc("/remove", handleUserRemove)
|
|
|
- http.HandleFunc("/getStatus", handleGetStatus)
|
|
|
- http.Handle("/", fs)
|
|
|
-
|
|
|
- SetupCloseHandler()
|
|
|
-
|
|
|
- log.Println("ArSamba subservice started. Listening on " + handler.Port)
|
|
|
- err := http.ListenAndServe(handler.Port, nil)
|
|
|
- if err != nil {
|
|
|
- log.Fatal(err)
|
|
|
- }
|
|
|
-
|
|
|
-}
|
|
|
-
|
|
|
-func handleGetStatus(w http.ResponseWriter, r *http.Request) {
|
|
|
- //Get username from request
|
|
|
- username, _ := handler.GetUserInfoFromRequest(w, r)
|
|
|
-
|
|
|
- //Check if the user has already in samba user
|
|
|
- log.Println("Checking User Status", username)
|
|
|
-
|
|
|
- //Send the results
|
|
|
- js, _ := json.Marshal(true)
|
|
|
- sendJSONResponse(w, string(js))
|
|
|
-}
|
|
|
-
|
|
|
-func handleNewUser(w http.ResponseWriter, r *http.Request) {
|
|
|
- //Get the required information
|
|
|
- username, err := mv(r, "username", true)
|
|
|
- if err != nil {
|
|
|
- sendErrorResponse(w, "Invalid username given")
|
|
|
- return
|
|
|
- }
|
|
|
-
|
|
|
- //Match the session username
|
|
|
- proxyUser, _ := handler.GetUserInfoFromRequest(w, r)
|
|
|
- if username != proxyUser {
|
|
|
- sendErrorResponse(w, "User not logged in")
|
|
|
- return
|
|
|
- }
|
|
|
-
|
|
|
- password, err := mv(r, "password", true)
|
|
|
- if err != nil {
|
|
|
- sendErrorResponse(w, "Invalid password given")
|
|
|
- return
|
|
|
- }
|
|
|
-
|
|
|
- //Add the user to samba
|
|
|
- log.Println("Adding User", username, password)
|
|
|
-
|
|
|
- //Return ok
|
|
|
- sendOK(w)
|
|
|
-
|
|
|
-}
|
|
|
-
|
|
|
-func handleUserRemove(w http.ResponseWriter, r *http.Request) {
|
|
|
- //Get the required information
|
|
|
- username, err := mv(r, "username", true)
|
|
|
- if err != nil {
|
|
|
- sendErrorResponse(w, "Invalid username given")
|
|
|
- return
|
|
|
- }
|
|
|
-
|
|
|
- //Match the session username
|
|
|
- proxyUser, _ := handler.GetUserInfoFromRequest(w, r)
|
|
|
- if username != proxyUser {
|
|
|
- sendErrorResponse(w, "User not logged in")
|
|
|
- return
|
|
|
- }
|
|
|
-
|
|
|
- //OK! Remove user
|
|
|
- log.Println("Remove user", username)
|
|
|
-
|
|
|
- //Return OK
|
|
|
- sendOK(w)
|
|
|
-}
|
|
|
+package main
|
|
|
+
|
|
|
+import (
|
|
|
+ "encoding/json"
|
|
|
+ "io/ioutil"
|
|
|
+ "log"
|
|
|
+ "net/http"
|
|
|
+ "os"
|
|
|
+ "os/exec"
|
|
|
+ "os/signal"
|
|
|
+ "path/filepath"
|
|
|
+ "strings"
|
|
|
+ "syscall"
|
|
|
+
|
|
|
+ "git.arozos.com/ArSamba/apt"
|
|
|
+
|
|
|
+ "git.arozos.com/ArSamba/aroz"
|
|
|
+)
|
|
|
+
|
|
|
+var (
|
|
|
+ handler *aroz.ArozHandler
|
|
|
+)
|
|
|
+
|
|
|
+func SetupCloseHandler() {
|
|
|
+ c := make(chan os.Signal, 2)
|
|
|
+ signal.Notify(c, os.Interrupt, syscall.SIGTERM)
|
|
|
+ go func() {
|
|
|
+ <-c
|
|
|
+ log.Println("\r- Shutting down ArSamba module.")
|
|
|
+
|
|
|
+ os.Exit(0)
|
|
|
+ }()
|
|
|
+}
|
|
|
+
|
|
|
+func main() {
|
|
|
+ //If you have other flags, please add them here
|
|
|
+
|
|
|
+ //Start the aoModule pipeline (which will parse the flags as well). Pass in the module launch information
|
|
|
+ handler = aroz.HandleFlagParse(aroz.ServiceInfo{
|
|
|
+ Name: "ArSamba",
|
|
|
+ Desc: "arozos Samba Setting Subservice",
|
|
|
+ Group: "System Settings",
|
|
|
+ IconPath: "arsamba/img/icon.png",
|
|
|
+ Version: "1.0",
|
|
|
+ StartDir: "arsamba/index.html",
|
|
|
+ SupportFW: true,
|
|
|
+ LaunchFWDir: "arsamba/index.html",
|
|
|
+ InitFWSize: []int{350, 560},
|
|
|
+ })
|
|
|
+
|
|
|
+ //Register the standard web services urls
|
|
|
+ fs := http.FileServer(http.Dir("./web"))
|
|
|
+ http.HandleFunc("/create", handleNewUser)
|
|
|
+ http.HandleFunc("/remove", handleUserRemove)
|
|
|
+ http.HandleFunc("/getStatus", handleGetStatus)
|
|
|
+ http.Handle("/", fs)
|
|
|
+
|
|
|
+ SetupCloseHandler()
|
|
|
+
|
|
|
+ go func(port string) {
|
|
|
+ log.Println("ArSamba subservice started. Listening on " + handler.Port)
|
|
|
+ err := http.ListenAndServe(port, nil)
|
|
|
+ if err != nil {
|
|
|
+ log.Fatal(err)
|
|
|
+ }
|
|
|
+ }(handler.Port)
|
|
|
+
|
|
|
+ //Mkdir for user samba profile
|
|
|
+ os.MkdirAll("./profiles", 0755)
|
|
|
+
|
|
|
+ //Install samba if it is not installed
|
|
|
+ pm := apt.NewPackageManager(true)
|
|
|
+ err := pm.InstallIfNotExists("samba", true)
|
|
|
+ if err != nil {
|
|
|
+ panic(err)
|
|
|
+ }
|
|
|
+
|
|
|
+ //Do a blocking loop
|
|
|
+ select {}
|
|
|
+}
|
|
|
+
|
|
|
+func handleGetStatus(w http.ResponseWriter, r *http.Request) {
|
|
|
+ //Get username from request
|
|
|
+ username, _ := handler.GetUserInfoFromRequest(w, r)
|
|
|
+
|
|
|
+ //Check if the user has already in samba user
|
|
|
+ log.Println("Checking User Status", username)
|
|
|
+ userExists := false
|
|
|
+ out, err := execute("pdbedit -L | grep " + username)
|
|
|
+ if err != nil {
|
|
|
+ userExists = false
|
|
|
+ }
|
|
|
+
|
|
|
+ if strings.TrimSpace(string(out)) != "" {
|
|
|
+ userExists = true
|
|
|
+ }
|
|
|
+
|
|
|
+ //Send the results
|
|
|
+ js, _ := json.Marshal(userExists)
|
|
|
+ sendJSONResponse(w, string(js))
|
|
|
+}
|
|
|
+
|
|
|
+func handleNewUser(w http.ResponseWriter, r *http.Request) {
|
|
|
+ //Get the required information
|
|
|
+ username, err := mv(r, "username", true)
|
|
|
+ if err != nil {
|
|
|
+ sendErrorResponse(w, "Invalid username given")
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ //Match the session username
|
|
|
+ proxyUser, token := handler.GetUserInfoFromRequest(w, r)
|
|
|
+ if username != proxyUser {
|
|
|
+ sendErrorResponse(w, "User not logged in")
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ password, err := mv(r, "password", true)
|
|
|
+ if err != nil {
|
|
|
+ sendErrorResponse(w, "Invalid password given")
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ //Add the user to samba
|
|
|
+ log.Println("Adding User", username)
|
|
|
+ //Add user to linux
|
|
|
+ out, _ := execute("useradd -m \"" + username + "\"")
|
|
|
+ log.Println(string(out))
|
|
|
+
|
|
|
+ //Set password for the new user
|
|
|
+ out, _ = execute(`(echo "` + password + `"; sleep 1; echo "` + password + `";) | passwd "` + username + `"`)
|
|
|
+ log.Println(string(out))
|
|
|
+
|
|
|
+ //Add it to samba user
|
|
|
+ out, _ = execute(`(echo "` + password + `"; sleep 1; echo "` + password + `" ) | sudo smbpasswd -s -a "` + username + `"`)
|
|
|
+ log.Println(string(out))
|
|
|
+
|
|
|
+ //Create an AGI Call that get the user's storage directories files
|
|
|
+ script := `
|
|
|
+ requirelib("filelib");
|
|
|
+ //Get the roots of this user
|
|
|
+ var roots = filelib.glob("/");
|
|
|
+ var userdirs = [];
|
|
|
+ for (var i = 0; i < roots.length; i++){
|
|
|
+ //Translate all these roots to realpath
|
|
|
+ userdirs.push([roots[i].split(":").shift(), decodeAbsoluteVirtualPath(roots[i]), pathCanWrite(roots[i])])
|
|
|
+ }
|
|
|
+
|
|
|
+ sendJSONResp(JSON.stringify(userdirs))
|
|
|
+ `
|
|
|
+
|
|
|
+ userProfile := []string{}
|
|
|
+
|
|
|
+ //Execute the AGI request on server side
|
|
|
+ resp, err := handler.RequestGatewayInterface(token, script)
|
|
|
+ if err != nil {
|
|
|
+ //Something went wrong when performing POST request
|
|
|
+ log.Println(err)
|
|
|
+ } else {
|
|
|
+ //Try to read the resp body
|
|
|
+ bodyBytes, err := ioutil.ReadAll(resp.Body)
|
|
|
+ if err != nil {
|
|
|
+ log.Println(err)
|
|
|
+ w.Write([]byte(err.Error()))
|
|
|
+ return
|
|
|
+ }
|
|
|
+ resp.Body.Close()
|
|
|
+
|
|
|
+ log.Println(string(bodyBytes))
|
|
|
+
|
|
|
+ //Decode the json
|
|
|
+ type Results [][]interface{}
|
|
|
+ results := new(Results)
|
|
|
+ err = json.Unmarshal(bodyBytes, &results)
|
|
|
+ if err != nil {
|
|
|
+ log.Println(err)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ log.Println(results)
|
|
|
+
|
|
|
+ //Generate user root folders
|
|
|
+ for _, r := range *results {
|
|
|
+ if len(r) == 3 {
|
|
|
+ pathname := r[0].(string)
|
|
|
+ if pathname == "tmp" {
|
|
|
+ //Do not expose tmp folder
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ rpath := r[1].(string)
|
|
|
+ canWrite := r[2].(bool)
|
|
|
+ uuidOfStorage := username + " (" + pathname + ")"
|
|
|
+ if canWrite {
|
|
|
+ userProfile = append(userProfile, `[`+uuidOfStorage+`]
|
|
|
+ comment=`+username+"'s "+pathname+`
|
|
|
+ path=`+rpath+`
|
|
|
+ read only=no
|
|
|
+ valid users = `+username+`
|
|
|
+ guest ok=no
|
|
|
+ browseable=yes
|
|
|
+ create mask=0777
|
|
|
+ directory mask=0777`)
|
|
|
+ } else {
|
|
|
+ userProfile = append(userProfile, `[`+uuidOfStorage+`]
|
|
|
+ comment=`+username+"'s "+pathname+`
|
|
|
+ path=`+rpath+`
|
|
|
+ read only=yes
|
|
|
+ valid users = `+username+`
|
|
|
+ guest ok=no
|
|
|
+ browseable=yes
|
|
|
+ create mask=0777
|
|
|
+ directory mask=0777`)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ log.Println(strings.Join(userProfile, "\n\n"))
|
|
|
+
|
|
|
+ //Write the user profiles to file
|
|
|
+ ioutil.WriteFile("./profiles/"+username+".conf", []byte(strings.Join(userProfile, "\n\n")), 0755)
|
|
|
+
|
|
|
+ updateSmbConfig()
|
|
|
+ //Return ok
|
|
|
+ sendOK(w)
|
|
|
+}
|
|
|
+
|
|
|
+func handleUserRemove(w http.ResponseWriter, r *http.Request) {
|
|
|
+ //Get the required information
|
|
|
+ username, err := mv(r, "username", true)
|
|
|
+ if err != nil {
|
|
|
+ sendErrorResponse(w, "Invalid username given")
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ //Match the session username
|
|
|
+ proxyUser, _ := handler.GetUserInfoFromRequest(w, r)
|
|
|
+ if username != proxyUser {
|
|
|
+ sendErrorResponse(w, "User not logged in")
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ //OK! Remove user
|
|
|
+ log.Println("Remove user", username)
|
|
|
+
|
|
|
+ //Remove user from samba
|
|
|
+ out, _ := execute("smbpasswd -x \"" + username + "\"")
|
|
|
+ log.Println(string(out))
|
|
|
+
|
|
|
+ //Remove user from linux as well
|
|
|
+ out, _ = execute("userdel -r \"" + username + "\"")
|
|
|
+ log.Println(string(out))
|
|
|
+
|
|
|
+ //Remove user profiles
|
|
|
+ if fileExists("./profiles/" + username + ".conf") {
|
|
|
+ os.Remove("./profiles/" + username + ".conf")
|
|
|
+ }
|
|
|
+ updateSmbConfig()
|
|
|
+
|
|
|
+ //Return OK
|
|
|
+ sendOK(w)
|
|
|
+}
|
|
|
+
|
|
|
+func updateSmbConfig() {
|
|
|
+ //Update the system config
|
|
|
+ profiles, _ := filepath.Glob("./profiles/*.conf")
|
|
|
+ base, _ := ioutil.ReadFile("smb.conf")
|
|
|
+ additionalProfiles := []string{}
|
|
|
+ for _, profile := range profiles {
|
|
|
+ thisProfileContent, _ := ioutil.ReadFile(profile)
|
|
|
+ additionalProfiles = append(additionalProfiles, string(thisProfileContent))
|
|
|
+ }
|
|
|
+
|
|
|
+ finalConfigFile := string(base) + strings.Join(additionalProfiles, "\n\n")
|
|
|
+
|
|
|
+ ioutil.WriteFile("/etc/samba/smb.conf", []byte(finalConfigFile), 0777)
|
|
|
+
|
|
|
+ out, err := execute("systemctl restart smbd.service")
|
|
|
+ log.Println("Samba restarted: ", string(out), err)
|
|
|
+}
|
|
|
+
|
|
|
+func execute(command string) (string, error) {
|
|
|
+ cmd := exec.Command("bash", "-c", command)
|
|
|
+ out, err := cmd.CombinedOutput()
|
|
|
+ if err != nil {
|
|
|
+ return string(out), err
|
|
|
+ }
|
|
|
+ return string(out), nil
|
|
|
+}
|