123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290 |
- 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
- }
|