Select Git revision
remove.go 4.72 KiB
package user
import (
"fmt"
"log"
"os"
"os/exec"
"path/filepath"
"strconv"
"time"
"github.com/go-ldap/ldap/v3"
"github.com/spf13/cobra"
"gitlab.c3sl.ufpr.br/tss24/useradm/model"
)
var (
ANO = strconv.Itoa(time.Now().Year())
NO_BKP_TRASH = "/nobackup/contas_removidas/" + ANO
HOME_TRASH = "/home/contas_removidas/" + ANO
WEB_TRASH = "/home/contas_removidas/html/" + ANO
)
var RemoveUserCmd = &cobra.Command{
Use: "remove [username]",
Short: "Delete a user",
Args: cobra.ExactArgs(1),
RunE: removeUserFunc,
}
func init() {
RemoveUserCmd.Flags().BoolP("confirm", "y", false, "Skip confirmation prompt")
}
func removeUserFunc(cmd *cobra.Command, args []string) error {
var opts model.Opts
success := false
err := opts.RetrieveOpts(cmd)
if err != nil {
return err
}
login := args[0]
u, err := locateUser(login)
if err != nil {
return err
}
defer func() {
if !success {
log.Println("Found error, rolling back dirs...")
_ = moveAndChown(filepath.Join(NO_BKP_TRASH, filepath.Base(u.Nobackup)),
u.Nobackup, u.UID, u.GID)
_ = moveAndChown(filepath.Join(HOME_TRASH, filepath.Base(u.Homedir)),
u.Homedir, u.UID, u.GID)
_ = moveAndChown(filepath.Join(WEB_TRASH, filepath.Base(u.Webdir)),
u.Webdir, u.UID, u.GID)
}
}()
fmt.Printf("Found %v\n\n", u.ToString())
confirmationPrompt(opts.Confirm, "removal")
err = removeDirs(u)
if err != nil {
return err
}
err = delUserLDAP(u)
if err != nil {
return err
}
fmt.Printf("\nUser removed!\n")
success = true
return nil
}
// searches for the specified login string, there can only be one >:)
func locateUser(login string) (model.User, error) {
var u model.User
users, err := getUsers()
if !loginExists(users, login) {
return u, fmt.Errorf("Failed to find login in LDAP database: %v", err)
}
filter := searchUser(users, false, login, "", "", "", "", "")
if len(filter) != 1 {
return u, fmt.Errorf(`More than one user matched the login given.
search made: "useradm user show -l %v"`, login)
}
u = filter[0]
return u, nil
}
// moves dirs to their respective trash dir
func removeDirs(u model.User) error {
err := moveAndChown(u.Homedir, HOME_TRASH, "nobody", "nogroup")
if err != nil {
return err
}
err = moveAndChown(u.Nobackup, NO_BKP_TRASH, "nobody", "nogroup")
if err != nil {
return err
}
err = moveAndChown(u.Webdir, WEB_TRASH, "nobody", "nogroup")
if err != nil {
return err
}
return nil
}
func delUserLDAP(u model.User) error {
l, err := connLDAP()
if err != nil {
return err
}
defer l.Close()
// first remove user from all groups
searchReq := ldap.NewSearchRequest(
"ou=grupos,dc=c3local,dc=com",
ldap.ScopeWholeSubtree,
ldap.NeverDerefAliases, 0, 0, false,
"(memberUid="+u.UID+")", // filter by UID membership
[]string{"dn"},
nil,
)
// searches groups for target
groups, err := l.Search(searchReq)
if err != nil && !ldap.IsErrorWithCode(err, ldap.LDAPResultNoSuchObject) {
return fmt.Errorf("Group members search failed: %v", err)
}
// removing from groups
for _, entry := range groups.Entries {
modReq := ldap.NewModifyRequest(entry.DN, nil)
modReq.Delete("memberUid", []string{u.UID})
if err := l.Modify(modReq); err != nil &&
!ldap.IsErrorWithCode(err, ldap.LDAPResultNoSuchAttribute) {
log.Printf("Warning: Failed to remove from group %s: %v", entry.DN, err)
}
}
// removing user entry
delReq := ldap.NewDelRequest(u.DN, nil)
if err := l.Del(delReq); err != nil &&
!ldap.IsErrorWithCode(err, ldap.LDAPResultNoSuchObject) {
return fmt.Errorf("user deletion failed: %v", err)
}
return nil
}
// usually not necessary but used in a failed create command
func delKerberosPrincipal(login string) error {
cmd := exec.Command("kadmin.local", "-q", fmt.Sprintf("delprinc -force %s", login))
output, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("Fail to delete Kerberos principal: %v\nOutput: %s", err, output)
}
return nil
}
func moveAndChown(orig, dest, owner, group string) error {
// check if orig exists
if _, err := os.Stat(orig); err != nil {
log.Printf("Directory %v not found so not moved\n", orig)
return nil
}
// construct destination path
destPath := filepath.Join(dest, filepath.Base(orig))
if _, err := os.Stat(destPath); err == nil {
return fmt.Errorf("Directory %v already exists, can't move\n", destPath)
}
// move directory
cmd := exec.Command("mv", orig, destPath)
if output, err := cmd.CombinedOutput(); err != nil {
return fmt.Errorf("Failed to move dirs: %w\nOutput: %v", err, output)
}
// recursive chown
cmd = exec.Command("chown", "-R", owner+":"+group, destPath)
if output, err := cmd.CombinedOutput(); err != nil {
return fmt.Errorf("Failed to set owner/group: %w\nOutput: %v", err, output)
}
return nil
}