diff --git a/cmd/user.go b/cmd/user.go
index 2a4dafd010904b779e5d603cd3ef51c5e0ce8acc..177e3763355b9e5b2f0e96d1db650da8ed43d575 100644
--- a/cmd/user.go
+++ b/cmd/user.go
@@ -18,4 +18,5 @@ func init() {
 	userCmd.AddCommand(user.DeleteUserCmd)
 	userCmd.AddCommand(user.ModCmd)
 	userCmd.AddCommand(user.ShowCmd)
+	userCmd.AddCommand(user.ResetCmd)
 }
diff --git a/cmd/user/create.go b/cmd/user/create.go
index 26b41cb63f0cbd48ecbbf25ff6b0ff26f17cefed..dee6c40ee46eb1724411d9b6c232f1f2d0cc1735 100644
--- a/cmd/user/create.go
+++ b/cmd/user/create.go
@@ -20,7 +20,7 @@ const (
 	DEF_PERMISSION  = "0700"         // default user dir permission
 	BLK_PERMISSION  = "0000"         // user dir permission if blocked
 	HTML_BASE_PERM  = "0755"         // set public_html to this on creation
-	MAX_VARIANCE    = 50             // tries made to create login automatically
+	MAX_VARIANCE    = 200            // tries made to create login automatically
 	MIN_UID         = 1000
 	MAX_UID         = 6000
 )
@@ -239,42 +239,44 @@ func genLogin(name string, grr string, ltype LoginType, variance int) string {
 		return "_"
 	}
 
-	part_prefix_len := make([]int, len(parts))
+	partPrefixLen := make([]int, len(parts))
 	if ltype == Initials {
-		// a primeira letra de cada parte deve aparecer
+		// the first letter of each part must appear
 		for i := 0; i < len(parts); i++ {
-			part_prefix_len[i] = 1
+			partPrefixLen[i] = 1
 		}
 	} else if ltype == FirstName {
-		// a primeira parte inteira deve aparecer
-		part_prefix_len[0] = len(parts[0])
+		// the first name(part) must appear
+		partPrefixLen[0] = len(parts[0])
 	} else {
-		// a primeira letra de cada parte deve aparecer
+		// the first letter of each part must appear
 		for i := 0; i < len(parts); i++ {
-			part_prefix_len[i] = 1
+			partPrefixLen[i] = 1
 		}
-		// assim com a parte final do nome
-		part_prefix_len[len(parts)-1] = len(parts[len(parts)-1])
+		// just as the last part
+		partPrefixLen[len(parts)-1] = len(parts[len(parts)-1])
 	}
-	part_prefix_ix := 0
+
+	partPrefixIx := 0
 	for i := 0; i < variance; i++ {
 		ok := false
 		for k := 0; k < len(parts) && !ok; k++ {
-			if part_prefix_len[part_prefix_ix] < len(parts[part_prefix_ix]) {
-				part_prefix_len[part_prefix_ix]++
+			if partPrefixLen[partPrefixIx] < len(parts[partPrefixIx]) {
+				partPrefixLen[partPrefixIx]++
 				ok = true
 			}
-			part_prefix_ix = (part_prefix_ix + 1) % len(parts)
+			partPrefixIx = (partPrefixIx + 1) % len(parts)
 		}
 		if !ok {
-			// acabou o que fazer, vamos abandonar porque não vai mudar mais nada
+			// it's joever, from now on nothing happens, quit :D
 			break
 		}
 	}
 
+	// contruct the login with the given legths
 	login := ""
 	for i := 0; i < len(parts); i++ {
-		login += parts[i][:part_prefix_len[i]]
+		login += parts[i][:partPrefixLen[i]]
 	}
 	if login == "" {
 		return "_"
@@ -396,21 +398,6 @@ func addKerberosPrincipal(login string) error {
 	return nil
 }
 
-// sets the password for the user (via kerberos)
-func modKerberosPassword(login, password string) error {
-	cmd := exec.Command("kadmin.local", "-q",
-		fmt.Sprintf("cpw -pw %s %s", password, login))
-
-	cmd.Stdout = nil
-	cmd.Stderr = nil
-	output, err := cmd.CombinedOutput()
-	if err != nil {
-		return fmt.Errorf("Failed to change password for %s: %v\nOutput: %s", login, err, output)
-	}
-
-	return nil
-}
-
 func createUserDirs(u model.User) error {
 	success := false
 
diff --git a/cmd/user/mod.go b/cmd/user/mod.go
index 74f23bbd96101cc57ca086237eb303d6f309692b..ded2fa745cf200b6fa522aaa3b53a7c93ee90f71 100644
--- a/cmd/user/mod.go
+++ b/cmd/user/mod.go
@@ -2,31 +2,32 @@ package user
 
 import (
 	"bufio"
-	"crypto/rand"
 	"fmt"
 	"os"
 	"os/exec"
 	"strings"
 
+	"github.com/go-ldap/ldap/v3"
 	"github.com/spf13/cobra"
 	"gitlab.c3sl.ufpr.br/tss24/useradm/model"
 	"gopkg.in/yaml.v3"
 )
 
 type cfg struct {
-	Name   string `yaml:"name"`
-	GRR    string `yaml:"grr"`
-	Group  string `yaml:"group"`
-	Status string `yaml:"status"`
-	Shell  string `yaml:"shell"`
-	Course string `yaml:"course"`
-	Resp   string `yaml:"resp"`
-	Expiry string `yaml:"expiry"`
+	Name   string `yaml:"Name"`
+	GRR    string `yaml:"GRR"`
+	Group  string `yaml:"Group"`
+	Status string `yaml:"Status"`
+	Shell  string `yaml:"Shell"`
+	Course string `yaml:"Course"`
+	Resp   string `yaml:"Resp"`
+	Expiry string `yaml:"Expiry"`
 }
 
 var ModCmd = &cobra.Command{
 	Use:   "mod [username]",
 	Short: "Modify user information",
+	Long:  "Opens a file for editing the users config. Uses $EDITOR variable",
 	Args:  cobra.ExactArgs(1),
 	RunE:  modifyUserFunc,
 }
@@ -44,41 +45,144 @@ func modifyUserFunc(cmd *cobra.Command, args []string) error {
 		err = fmt.Errorf("More than one user found")
 		return err
 	}
-	u := res[0]
+	curr := res[0]
 
 	state := cfg{
-		Name:   u.Name,
-		GRR:    u.GRR,
-		Group:  u.GID,
-		Status: u.Status,
-		Shell:  u.Shell,
-		Course: u.Course,
-		Resp:   u.Resp,
-		Expiry: u.Expiry,
+		Name:   curr.Name,
+		GRR:    curr.GRR,
+		Group:  curr.GID,
+		Status: curr.Status,
+		Shell:  curr.Shell,
+		Course: curr.Course,
+		Resp:   curr.Resp,
+		Expiry: curr.Expiry,
 	}
 
-	// Criar arquivo temporário
+	changes, err := promptUserYaml(state)
+
+	err = validateGRR(changes.GRR)
+	if err != nil {
+		return err
+	}
+
+	err = validateGID(changes.Group)
+	if err != nil {
+		return err
+	}
+
+	err = validateStatus(changes.Status)
+	if err != nil {
+		return err
+	}
+
+	err = validateExpiry(changes.Expiry)
+	if err != nil {
+		return err
+	}
+
+	req, err := genRequest(curr, changes)
+	if err != nil {
+		return err
+	}
+
+	l, err := connLDAP()
+	if err != nil {
+		return err
+	}
+	defer l.Close()
+
+	if err := l.Modify(req); err != nil {
+		return fmt.Errorf("Failed to update user attributes: %v", err)
+	}
+
+	fmt.Printf("Changes applied!\n")
+	return nil
+}
+
+func genRequest(curr model.User, changes cfg) (*ldap.ModifyRequest, error) {
+	req := ldap.NewModifyRequest(curr.DN, nil)
+
+	// changed name
+	if curr.Name != changes.Name {
+		req.Replace("cn", []string{changes.Name})
+	}
+
+	// changed status
+	if curr.Status != changes.Status {
+		if changes.Status == "Active" && changes.Shell == "/bin/false" {
+			req.Replace("loginShell", []string{"/bin/bash"})
+		} else if changes.Status == "Active" {
+			req.Replace("loginShell", []string{changes.Shell})
+		} else {
+			req.Replace("loginShell", []string{"/bin/false"})
+		}
+	} else {
+		// only changed shell
+		if curr.Shell != changes.Shell {
+			req.Replace("loginShell", []string{changes.Shell})
+		}
+	}
+
+	// changed base group
+	if curr.GID != changes.Group {
+		groups, err := getGroups()
+		if err != nil {
+			return req, err
+		}
+
+		var gidNumber string
+		for id, gid := range groups {
+			if gid == changes.Group {
+				gidNumber = id
+				break
+			}
+		}
+
+		req.Replace("gidNumber", []string{gidNumber})
+	}
+
+	changed := applyChangesToUser(curr, changes)
+
+	changed = genGecos(changed)
+
+	// changed gecos
+	if curr.Gecos != changed.Gecos {
+		req.Replace("gecos", []string{changed.Gecos})
+	}
+
+	return req, nil
+}
+
+func applyChangesToUser(c model.User, n cfg) model.User {
+	c.GRR = n.GRR
+	c.Name = n.Name
+	c.Resp = n.Resp
+	c.Shell = n.Shell
+	c.Status = n.Status
+	c.Course = n.Course
+	c.Expiry = n.Expiry
+	return c
+}
+
+func promptUserYaml(state cfg) (cfg, error) {
+	var newState cfg
 	tmpFile, err := os.CreateTemp("", "config-*.yaml")
 	if err != nil {
 		err = fmt.Errorf("Error trying to create temp file: %v", err)
-		return err
+		return newState, err
 	}
 	defer os.Remove(tmpFile.Name())
 
-	// Serializar apenas os campos editáveis
 	data, err := yaml.Marshal(state)
 	if err != nil {
-		err = fmt.Errorf("Error serializing the yaml: %v", err)
-		return err
+		return newState, fmt.Errorf("Error serializing the yaml: %v", err)
 	}
 
-	// Escrever no arquivo temporário
 	if err := os.WriteFile(tmpFile.Name(), data, 0644); err != nil {
-		err = fmt.Errorf("Error writing to temp file: %v", err)
-		return err
+		return newState, fmt.Errorf("Error writing to temp file: %v", err)
 	}
 
-	// Abrir no editor
+	// abrir o editor
 	editor := os.Getenv("EDITOR")
 	if editor == "" {
 		editor = "nano"
@@ -90,42 +194,19 @@ func modifyUserFunc(cmd *cobra.Command, args []string) error {
 	comd.Stderr = os.Stderr
 
 	if err := comd.Run(); err != nil {
-		err = fmt.Errorf("Error opening the editor: %v", err)
-		return err
+		return newState, fmt.Errorf("Error opening the editor: %v", err)
 	}
 
-	// Ler o conteúdo editado
 	editedData, err := os.ReadFile(tmpFile.Name())
 	if err != nil {
-		err = fmt.Errorf("Error reading the modified file: %v", err)
-		return err
+		return newState, fmt.Errorf("Error reading the modified file: %v", err)
 	}
 
-	// Desserializar apenas os campos editáveis
-	var newState cfg
 	if err := yaml.Unmarshal(editedData, &newState); err != nil {
-		err = fmt.Errorf("Error de-serializing the yaml: %v", err)
-		return err
+		return newState, fmt.Errorf("Error de-serializing the yaml: %v", err)
 	}
 
-	// Exibir a struct atualizada
-	fmt.Println("New config:")
-	fmt.Printf("%+v\n", newState)
-
-	return nil
-}
-
-// do NOT include ':' in the charset, it WILL break the command
-func genPassword() string {
-	const charset = "@*()=+[];,.?123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"
-	b := make([]byte, 20)
-	if _, err := rand.Read(b); err != nil {
-		panic(err)
-	}
-	for i := range b {
-		b[i] = charset[int(b[i])%len(charset)]
-	}
-	return string(b)
+	return newState, nil
 }
 
 // prints a confirmation prompt, given the operation being performed
diff --git a/cmd/user/reset.go b/cmd/user/reset.go
new file mode 100644
index 0000000000000000000000000000000000000000..a84d944a94bde82206b9ee79c2cab15d53e9a0f6
--- /dev/null
+++ b/cmd/user/reset.go
@@ -0,0 +1,79 @@
+package user
+
+import (
+	"crypto/rand"
+	"fmt"
+	"os/exec"
+
+	"github.com/spf13/cobra"
+)
+
+var ResetCmd = &cobra.Command{
+	Use:   "reset [username]",
+	Short: "Reset the password of a user",
+	Args:  cobra.ExactArgs(1),
+	RunE:  resetPass,
+}
+
+func init() {
+	ResetCmd.Flags().StringP("passwd", "p", "", "User's new password")
+}
+
+func resetPass(cmd *cobra.Command, args []string) error {
+	pass, err := cmd.Flags().GetString("passwd")
+	if err != nil {
+		return err
+	}
+
+	users, err := getUsers()
+	if err != nil {
+		return err
+	}
+
+	login := args[0]
+	res := searchUser(users, false, login, "", "", "", "", "")
+	if len(res) != 1 {
+		return fmt.Errorf("More than one user found")
+	}
+
+	if pass == "" {
+		pass = genPassword()
+	}
+
+	err = modKerberosPassword(login, pass)
+	if err != nil {
+		return err
+	}
+
+	fmt.Printf("Password for user %v has been reset!\n", login)
+	fmt.Printf("New Password: %v\n", pass)
+	return nil
+}
+
+// do NOT include ':' in the charset, it WILL break the command
+func genPassword() string {
+	const charset = "@*()=+[];,.?123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"
+	b := make([]byte, 20)
+	if _, err := rand.Read(b); err != nil {
+		panic(err)
+	}
+	for i := range b {
+		b[i] = charset[int(b[i])%len(charset)]
+	}
+	return string(b)
+}
+
+// command that changes the password >:D
+func modKerberosPassword(login, password string) error {
+	cmd := exec.Command("kadmin.local", "-q",
+		fmt.Sprintf("cpw -pw %s %s", password, login))
+
+	cmd.Stdout = nil
+	cmd.Stderr = nil
+	output, err := cmd.CombinedOutput()
+	if err != nil {
+		return fmt.Errorf("Failed to change password for %s: %v\nOutput: %s", login, err, output)
+	}
+
+	return nil
+}