2024-03-20 19:25:25 +00:00
// Copyright 2024 Matthew Rich <matthewrich.conf@gmail.com>. All rights reserved.
2024-03-22 17:39:06 +00:00
2024-03-20 16:15:27 +00:00
package resource
import (
2024-03-25 20:31:06 +00:00
"context"
"fmt"
"gopkg.in/yaml.v3"
2024-05-06 00:48:54 +00:00
_ "log/slog"
2024-03-25 20:31:06 +00:00
"net/url"
2024-04-05 17:22:17 +00:00
_ "os"
2024-03-25 20:31:06 +00:00
"os/exec"
"os/user"
2024-04-05 17:22:17 +00:00
"io"
2024-05-06 00:48:54 +00:00
"encoding/json"
"errors"
"gitea.rosskeen.house/rosskeen.house/machine"
2024-07-17 08:34:57 +00:00
"strings"
2024-05-14 18:26:05 +00:00
"decl/internal/codec"
2024-07-17 08:34:57 +00:00
"decl/internal/command"
2024-09-19 08:11:57 +00:00
"decl/internal/data"
"decl/internal/folio"
2024-05-06 00:48:54 +00:00
)
type decodeUser User
type UserType string
const (
2024-09-19 08:11:57 +00:00
UserTypeName TypeName = "user"
2024-10-09 22:26:39 +00:00
UserTypeBusyBox UserType = "busybox"
UserTypeShadow UserType = "shadow"
2024-03-20 16:15:27 +00:00
)
2024-07-17 08:34:57 +00:00
var ErrUnsupportedUserType error = errors . New ( "The UserType is not supported on this system" )
var ErrInvalidUserType error = errors . New ( "invalid UserType value" )
2024-10-09 22:26:39 +00:00
var SupportedUserTypes [ ] UserType = [ ] UserType { UserTypeShadow , UserTypeBusyBox }
2024-07-17 08:34:57 +00:00
var SystemUserType UserType = FindSystemUserType ( )
2024-03-20 16:15:27 +00:00
type User struct {
2024-09-19 08:11:57 +00:00
* Common ` json:",inline" yaml:",inline" `
2024-05-09 07:39:45 +00:00
stater machine . Stater ` json:"-" yaml:"-" `
2024-04-03 16:54:50 +00:00
Name string ` json:"name" yaml:"name" `
2024-05-06 00:48:54 +00:00
UID string ` json:"uid,omitempty" yaml:"uid,omitempty" `
2024-04-03 16:54:50 +00:00
Group string ` json:"group,omitempty" yaml:"group,omitempty" `
Groups [ ] string ` json:"groups,omitempty" yaml:"groups,omitempty" `
2024-10-09 22:26:39 +00:00
AppendGroups bool ` json:"appendgroups,omitempty" yaml:"appendgroups,omitempty" `
2024-04-03 16:54:50 +00:00
Gecos string ` json:"gecos,omitempty" yaml:"gecos,omitempty" `
Home string ` json:"home" yaml:"home" `
CreateHome bool ` json:"createhome,omitempty" yaml:"createhome,omitempty" `
Shell string ` json:"shell,omitempty" yaml:"shell,omitempty" `
2024-10-09 22:26:39 +00:00
UserType UserType ` json:"type,omitempty" yaml:"type,omitempty" `
userStatus * user . User ` json:"-" yaml:"-" `
groupStatus * user . Group ` json:"-" yaml:"-" `
2024-03-25 20:31:06 +00:00
2024-07-17 08:34:57 +00:00
CreateCommand * command . Command ` json:"-" yaml:"-" `
ReadCommand * command . Command ` json:"-" yaml:"-" `
UpdateCommand * command . Command ` json:"-" yaml:"-" `
DeleteCommand * command . Command ` json:"-" yaml:"-" `
2024-09-19 08:11:57 +00:00
Resources data . ResourceMapper ` json:"-" yaml:"-" `
2024-03-20 16:15:27 +00:00
}
func NewUser ( ) * User {
2024-10-09 22:26:39 +00:00
u := & User { CreateHome : true , AppendGroups : true , UserType : SystemUserType }
u . Common = NewCommon ( UserTypeName , false )
u . Common . NormalizePath = u . NormalizePath
return u
2024-03-20 16:15:27 +00:00
}
2024-03-22 04:35:17 +00:00
func init ( ) {
2024-10-16 17:26:42 +00:00
folio . DocumentRegistry . ResourceTypes . Register ( [ ] string { "user" } , func ( u * url . URL ) ( user data . Resource ) {
user = NewUser ( )
if u != nil {
if err := folio . CastParsedURI ( u ) . ConstructResource ( user ) ; err != nil {
panic ( err )
}
}
return
2024-03-25 20:31:06 +00:00
} )
2024-03-22 04:35:17 +00:00
}
2024-07-17 08:34:57 +00:00
func FindSystemUserType ( ) UserType {
2024-10-09 22:26:39 +00:00
for _ , userType := range SupportedUserTypes {
2024-07-17 08:34:57 +00:00
c := userType . NewCreateCommand ( )
if c . Exists ( ) {
return userType
}
}
2024-10-09 22:26:39 +00:00
return UserTypeShadow
}
2024-10-16 17:26:42 +00:00
func ( u * User ) Init ( uri data . URIParser ) error {
if uri == nil {
uri = folio . URI ( u . URI ( ) ) . Parse ( )
2024-10-16 18:31:33 +00:00
} else {
u . Name = uri . URL ( ) . Hostname ( )
2024-10-16 17:26:42 +00:00
}
u . UID = LookupUIDString ( uri . URL ( ) . Hostname ( ) )
u . CreateCommand , u . ReadCommand , u . UpdateCommand , u . DeleteCommand = u . UserType . NewCRUD ( )
2024-10-16 17:51:58 +00:00
return u . SetParsedURI ( uri )
2024-10-16 17:26:42 +00:00
}
2024-10-09 22:26:39 +00:00
func ( u * User ) NormalizePath ( ) error {
return nil
2024-07-17 08:34:57 +00:00
}
2024-09-19 08:11:57 +00:00
func ( u * User ) SetResourceMapper ( resources data . ResourceMapper ) {
2024-07-17 08:34:57 +00:00
u . Resources = resources
}
2024-09-19 08:11:57 +00:00
func ( u * User ) Clone ( ) data . Resource {
2024-05-06 00:48:54 +00:00
newu := & User {
2024-09-19 08:11:57 +00:00
Common : u . Common ,
2024-04-19 07:52:10 +00:00
Name : u . Name ,
UID : u . UID ,
Group : u . Group ,
Groups : u . Groups ,
Gecos : u . Gecos ,
Home : u . Home ,
CreateHome : u . CreateHome ,
Shell : u . Shell ,
2024-05-06 00:48:54 +00:00
UserType : u . UserType ,
2024-04-19 07:52:10 +00:00
}
2024-05-06 00:48:54 +00:00
newu . CreateCommand , newu . ReadCommand , newu . UpdateCommand , newu . DeleteCommand = u . UserType . NewCRUD ( )
return newu
}
func ( u * User ) StateMachine ( ) machine . Stater {
2024-05-09 07:39:45 +00:00
if u . stater == nil {
u . stater = StorageMachine ( u )
}
return u . stater
}
func ( u * User ) Notify ( m * machine . EventMessage ) {
ctx := context . Background ( )
switch m . On {
case machine . ENTERSTATEEVENT :
switch m . Dest {
2024-10-09 22:26:39 +00:00
case "start_stat" :
if statErr := u . ReadStat ( ) ; statErr == nil {
if triggerErr := u . StateMachine ( ) . Trigger ( "exists" ) ; triggerErr == nil {
return
}
} else {
if triggerErr := u . StateMachine ( ) . Trigger ( "notexists" ) ; triggerErr == nil {
return
}
}
2024-07-17 08:34:57 +00:00
case "start_read" :
if _ , readErr := u . Read ( ctx ) ; readErr == nil {
if triggerErr := u . StateMachine ( ) . Trigger ( "state_read" ) ; triggerErr == nil {
return
} else {
2024-09-19 08:11:57 +00:00
u . Common . State = "absent"
2024-07-17 08:34:57 +00:00
panic ( triggerErr )
}
} else {
2024-09-19 08:11:57 +00:00
u . Common . State = "absent"
2024-07-17 08:34:57 +00:00
panic ( readErr )
}
2024-10-09 22:26:39 +00:00
case "start_update" :
if updateErr := u . Update ( ctx ) ; updateErr == nil {
if triggerErr := u . stater . Trigger ( "updated" ) ; triggerErr == nil {
return
} else {
u . Common . State = "absent"
}
} else {
u . Common . State = "absent"
panic ( updateErr )
}
2024-07-17 08:34:57 +00:00
case "start_delete" :
if deleteErr := u . Delete ( ctx ) ; deleteErr == nil {
if triggerErr := u . StateMachine ( ) . Trigger ( "deleted" ) ; triggerErr == nil {
return
} else {
2024-09-19 08:11:57 +00:00
u . Common . State = "present"
2024-07-17 08:34:57 +00:00
panic ( triggerErr )
}
} else {
2024-09-19 08:11:57 +00:00
u . Common . State = "present"
2024-07-17 08:34:57 +00:00
panic ( deleteErr )
}
2024-05-09 07:39:45 +00:00
case "start_create" :
2024-05-14 19:53:42 +00:00
if e := u . Create ( ctx ) ; e == nil {
if triggerErr := u . stater . Trigger ( "created" ) ; triggerErr == nil {
return
2024-05-13 05:41:12 +00:00
}
2024-05-09 07:39:45 +00:00
}
2024-09-19 08:11:57 +00:00
u . Common . State = "absent"
2024-07-17 08:34:57 +00:00
case "absent" :
2024-09-19 08:11:57 +00:00
u . Common . State = "absent"
2024-07-17 08:34:57 +00:00
case "present" , "created" , "read" :
2024-09-19 08:11:57 +00:00
u . Common . State = "present"
2024-05-09 07:39:45 +00:00
}
case machine . EXITSTATEEVENT :
}
2024-04-19 07:52:10 +00:00
}
2024-03-20 19:25:25 +00:00
func ( u * User ) URI ( ) string {
2024-03-25 20:31:06 +00:00
return fmt . Sprintf ( "user://%s" , u . Name )
2024-03-20 19:25:25 +00:00
}
func ( u * User ) ResolveId ( ctx context . Context ) string {
2024-10-04 17:35:27 +00:00
if u . config != nil {
2024-10-09 22:26:39 +00:00
if configUser , configUserErr := u . config . GetValue ( "user" ) ; configUserErr == nil && u . Name == "self" {
2024-10-04 17:35:27 +00:00
u . Name = configUser . ( string )
}
}
2024-03-25 20:31:06 +00:00
return LookupUIDString ( u . Name )
2024-03-20 19:25:25 +00:00
}
2024-04-09 19:30:05 +00:00
func ( u * User ) Validate ( ) error {
return fmt . Errorf ( "failed" )
}
2024-03-20 16:15:27 +00:00
func ( u * User ) Apply ( ) error {
2024-07-17 08:34:57 +00:00
ctx := context . Background ( )
2024-09-19 08:11:57 +00:00
switch u . Common . State {
2024-03-25 20:31:06 +00:00
case "present" :
_ , NoUserExists := LookupUID ( u . Name )
if NoUserExists != nil {
2024-05-06 00:48:54 +00:00
cmdErr := u . Create ( context . Background ( ) )
2024-03-25 20:31:06 +00:00
return cmdErr
}
case "absent" :
2024-07-17 08:34:57 +00:00
cmdErr := u . Delete ( ctx )
2024-03-25 20:31:06 +00:00
return cmdErr
}
return nil
2024-03-20 16:15:27 +00:00
}
2024-09-19 08:11:57 +00:00
func ( u * User ) Load ( docData [ ] byte , f codec . Format ) ( err error ) {
err = f . StringDecoder ( string ( docData ) ) . Decode ( u )
return
}
func ( u * User ) LoadReader ( r io . ReadCloser , f codec . Format ) ( err error ) {
err = f . Decoder ( r ) . Decode ( u )
return
}
func ( u * User ) LoadString ( docData string , f codec . Format ) ( err error ) {
err = f . StringDecoder ( docData ) . Decode ( u )
return
2024-04-05 17:22:17 +00:00
}
func ( u * User ) LoadDecl ( yamlResourceDeclaration string ) error {
2024-09-19 08:11:57 +00:00
return u . LoadString ( yamlResourceDeclaration , codec . FormatYaml )
2024-03-20 16:15:27 +00:00
}
2024-03-20 19:25:25 +00:00
func ( u * User ) Type ( ) string { return "user" }
2024-03-22 04:35:17 +00:00
2024-05-06 00:48:54 +00:00
func ( u * User ) Create ( ctx context . Context ) ( error ) {
_ , err := u . CreateCommand . Execute ( u )
if err != nil {
return err
}
_ , e := u . Read ( ctx )
return e
}
2024-10-09 22:26:39 +00:00
func ( u * User ) ReadStat ( ) ( err error ) {
if u . userStatus == nil {
if u . userStatus , err = user . Lookup ( u . Name ) ; err != nil {
return err
}
}
if len ( u . userStatus . Uid ) < 1 {
return ErrResourceStateAbsent
}
u . UID = u . userStatus . Uid
if len ( u . Group ) > 1 {
if u . groupStatus == nil {
if u . groupStatus , err = user . LookupGroup ( u . Group ) ; err != nil {
return err
}
}
if len ( u . groupStatus . Gid ) < 1 {
return ErrResourceStateAbsent
}
}
return
}
2024-03-22 04:35:17 +00:00
func ( u * User ) Read ( ctx context . Context ) ( [ ] byte , error ) {
2024-05-06 00:48:54 +00:00
exErr := u . ReadCommand . Extractor ( nil , u )
if exErr != nil {
2024-09-19 08:11:57 +00:00
u . Common . State = "absent"
2024-03-25 20:31:06 +00:00
}
2024-10-09 22:26:39 +00:00
_ = u . ReadGroups ( )
if yamlDoc , yamlErr := yaml . Marshal ( u ) ; yamlErr != nil {
return yamlDoc , yamlErr
2024-05-06 00:48:54 +00:00
} else {
2024-10-09 22:26:39 +00:00
return yamlDoc , exErr
2024-03-25 20:31:06 +00:00
}
2024-05-06 00:48:54 +00:00
}
2024-03-25 20:31:06 +00:00
2024-10-09 22:26:39 +00:00
func ( u * User ) ReadGroups ( ) ( err error ) {
knownSecondaryGroups := make ( map [ string ] bool )
for _ , secondaryGroupName := range u . Groups {
knownSecondaryGroups [ secondaryGroupName ] = true
}
if u . ReadStat ( ) == nil {
if groups , groupsErr := u . userStatus . GroupIds ( ) ; groupsErr == nil {
for _ , secondaryGroup := range groups {
if readGroup , groupErr := user . LookupGroupId ( secondaryGroup ) ; groupErr == nil {
if ! knownSecondaryGroups [ readGroup . Name ] {
u . Groups = append ( u . Groups , readGroup . Name )
knownSecondaryGroups [ readGroup . Name ] = true
}
} else {
err = groupErr
}
}
} else {
err = groupsErr
}
}
return
}
2024-11-10 18:24:06 +00:00
func ( u * User ) Update ( ctx context . Context ) ( err error ) {
switch u . UserType {
case UserTypeBusyBox :
_ , err = u . CreateCommand . Execute ( u )
if err != nil {
return err
}
}
_ , err = u . UpdateCommand . Execute ( u )
2024-10-09 22:26:39 +00:00
if err != nil {
return err
}
2024-11-10 18:24:06 +00:00
_ , err = u . Read ( ctx )
return
2024-09-19 08:11:57 +00:00
}
2024-07-17 08:34:57 +00:00
func ( u * User ) Delete ( ctx context . Context ) ( error ) {
2024-05-06 00:48:54 +00:00
_ , err := u . DeleteCommand . Execute ( u )
if err != nil {
return err
2024-03-25 20:31:06 +00:00
}
2024-05-06 00:48:54 +00:00
return err
}
func ( u * User ) UnmarshalJSON ( data [ ] byte ) error {
if unmarshalErr := json . Unmarshal ( data , ( * decodeUser ) ( u ) ) ; unmarshalErr != nil {
return unmarshalErr
}
u . CreateCommand , u . ReadCommand , u . UpdateCommand , u . DeleteCommand = u . UserType . NewCRUD ( )
return nil
}
func ( u * User ) UnmarshalYAML ( value * yaml . Node ) error {
if unmarshalErr := value . Decode ( ( * decodeUser ) ( u ) ) ; unmarshalErr != nil {
return unmarshalErr
}
u . CreateCommand , u . ReadCommand , u . UpdateCommand , u . DeleteCommand = u . UserType . NewCRUD ( )
return nil
}
2024-07-17 08:34:57 +00:00
func ( u * UserType ) NewCRUD ( ) ( create * command . Command , read * command . Command , update * command . Command , del * command . Command ) {
2024-05-06 00:48:54 +00:00
switch * u {
2024-10-09 22:26:39 +00:00
case UserTypeShadow :
return NewUserShadowCreateCommand ( ) , NewUserReadCommand ( ) , NewUserShadowUpdateCommand ( ) , NewUserShadowDeleteCommand ( )
case UserTypeBusyBox :
return NewUserBusyBoxCreateCommand ( ) , NewUserReadCommand ( ) , NewUserBusyBoxUpdateCommand ( ) , NewUserBusyBoxDeleteCommand ( )
2024-05-06 00:48:54 +00:00
default :
if _ , addUserPathErr := exec . LookPath ( "adduser" ) ; addUserPathErr == nil {
2024-10-09 22:26:39 +00:00
* u = UserTypeBusyBox
return NewUserBusyBoxCreateCommand ( ) , NewUserReadCommand ( ) , NewUserBusyBoxUpdateCommand ( ) , NewUserBusyBoxDeleteCommand ( )
2024-05-06 00:48:54 +00:00
}
if _ , pathErr := exec . LookPath ( "useradd" ) ; pathErr == nil {
2024-10-09 22:26:39 +00:00
* u = UserTypeShadow
return NewUserShadowCreateCommand ( ) , NewUserReadCommand ( ) , NewUserShadowUpdateCommand ( ) , NewUserShadowDeleteCommand ( )
2024-05-06 00:48:54 +00:00
}
2024-10-09 22:26:39 +00:00
return NewUserShadowCreateCommand ( ) , NewUserReadCommand ( ) , NewUserShadowUpdateCommand ( ) , NewUserShadowDeleteCommand ( )
2024-05-06 00:48:54 +00:00
}
}
2024-10-09 22:26:39 +00:00
func ( u * UserType ) NewReadCommand ( ) ( read * command . Command ) {
return NewUserReadCommand ( )
}
2024-07-17 08:34:57 +00:00
func ( u * UserType ) NewCreateCommand ( ) ( create * command . Command ) {
switch * u {
2024-10-09 22:26:39 +00:00
case UserTypeShadow :
return NewUserShadowCreateCommand ( )
case UserTypeBusyBox :
return NewUserBusyBoxCreateCommand ( )
2024-07-17 08:34:57 +00:00
default :
}
return nil
}
func ( p * UserType ) NewReadUsersCommand ( ) ( * command . Command ) {
return NewReadUsersCommand ( )
}
2024-05-06 00:48:54 +00:00
func ( u * UserType ) UnmarshalValue ( value string ) error {
switch value {
2024-10-09 22:26:39 +00:00
case string ( UserTypeShadow ) , string ( UserTypeBusyBox ) :
2024-05-06 00:48:54 +00:00
* u = UserType ( value )
return nil
default :
2024-07-17 08:34:57 +00:00
return ErrInvalidUserType
2024-03-25 20:31:06 +00:00
}
2024-05-06 00:48:54 +00:00
}
func ( u * UserType ) UnmarshalJSON ( data [ ] byte ) error {
var s string
if unmarshalUserTypeErr := json . Unmarshal ( data , & s ) ; unmarshalUserTypeErr != nil {
return unmarshalUserTypeErr
}
return u . UnmarshalValue ( s )
}
func ( u * UserType ) UnmarshalYAML ( value * yaml . Node ) error {
var s string
if err := value . Decode ( & s ) ; err != nil {
return err
}
return u . UnmarshalValue ( s )
}
2024-07-17 08:34:57 +00:00
func NewReadUsersCommand ( ) * command . Command {
c := command . NewCommand ( )
c . Path = "getent"
c . Args = [ ] command . CommandArg {
command . CommandArg ( "passwd" ) ,
}
c . Extractor = func ( out [ ] byte , target any ) error {
Users := target . ( * [ ] * User )
lines := strings . Split ( strings . TrimSpace ( string ( out ) ) , "\n" )
lineIndex := 0
for _ , line := range lines {
userRecord := strings . Split ( strings . TrimSpace ( line ) , ":" )
if len ( * Users ) <= lineIndex + 1 {
* Users = append ( * Users , NewUser ( ) )
}
u := ( * Users ) [ lineIndex ]
u . Name = userRecord [ 0 ]
u . UID = userRecord [ 2 ]
u . Gecos = userRecord [ 4 ]
u . Home = userRecord [ 5 ]
u . Shell = userRecord [ 6 ]
if readUser , userErr := user . Lookup ( u . Name ) ; userErr == nil {
if groups , groupsErr := readUser . GroupIds ( ) ; groupsErr == nil {
for _ , secondaryGroup := range groups {
if readGroup , groupErr := user . LookupGroupId ( secondaryGroup ) ; groupErr == nil {
u . Groups = append ( u . Groups , readGroup . Name )
}
}
}
}
if readGroup , groupErr := user . LookupGroupId ( userRecord [ 3 ] ) ; groupErr == nil {
u . Group = readGroup . Name
}
2024-09-19 08:11:57 +00:00
u . Common . State = "present"
2024-07-17 08:34:57 +00:00
u . UserType = SystemUserType
lineIndex ++
}
return nil
}
return c
}
2024-10-09 22:26:39 +00:00
func NewUserShadowCreateCommand ( ) * command . Command {
2024-07-17 08:34:57 +00:00
c := command . NewCommand ( )
2024-05-06 00:48:54 +00:00
c . Path = "useradd"
2024-07-17 08:34:57 +00:00
c . Args = [ ] command . CommandArg {
command . CommandArg ( "{{ if .UID }}-u {{ .UID }}{{ end }}" ) ,
command . CommandArg ( "{{ if .Gecos }}-c {{ .Gecos }}{{ end }}" ) ,
command . CommandArg ( "{{ if .Group }}-g {{ .Group }}{{ end }}" ) ,
command . CommandArg ( "{{ if .Groups }}-G {{ range .Groups }}{{ . }},{{- end }}{{ end }}" ) ,
command . CommandArg ( "{{ if .Home }}-d {{ .Home }}{{ end }}" ) ,
command . CommandArg ( "{{ if .CreateHome }}-m{{ else }}-M{{ end }}" ) ,
command . CommandArg ( "{{ .Name }}" ) ,
2024-05-06 00:48:54 +00:00
}
c . Extractor = func ( out [ ] byte , target any ) error {
return nil
}
return c
}
2024-10-09 22:26:39 +00:00
func NewUserBusyBoxCreateCommand ( ) * command . Command {
2024-07-17 08:34:57 +00:00
c := command . NewCommand ( )
2024-05-06 00:48:54 +00:00
c . Path = "adduser"
2024-11-10 18:24:06 +00:00
c . Split = false
2024-07-17 08:34:57 +00:00
c . Args = [ ] command . CommandArg {
2024-11-10 18:24:06 +00:00
command . CommandArg ( "{{ if .UID }}-u{{ end }}" ) ,
command . CommandArg ( "{{ if .UID }}{{ .UID }}{{ end }}" ) ,
command . CommandArg ( "{{ if .Gecos }}-g{{ end }}" ) ,
command . CommandArg ( "{{ if .Gecos }}{{ .Gecos }}{{ end }}" ) ,
command . CommandArg ( "{{ if .Group }}-G{{ end }}" ) ,
command . CommandArg ( "{{ if .Group }}{{ .Group }}{{ end }}" ) ,
command . CommandArg ( "{{ if .Home }}-h{{ end }}" ) ,
command . CommandArg ( "{{ if .Home }}{{ .Home }}{{ end }}" ) ,
2024-07-17 08:34:57 +00:00
command . CommandArg ( "{{ if not .CreateHome }}-H{{ end }}" ) ,
command . CommandArg ( "-D" ) ,
command . CommandArg ( "{{ .Name }}" ) ,
2024-05-06 00:48:54 +00:00
}
c . Extractor = func ( out [ ] byte , target any ) error {
return nil
}
return c
}
2024-03-25 20:31:06 +00:00
2024-07-17 08:34:57 +00:00
func NewUserReadCommand ( ) * command . Command {
c := command . NewCommand ( )
2024-05-06 00:48:54 +00:00
c . Extractor = func ( out [ ] byte , target any ) error {
u := target . ( * User )
2024-09-19 08:11:57 +00:00
u . Common . State = "absent"
2024-05-06 00:48:54 +00:00
var readUser * user . User
var e error
if u . Name != "" {
readUser , e = user . Lookup ( u . Name )
} else {
if u . UID != "" {
readUser , e = user . LookupId ( u . UID )
}
}
if e == nil {
u . Name = readUser . Username
u . UID = readUser . Uid
u . Home = readUser . HomeDir
u . Gecos = readUser . Name
if readGroup , groupErr := user . LookupGroupId ( readUser . Gid ) ; groupErr == nil {
u . Group = readGroup . Name
} else {
return groupErr
}
if u . UID != "" {
2024-09-19 08:11:57 +00:00
u . Common . State = "present"
2024-05-06 00:48:54 +00:00
}
}
return e
}
return c
}
2024-10-09 22:26:39 +00:00
func NewUserBusyBoxUpdateCommand ( ) * command . Command {
c := command . NewCommand ( )
c . Path = "xargs"
c . StdinAvailable = true
c . Input = command . CommandInput ( "{{ if .Groups }}{{ range .Groups }}{{ . }}\n{{ end }}{{ end }}" )
c . Args = [ ] command . CommandArg {
2024-11-10 18:24:06 +00:00
command . CommandArg ( "-r" ) ,
command . CommandArg ( "-IGROUP" ) ,
2024-10-09 22:26:39 +00:00
command . CommandArg ( "adduser" ) ,
command . CommandArg ( "{{ .Name }}" ) ,
2024-11-10 18:24:06 +00:00
command . CommandArg ( "GROUP" ) ,
2024-10-09 22:26:39 +00:00
}
c . Extractor = func ( out [ ] byte , target any ) error {
return nil
}
return c
}
func NewUserShadowUpdateCommand ( ) * command . Command {
c := command . NewCommand ( )
c . Path = "usermod"
c . Args = [ ] command . CommandArg {
command . CommandArg ( "{{ if .UID }}-u {{ .UID }}{{ end }}" ) ,
command . CommandArg ( "{{ if .Gecos }}-c {{ .Gecos }}{{ end }}" ) ,
command . CommandArg ( "{{ if .Group }}-g {{ .groupStatus.Gid }}{{ end }}" ) ,
command . CommandArg ( "{{ if .Home }}-d {{ .Home }}{{ if .CreateHome }} -m{{- end }}{{ end }}" ) ,
command . CommandArg ( "{{ if .Groups }}-G {{- range $i, $g := .Groups -}}{{ if $i }}, {{- end }}{{ . }}{{- end }}{{ if .AppendGroups }} -a{{- end }}{{- end }}" ) ,
command . CommandArg ( "{{ if .Shell }}-s {{ .Shell }}{{ end }}" ) ,
command . CommandArg ( "{{ .Name }}" ) ,
}
c . Extractor = func ( out [ ] byte , target any ) error {
return nil
}
return c
2024-05-06 00:48:54 +00:00
}
2024-10-09 22:26:39 +00:00
func NewUserShadowDeleteCommand ( ) * command . Command {
2024-07-17 08:34:57 +00:00
c := command . NewCommand ( )
2024-05-06 00:48:54 +00:00
c . Path = "userdel"
2024-07-17 08:34:57 +00:00
c . Args = [ ] command . CommandArg {
command . CommandArg ( "{{ .Name }}" ) ,
2024-05-06 00:48:54 +00:00
}
c . Extractor = func ( out [ ] byte , target any ) error {
return nil
}
return c
}
2024-10-09 22:26:39 +00:00
func NewUserBusyBoxDeleteCommand ( ) * command . Command {
2024-07-17 08:34:57 +00:00
c := command . NewCommand ( )
2024-05-06 00:48:54 +00:00
c . Path = "deluser"
2024-07-17 08:34:57 +00:00
c . Args = [ ] command . CommandArg {
command . CommandArg ( "{{ .Name }}" ) ,
2024-05-06 00:48:54 +00:00
}
c . Extractor = func ( out [ ] byte , target any ) error {
return nil
}
return c
2024-03-22 04:35:17 +00:00
}