Skip to content

Commit

Permalink
Added SetRecoveryLock support (micromdm#757)
Browse files Browse the repository at this point in the history
  • Loading branch information
tomaswallentinus authored Jun 16, 2021
1 parent 30ff25e commit 1dfa0a8
Show file tree
Hide file tree
Showing 15 changed files with 1,260 additions and 276 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
## [Unreleased](https://github.com/micromdm/micromdm/compare/v1.8.0...main) TBD

- Added support for SetRecoveryLock and VerifyRecoveryLock (#757)
- Fix SetFirmwarePassword and VerifyFirmwarePassword parameters (#743)
- Command UUID can now be passed in as as a request parameter (#754)
- Update to SCEP v2, switch to Mozilla PKCS7 fork, interface cleanup (#737)
Expand Down
20 changes: 17 additions & 3 deletions mdm/mdm/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ type Command struct {
ManagedApplicationFeedback *ManagedApplicationFeedback
SetFirmwarePassword *SetFirmwarePassword
VerifyFirmwarePassword *VerifyFirmwarePassword
SetRecoveryLock *SetRecoveryLock
VerifyRecoveryLock *VerifyRecoveryLock
SetAutoAdminPassword *SetAutoAdminPassword
ScheduleOSUpdate *ScheduleOSUpdate
ScheduleOSUpdateScan *ScheduleOSUpdateScan
Expand Down Expand Up @@ -248,15 +250,27 @@ type ManagedApplicationFeedback struct {
}

type SetFirmwarePassword struct {
CurrentPassword string `plist:",omitempty" json:"current_password,omitempty"`
NewPassword string `json:"new_password"`
AllowOroms bool `plist:",omitempty" json:"allow_oroms,omitempty"`
CurrentPassword string `plist:",omitempty" json:"current_password,omitempty"`
NewPassword string `json:"new_password"`
RequestRequiresNetworkTether bool `plist:",omitempty" json:"request_requires_network_tether,omitempty"`
AllowOroms bool `plist:",omitempty" json:"allow_oroms,omitempty"`
}

type VerifyFirmwarePassword struct {
Password string `json:"password"`
}

type SetRecoveryLock struct {
CurrentPassword string `plist:",omitempty" json:"current_password,omitempty"`
NewPassword string `json:"new_password"`
RequestRequiresNetworkTether bool `plist:",omitempty" json:"request_requires_network_tether,omitempty"`
AllowOroms bool `plist:",omitempty" json:"allow_oroms,omitempty"`
}

type VerifyRecoveryLock struct {
Password string `json:"password"`
}

type SetAutoAdminPassword struct {
GUID string `plist:",omitempty" json:"guid,omitempty"`
PasswordHash []byte `plist:"passwordHash" json:"password_hash"`
Expand Down
1,242 changes: 975 additions & 267 deletions mdm/mdm/internal/mdmproto/mdm.pb.go

Large diffs are not rendered by default.

14 changes: 14 additions & 0 deletions mdm/mdm/internal/mdmproto/mdm.proto
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ message Command {
RotateFileVaultKey rotate_filevault_key = 35;
InstallEnterpriseApplication install_enterprise_application = 36;
SetBootstrapToken set_bootstrap_token = 37;
SetRecoveryLock set_recovery_lock = 38;
VerifyRecoveryLock verify_recovery_lock = 39;
}
}

Expand Down Expand Up @@ -362,12 +364,24 @@ message SetFirmwarePassword {
string current_password = 1;
string new_password = 2;
bool allow_oroms = 3;
bool request_requires_network_tether = 4;
}

message VerifyFirmwarePassword {
string password = 1;
}

message SetRecoveryLock {
string current_password = 1;
string new_password = 2;
bool allow_oroms = 3;
bool request_requires_network_tether = 4;
}

message VerifyRecoveryLock {
string password = 1;
}

message SetAutoAdminPassword {
string guid = 1;
bytes password_hash = 2;
Expand Down
18 changes: 18 additions & 0 deletions mdm/mdm/marshal_json.go
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,24 @@ func (c *Command) MarshalJSON() ([]byte, error) {
VerifyFirmwarePassword: c.VerifyFirmwarePassword,
}
return json.Marshal(&x)
case "SetRecoveryLock":
var x = struct {
RequestType string `json:"request_type"`
*SetRecoveryLock
}{
RequestType: c.RequestType,
SetRecoveryLock: c.SetRecoveryLock,
}
return json.Marshal(&x)
case "VerifyRecoveryLock":
var x = struct {
RequestType string `json:"request_type"`
*VerifyRecoveryLock
}{
RequestType: c.RequestType,
VerifyRecoveryLock: c.VerifyRecoveryLock,
}
return json.Marshal(&x)
case "SetAutoAdminPassword":
var x = struct {
RequestType string `json:"request_type"`
Expand Down
16 changes: 16 additions & 0 deletions mdm/mdm/marshal_plist.go
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,22 @@ func (c *Command) MarshalPlist() (interface{}, error) {
RequestType: c.RequestType,
VerifyFirmwarePassword: c.VerifyFirmwarePassword,
}, nil
case "SetRecoveryLock":
return &struct {
RequestType string
*SetRecoveryLock
}{
RequestType: c.RequestType,
SetRecoveryLock: c.SetRecoveryLock,
}, nil
case "VerifyRecoveryLock":
return &struct {
RequestType string
*VerifyRecoveryLock
}{
RequestType: c.RequestType,
VerifyRecoveryLock: c.VerifyRecoveryLock,
}, nil
case "SetAutoAdminPassword":
return &struct {
RequestType string
Expand Down
22 changes: 19 additions & 3 deletions mdm/mdm/marshal_proto.go
Original file line number Diff line number Diff line change
Expand Up @@ -326,9 +326,19 @@ func commandToProto(cmd *Command) (*mdmproto.Command, error) {
case "SetFirmwarePassword":
cmdproto.Request = &mdmproto.Command_SetFirmwarePassword{
SetFirmwarePassword: &mdmproto.SetFirmwarePassword{
CurrentPassword: cmd.SetFirmwarePassword.CurrentPassword,
NewPassword: cmd.SetFirmwarePassword.NewPassword,
AllowOroms: cmd.SetFirmwarePassword.AllowOroms,
CurrentPassword: cmd.SetFirmwarePassword.CurrentPassword,
NewPassword: cmd.SetFirmwarePassword.NewPassword,
AllowOroms: cmd.SetFirmwarePassword.AllowOroms,
RequestRequiresNetworkTether: cmd.SetFirmwarePassword.RequestRequiresNetworkTether,
},
}
case "SetRecoveryLock":
cmdproto.Request = &mdmproto.Command_SetRecoveryLock{
SetRecoveryLock: &mdmproto.SetRecoveryLock{
CurrentPassword: cmd.SetRecoveryLock.CurrentPassword,
NewPassword: cmd.SetRecoveryLock.NewPassword,
AllowOroms: cmd.SetRecoveryLock.AllowOroms,
RequestRequiresNetworkTether: cmd.SetRecoveryLock.RequestRequiresNetworkTether,
},
}
case "SetBootstrapToken":
Expand All @@ -343,6 +353,12 @@ func commandToProto(cmd *Command) (*mdmproto.Command, error) {
Password: cmd.VerifyFirmwarePassword.Password,
},
}
case "VerifyRecoveryLock":
cmdproto.Request = &mdmproto.Command_VerifyRecoveryLock{
VerifyRecoveryLock: &mdmproto.VerifyRecoveryLock{
Password: cmd.VerifyRecoveryLock.Password,
},
}
case "SetAutoAdminPassword":
cmdproto.Request = &mdmproto.Command_SetAutoAdminPassword{
SetAutoAdminPassword: &mdmproto.SetAutoAdminPassword{
Expand Down
89 changes: 89 additions & 0 deletions mdm/mdm/mdm_command_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,30 @@ func TestMarshalCommand(t *testing.T) {
},
},
},
{
Command: Command{
RequestType: "SetRecoveryLock",
SetRecoveryLock: &SetRecoveryLock{
CurrentPassword: "test",
},
},
},
{
Command: Command{
RequestType: "SetRecoveryLock",
SetRecoveryLock: &SetRecoveryLock{
NewPassword: "test",
},
},
},
{
Command: Command{
RequestType: "SetRecoveryLock",
VerifyRecoveryLock: &VerifyRecoveryLock{
Password: "test",
},
},
},
}
for _, tt := range tests {
t.Run(tt.Command.RequestType+"_json", func(t *testing.T) {
Expand Down Expand Up @@ -356,6 +380,71 @@ func TestEndToEnd(t *testing.T) {
}
},
},
{
name: "SetRecoveryLock_NoNewPassword",
requestBytes: []byte(
`{"request_type":"SetRecoveryLock","current_password":"test"}`,
),
testFn: func(t *testing.T, parts endToEndParts) {
needToSee := [][]byte{
[]byte(`CurrentPassword`),
[]byte(`test`),
[]byte(`NewPassword`),
}
for _, b := range needToSee {
if !bytes.Contains(parts.plistData, b) {
t.Error(fmt.Sprintf("marshaled plist does not contain required bytes: '%s'", string(b)))
}
}
},
},
{
name: "SetRecoveryLock_NewPassword",
requestBytes: []byte(
`{"request_type":"SetRecoveryLock","new_password":"test"}`,
),
testFn: func(t *testing.T, parts endToEndParts) {
needToSee := [][]byte{
[]byte(`NewPassword`),
[]byte(`test`),
}
for _, b := range needToSee {
if !bytes.Contains(parts.plistData, b) {
t.Error(fmt.Sprintf("marshaled plist does not contain required bytes: '%s'", string(b)))
}
}
},
},

{
name: "VerifyRecoveryLock",
requestBytes: []byte(
`{"request_type":"VerifyRecoveryLock","password":"test"}`,
),
testFn: func(t *testing.T, parts endToEndParts) {
needToSee := [][]byte{
[]byte(`Password`),
[]byte(`test`),
}
for _, b := range needToSee {
if !bytes.Contains(parts.plistData, b) {
t.Error(fmt.Sprintf("marshaled plist does not contain required bytes: '%s'", string(b)))
}
}
},
},

{
name: "Set Command UUID",
requestBytes: []byte(
`{"request_type":"VerifyRecoveryLock","password":"test","command_uuid":"this-uuid-should-be-used"}`,
),
testFn: func(t *testing.T, parts endToEndParts) {
if parts.payload.CommandUUID != "this-uuid-should-be-used" {
t.Error("CommandUUID should be set to request payload's command_uuid")
}
},
},
}

for _, tt := range tests {
Expand Down
14 changes: 14 additions & 0 deletions mdm/mdm/unmarshal_json.go
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,20 @@ func (c *Command) UnmarshalJSON(data []byte) error {
}
c.VerifyFirmwarePassword = &payload
return nil
case "SetRecoveryLock":
var payload SetRecoveryLock
if err := json.Unmarshal(data, &payload); err != nil {
return errors.Wrapf(err, "mdm: unmarshal %s command json", c.RequestType)
}
c.SetRecoveryLock = &payload
return nil
case "VerifyRecoveryLock":
var payload VerifyRecoveryLock
if err := json.Unmarshal(data, &payload); err != nil {
return errors.Wrapf(err, "mdm: unmarshal %s command json", c.RequestType)
}
c.VerifyRecoveryLock = &payload
return nil
case "SetAutoAdminPassword":
var payload SetAutoAdminPassword
if err := json.Unmarshal(data, &payload); err != nil {
Expand Down
14 changes: 14 additions & 0 deletions mdm/mdm/unmarshal_plist.go
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,20 @@ func (c *Command) UnmarshalPlist(unmarshal func(i interface{}) error) error {
}
c.VerifyFirmwarePassword = &payload
return nil
case "SetRecoveryLock":
var payload SetRecoveryLock
if err := unmarshal(&payload); err != nil {
return errors.Wrapf(err, "mdm: unmarshal %s command plist", requestType.RequestType)
}
c.SetRecoveryLock = &payload
return nil
case "VerifyRecoveryLock":
var payload VerifyRecoveryLock
if err := unmarshal(&payload); err != nil {
return errors.Wrapf(err, "mdm: unmarshal %s command plist", requestType.RequestType)
}
c.VerifyRecoveryLock = &payload
return nil
case "SetAutoAdminPassword":
var payload SetAutoAdminPassword
if err := unmarshal(&payload); err != nil {
Expand Down
20 changes: 17 additions & 3 deletions mdm/mdm/unmarshal_proto.go
Original file line number Diff line number Diff line change
Expand Up @@ -296,20 +296,34 @@ func protoToCommand(pb *mdmproto.Command) *Command {
case "SetFirmwarePassword":
pbc := pb.GetSetFirmwarePassword()
cmd.SetFirmwarePassword = &SetFirmwarePassword{
CurrentPassword: pbc.GetCurrentPassword(),
NewPassword: pbc.GetNewPassword(),
AllowOroms: pbc.GetAllowOroms(),
CurrentPassword: pbc.GetCurrentPassword(),
NewPassword: pbc.GetNewPassword(),
AllowOroms: pbc.GetAllowOroms(),
RequestRequiresNetworkTether: pbc.GetRequestRequiresNetworkTether(),
}
case "SetBootstrapToken":
pbc := pb.GetSetBootstrapToken()
cmd.SetBootstrapToken = &SetBootstrapToken{
BootstrapToken: pbc.GetBootstrapToken(),
}
case "SetRecoveryLock":
pbc := pb.GetSetRecoveryLock()
cmd.SetRecoveryLock = &SetRecoveryLock{
CurrentPassword: pbc.GetCurrentPassword(),
NewPassword: pbc.GetNewPassword(),
AllowOroms: pbc.GetAllowOroms(),
RequestRequiresNetworkTether: pbc.GetRequestRequiresNetworkTether(),
}
case "VerifyFirmwarePassword":
pbc := pb.GetVerifyFirmwarePassword()
cmd.VerifyFirmwarePassword = &VerifyFirmwarePassword{
Password: pbc.GetPassword(),
}
case "VerifyRecoveryLock":
pbc := pb.GetVerifyRecoveryLock()
cmd.VerifyRecoveryLock = &VerifyRecoveryLock{
Password: pbc.GetPassword(),
}
case "SetAutoAdminPassword":
pbc := pb.GetSetAutoAdminPassword()
cmd.SetAutoAdminPassword = &SetAutoAdminPassword{
Expand Down
18 changes: 18 additions & 0 deletions tools/api/commands/set_firmware_password
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/bin/bash
source $MICROMDM_ENV_PATH
endpoint="v1/commands"
jq -n \
--arg request_type "SetFirmwarePassword" \
--arg udid "$1" \
--arg current_password $2 \
--arg new_password $3 \
--arg request_requires_network_tether $4 \
--arg allow_oroms $5 \
'.udid = $udid
|.current_password = $current_password
|.new_password = $new_password
|.request_requires_network_tether = $request_requires_network_tether
|.allow_oroms = $allow_oroms
|.request_type = $request_type
'|\
curl $CURL_OPTS -K <(cat <<< "-u micromdm:$API_TOKEN") "$SERVER_URL/$endpoint" -d@-
18 changes: 18 additions & 0 deletions tools/api/commands/set_recovery_lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/bin/bash
source $MICROMDM_ENV_PATH
endpoint="v1/commands"
jq -n \
--arg request_type "SetRecoveryLock" \
--arg udid "$1" \
--arg current_password $2 \
--arg new_password $3 \
--arg request_requires_network_tether $4 \
--arg allow_oroms $5 \
'.udid = $udid
|.current_password = $current_password
|.new_password = $new_password
|.request_requires_network_tether = $request_requires_network_tether
|.allow_oroms = $allow_oroms
|.request_type = $request_type
'|\
curl $CURL_OPTS -K <(cat <<< "-u micromdm:$API_TOKEN") "$SERVER_URL/$endpoint" -d@-
Loading

0 comments on commit 1dfa0a8

Please sign in to comment.