From 0b8bb797b4951b853077f69e6bc88d20d53826c6 Mon Sep 17 00:00:00 2001 From: Lucas Rodriguez Date: Tue, 26 Jul 2022 10:51:14 -0300 Subject: [PATCH 01/11] Export the MySQL schema as a variable --- storage/mysql/mysql.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/storage/mysql/mysql.go b/storage/mysql/mysql.go index 398f867..166dfac 100644 --- a/storage/mysql/mysql.go +++ b/storage/mysql/mysql.go @@ -4,6 +4,7 @@ package mysql import ( "context" "database/sql" + _ "embed" "errors" "fmt" @@ -13,6 +14,11 @@ import ( "github.com/micromdm/nanomdm/mdm" ) +// Schema holds the schema for the NanoMDM MySQL storage. +// +//go:embed schema.sql +var Schema string + var ErrNoCert = errors.New("no certificate in MDM Request") type MySQLStorage struct { From 8df23dee99e9f322a9696ae9a145bcc0b8af69af Mon Sep 17 00:00:00 2001 From: Lucas Rodriguez Date: Tue, 26 Jul 2022 11:40:12 -0300 Subject: [PATCH 02/11] Bump go to go1.17 --- go.mod | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 26c082f..ecc6b48 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/micromdm/nanomdm -go 1.15 +go 1.17 require ( github.com/RobotsAndPencils/buford v0.14.0 @@ -9,3 +9,8 @@ require ( github.com/lib/pq v1.10.6 go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352 ) + +require ( + golang.org/x/net v0.0.0-20191009170851-d66e71096ffb // indirect + golang.org/x/text v0.3.0 // indirect +) From c245c96de5dc4919adc79f0b39ebcd165ed17f23 Mon Sep 17 00:00:00 2001 From: Lucas Rodriguez Date: Fri, 19 Aug 2022 18:18:00 -0300 Subject: [PATCH 03/11] Export pgsql's schema as Go var --- storage/pgsql/postgresql.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/storage/pgsql/postgresql.go b/storage/pgsql/postgresql.go index 12e0ae8..a6fd191 100644 --- a/storage/pgsql/postgresql.go +++ b/storage/pgsql/postgresql.go @@ -4,6 +4,7 @@ package pgsql import ( "context" "database/sql" + _ "embed" "errors" "fmt" @@ -13,6 +14,11 @@ import ( "github.com/micromdm/nanomdm/mdm" ) +// Schema holds the schema for the NanoMDM PostgresSQL storage. +// +//go:embed schema.sql +var Schema string + var ErrNoCert = errors.New("no certificate in MDM Request") type PgSQLStorage struct { From 15d7f85f0ea7711f2c2cc7a9010a3f401411a410 Mon Sep 17 00:00:00 2001 From: Michal Nicpon Date: Thu, 15 Sep 2022 16:25:22 -0600 Subject: [PATCH 04/11] add table prefix --- storage/mysql/bstoken.go | 4 ++-- storage/mysql/certauth.go | 8 ++++---- storage/mysql/migrate.go | 4 ++-- storage/mysql/mysql.go | 20 ++++++++++---------- storage/mysql/push.go | 2 +- storage/mysql/pushcert.go | 6 +++--- storage/mysql/queue.go | 30 +++++++++++++++--------------- storage/mysql/schema.sql | 38 +++++++++++++++++++------------------- 8 files changed, 56 insertions(+), 56 deletions(-) diff --git a/storage/mysql/bstoken.go b/storage/mysql/bstoken.go index f21e150..22c1e7b 100644 --- a/storage/mysql/bstoken.go +++ b/storage/mysql/bstoken.go @@ -7,7 +7,7 @@ import ( func (s *MySQLStorage) StoreBootstrapToken(r *mdm.Request, msg *mdm.SetBootstrapToken) error { _, err := s.db.ExecContext( r.Context, - `UPDATE devices SET bootstrap_token_b64 = ?, bootstrap_token_at = CURRENT_TIMESTAMP WHERE id = ? LIMIT 1;`, + `UPDATE devices SET nano_bootstrap_token_b64 = ?, bootstrap_token_at = CURRENT_TIMESTAMP WHERE id = ? LIMIT 1;`, nullEmptyString(msg.BootstrapToken.BootstrapToken.String()), r.ID, ) @@ -21,7 +21,7 @@ func (s *MySQLStorage) RetrieveBootstrapToken(r *mdm.Request, _ *mdm.GetBootstra var tokenB64 string err := s.db.QueryRowContext( r.Context, - `SELECT bootstrap_token_b64 FROM devices WHERE id = ?;`, + `SELECT nano_bootstrap_token_b64 FROM devices WHERE id = ?;`, r.ID, ).Scan(&tokenB64) if err != nil { diff --git a/storage/mysql/certauth.go b/storage/mysql/certauth.go index cc64c0e..c476972 100644 --- a/storage/mysql/certauth.go +++ b/storage/mysql/certauth.go @@ -17,7 +17,7 @@ func (s *MySQLStorage) queryRowContextRowExists(ctx context.Context, query strin func (s *MySQLStorage) EnrollmentHasCertHash(r *mdm.Request, _ string) (bool, error) { return s.queryRowContextRowExists( r.Context, - `SELECT COUNT(*) FROM cert_auth_associations WHERE id = ?;`, + `SELECT COUNT(*) FROM nano_cert_auth_associations WHERE id = ?;`, r.ID, ) } @@ -25,7 +25,7 @@ func (s *MySQLStorage) EnrollmentHasCertHash(r *mdm.Request, _ string) (bool, er func (s *MySQLStorage) HasCertHash(r *mdm.Request, hash string) (bool, error) { return s.queryRowContextRowExists( r.Context, - `SELECT COUNT(*) FROM cert_auth_associations WHERE sha256 = ?;`, + `SELECT COUNT(*) FROM nano_cert_auth_associations WHERE sha256 = ?;`, strings.ToLower(hash), ) } @@ -33,7 +33,7 @@ func (s *MySQLStorage) HasCertHash(r *mdm.Request, hash string) (bool, error) { func (s *MySQLStorage) IsCertHashAssociated(r *mdm.Request, hash string) (bool, error) { return s.queryRowContextRowExists( r.Context, - `SELECT COUNT(*) FROM cert_auth_associations WHERE id = ? AND sha256 = ?;`, + `SELECT COUNT(*) FROM nano_cert_auth_associations WHERE id = ? AND sha256 = ?;`, r.ID, strings.ToLower(hash), ) } @@ -41,7 +41,7 @@ func (s *MySQLStorage) IsCertHashAssociated(r *mdm.Request, hash string) (bool, func (s *MySQLStorage) AssociateCertHash(r *mdm.Request, hash string) error { _, err := s.db.ExecContext( r.Context, ` -INSERT INTO cert_auth_associations (id, sha256) VALUES (?, ?) AS new +INSERT INTO nano_cert_auth_associations (id, sha256) VALUES (?, ?) AS new ON DUPLICATE KEY UPDATE sha256 = new.sha256;`, r.ID, diff --git a/storage/mysql/migrate.go b/storage/mysql/migrate.go index 1e19804..3de6e38 100644 --- a/storage/mysql/migrate.go +++ b/storage/mysql/migrate.go @@ -11,7 +11,7 @@ func (s *MySQLStorage) RetrieveMigrationCheckins(ctx context.Context, c chan<- i // then we should synthesize a TokenUpdate to transfer it over. deviceRows, err := s.db.QueryContext( ctx, - `SELECT authenticate, token_update FROM devices;`, + `SELECT authenticate, token_update FROM nano_devices;`, ) if err != nil { return err @@ -36,7 +36,7 @@ func (s *MySQLStorage) RetrieveMigrationCheckins(ctx context.Context, c chan<- i } userRows, err := s.db.QueryContext( ctx, - `SELECT token_update FROM users;`, + `SELECT token_update FROM nano_users;`, ) if err != nil { return err diff --git a/storage/mysql/mysql.go b/storage/mysql/mysql.go index 166dfac..fc9e3b2 100644 --- a/storage/mysql/mysql.go +++ b/storage/mysql/mysql.go @@ -100,7 +100,7 @@ func (s *MySQLStorage) StoreAuthenticate(r *mdm.Request, msg *mdm.Authenticate) } _, err := s.db.ExecContext( r.Context, ` -INSERT INTO devices +INSERT INTO nano_devices (id, identity_cert, serial_number, authenticate, authenticate_at) VALUES (?, ?, ?, ?, CURRENT_TIMESTAMP) AS new @@ -116,7 +116,7 @@ UPDATE } func (s *MySQLStorage) storeDeviceTokenUpdate(r *mdm.Request, msg *mdm.TokenUpdate) error { - query := `UPDATE devices SET token_update = ?, token_update_at = CURRENT_TIMESTAMP` + query := `UPDATE nano_devices SET token_update = ?, token_update_at = CURRENT_TIMESTAMP` args := []interface{}{msg.Raw} // separately store the Unlock Token per MDM spec if len(msg.UnlockToken) > 0 { @@ -139,7 +139,7 @@ func (s *MySQLStorage) storeUserTokenUpdate(r *mdm.Request, msg *mdm.TokenUpdate } _, err := s.db.ExecContext( r.Context, ` -INSERT INTO users +INSERT INTO nano_users (id, device_id, user_short_name, user_long_name, token_update, token_update_at) VALUES (?, ?, ?, ?, ?, CURRENT_TIMESTAMP) AS new @@ -179,7 +179,7 @@ func (s *MySQLStorage) StoreTokenUpdate(r *mdm.Request, msg *mdm.TokenUpdate) er } _, err = s.db.ExecContext( r.Context, ` -INSERT INTO enrollments +INSERT INTO nano_enrollments (id, device_id, user_id, type, topic, push_magic, token_hex, last_seen_at, token_update_tally) VALUES (?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP, 1) AS new @@ -191,9 +191,9 @@ UPDATE topic = new.topic, push_magic = new.push_magic, token_hex = new.token_hex, - enabled = 1, - last_seen_at = CURRENT_TIMESTAMP, - enrollments.token_update_tally = enrollments.token_update_tally + 1;`, + enabled = 1, + last_seen_at = CURRENT_TIMESTAMP, + token_update_tally = nano_enrollments.token_update_tally + 1;`, r.ID, deviceId, nullEmptyString(userId), @@ -226,7 +226,7 @@ func (s *MySQLStorage) StoreUserAuthenticate(r *mdm.Request, msg *mdm.UserAuthen } _, err := s.db.ExecContext( r.Context, ` -INSERT INTO users +INSERT INTO nano_users (id, device_id, user_short_name, user_long_name, `+colName+`, `+colAtName+`) VALUES (?, ?, ?, ?, ?, CURRENT_TIMESTAMP) AS new @@ -256,7 +256,7 @@ func (s *MySQLStorage) Disable(r *mdm.Request) error { } _, err := s.db.ExecContext( r.Context, - `UPDATE enrollments SET enabled = 0, token_update_tally = 0, last_seen_at = CURRENT_TIMESTAMP WHERE device_id = ? AND enabled = 1;`, + `UPDATE nano_enrollments SET enabled = 0, token_update_tally = 0, last_seen_at = CURRENT_TIMESTAMP WHERE device_id = ? AND enabled = 1;`, r.ID, ) return err @@ -265,7 +265,7 @@ func (s *MySQLStorage) Disable(r *mdm.Request) error { func (s *MySQLStorage) updateLastSeen(r *mdm.Request) (err error) { _, err = s.db.ExecContext( r.Context, - `UPDATE enrollments SET last_seen_at = CURRENT_TIMESTAMP WHERE id = ?`, + `UPDATE nano_enrollments SET last_seen_at = CURRENT_TIMESTAMP WHERE id = ?`, r.ID, ) if err != nil { diff --git a/storage/mysql/push.go b/storage/mysql/push.go index 9fc106c..1383949 100644 --- a/storage/mysql/push.go +++ b/storage/mysql/push.go @@ -23,7 +23,7 @@ func (s *MySQLStorage) RetrievePushInfo(ctx context.Context, ids []string) (map[ } rows, err := s.db.QueryContext( ctx, - `SELECT id, topic, push_magic, token_hex FROM enrollments WHERE id IN (`+qs+`);`, + `SELECT id, topic, push_magic, token_hex FROM nano_enrollments WHERE id IN (`+qs+`);`, args..., ) if err != nil { diff --git a/storage/mysql/pushcert.go b/storage/mysql/pushcert.go index aedd364..c6346ce 100644 --- a/storage/mysql/pushcert.go +++ b/storage/mysql/pushcert.go @@ -13,7 +13,7 @@ func (s *MySQLStorage) RetrievePushCert(ctx context.Context, topic string) (*tls var staleToken int err := s.db.QueryRowContext( ctx, - `SELECT cert_pem, key_pem, stale_token FROM push_certs WHERE topic = ?;`, + `SELECT cert_pem, key_pem, stale_token FROM nano_push_certs WHERE topic = ?;`, topic, ).Scan(&certPEM, &keyPEM, &staleToken) if err != nil { @@ -34,7 +34,7 @@ func (s *MySQLStorage) IsPushCertStale(ctx context.Context, topic, staleToken st } err = s.db.QueryRowContext( ctx, - `SELECT stale_token FROM push_certs WHERE topic = ?;`, + `SELECT stale_token FROM nano_push_certs WHERE topic = ?;`, topic, ).Scan(&dbStaleToken) return dbStaleToken != staleTokenInt, err @@ -47,7 +47,7 @@ func (s *MySQLStorage) StorePushCert(ctx context.Context, pemCert, pemKey []byte } _, err = s.db.ExecContext( ctx, ` -INSERT INTO push_certs +INSERT INTO nano_push_certs (topic, cert_pem, key_pem, stale_token) VALUES (?, ?, ?, 0) AS new diff --git a/storage/mysql/queue.go b/storage/mysql/queue.go index 51acf68..2c86ff4 100644 --- a/storage/mysql/queue.go +++ b/storage/mysql/queue.go @@ -16,13 +16,13 @@ func enqueue(ctx context.Context, tx *sql.Tx, ids []string, cmd *mdm.Command) er } _, err := tx.ExecContext( ctx, - `INSERT INTO commands (command_uuid, request_type, command) VALUES (?, ?, ?);`, + `INSERT INTO nano_commands (command_uuid, request_type, command) VALUES (?, ?, ?);`, cmd.CommandUUID, cmd.Command.RequestType, cmd.Raw, ) if err != nil { return err } - query := `INSERT INTO enrollment_queue (id, command_uuid) VALUES (?, ?)` + query := `INSERT INTO nano_enrollment_queue (id, command_uuid) VALUES (?, ?)` query += strings.Repeat(", (?, ?)", len(ids)-1) args := make([]interface{}, len(ids)*2) for i, id := range ids { @@ -54,8 +54,8 @@ func (s *MySQLStorage) deleteCommand(ctx context.Context, tx *sql.Tx, id, uuid s DELETE q, r FROM - enrollment_queue AS q - LEFT JOIN command_results AS r + nano_enrollment_queue AS q + LEFT JOIN nano_command_results AS r ON q.command_uuid = r.command_uuid AND r.id = q.id WHERE q.id = ? AND q.command_uuid = ?; @@ -72,10 +72,10 @@ WHERE DELETE c FROM - commands AS c - LEFT JOIN enrollment_queue AS q + nano_commands AS c + LEFT JOIN nano_enrollment_queue AS q ON q.command_uuid = c.command_uuid - LEFT JOIN command_results AS r + LEFT JOIN nano_command_results AS r ON r.command_uuid = c.command_uuid WHERE c.command_uuid = ? AND @@ -117,11 +117,11 @@ func (s *MySQLStorage) StoreCommandReport(r *mdm.Request, result *mdm.CommandRes // not_now_at field. thus it will only represent the first NotNow. if result.Status == "NotNow" { notNowConstants = "CURRENT_TIMESTAMP, 1" - notNowBumpTallySQL = `, command_results.not_now_tally = command_results.not_now_tally + 1` + notNowBumpTallySQL = `, nano_command_results.not_now_tally = nano_command_results.not_now_tally + 1` } _, err := s.db.ExecContext( r.Context, ` -INSERT INTO command_results +INSERT INTO nano_command_results (id, command_uuid, status, result, not_now_at, not_now_tally) VALUES (?, ?, ?, ?, `+notNowConstants+`) AS new @@ -145,7 +145,7 @@ func (s *MySQLStorage) RetrieveNextCommand(r *mdm.Request, skipNotNow bool) (*md command := new(mdm.Command) err := s.db.QueryRowContext( r.Context, - `SELECT command_uuid, request_type, command FROM view_queue WHERE id = ? AND active = 1 AND `+statusWhere+` LIMIT 1;`, + `SELECT command_uuid, request_type, command FROM nano_view_queue WHERE id = ? AND active = 1 AND `+statusWhere+` LIMIT 1;`, r.ID, ).Scan(&command.CommandUUID, &command.Command.RequestType, &command.Raw) if err != nil { @@ -169,12 +169,12 @@ func (s *MySQLStorage) ClearQueue(r *mdm.Request) error { r.Context, ` UPDATE - enrollment_queue AS q - INNER JOIN enrollments AS e - ON q.id = e.id - INNER JOIN commands AS c + nano_enrollment_queue AS q + INNER JOIN nano_enrollments AS e + ON q.id = e.id + INNER JOIN nano_commands AS c ON q.command_uuid = c.command_uuid - LEFT JOIN command_results r + LEFT JOIN nano_command_results r ON r.command_uuid = q.command_uuid AND r.id = q.id SET q.active = 0 diff --git a/storage/mysql/schema.sql b/storage/mysql/schema.sql index e870875..4260af3 100644 --- a/storage/mysql/schema.sql +++ b/storage/mysql/schema.sql @@ -1,4 +1,4 @@ -CREATE TABLE devices ( +CREATE TABLE nano_devices ( id VARCHAR(255) NOT NULL, identity_cert TEXT NULL, @@ -40,7 +40,7 @@ CREATE TABLE devices ( ); -CREATE TABLE users ( +CREATE TABLE nano_users ( id VARCHAR(255) NOT NULL, device_id VARCHAR(255) NOT NULL, @@ -63,7 +63,7 @@ CREATE TABLE users ( PRIMARY KEY (id, device_id), FOREIGN KEY (device_id) - REFERENCES devices (id) + REFERENCES nano_devices (id) ON DELETE CASCADE ON UPDATE CASCADE, CHECK (user_short_name IS NULL OR user_short_name != ''), @@ -79,7 +79,7 @@ CREATE TABLE users ( /* This table represents enrollments which are an amalgamation of * both device and user enrollments. */ -CREATE TABLE enrollments ( +CREATE TABLE nano_enrollments ( -- The enrollment ID of this enrollment id VARCHAR(255) NOT NULL, -- The "device" enrollment ID of this enrollment. This will be @@ -111,11 +111,11 @@ CREATE TABLE enrollments ( CHECK (id != ''), FOREIGN KEY (device_id) - REFERENCES devices (id) + REFERENCES nano_devices (id) ON DELETE CASCADE ON UPDATE CASCADE, FOREIGN KEY (user_id) - REFERENCES users (id) + REFERENCES nano_users (id) ON DELETE CASCADE ON UPDATE CASCADE, UNIQUE (user_id), @@ -132,7 +132,7 @@ CREATE TABLE enrollments ( * a device, a result (response), etc. Joining other tables is required * for more context. */ -CREATE TABLE commands ( +CREATE TABLE nano_commands ( command_uuid VARCHAR(127) NOT NULL, request_type VARCHAR(63) NOT NULL, -- Raw command Plist @@ -160,7 +160,7 @@ CREATE TABLE commands ( * means we lose insight into when NotNows happen once a command is * Acknowledged. */ -CREATE TABLE command_results ( +CREATE TABLE nano_command_results ( id VARCHAR(255) NOT NULL, command_uuid VARCHAR(127) NOT NULL, status VARCHAR(31) NOT NULL, @@ -175,11 +175,11 @@ CREATE TABLE command_results ( PRIMARY KEY (id, command_uuid), FOREIGN KEY (id) - REFERENCES enrollments (id) + REFERENCES nano_enrollments (id) ON DELETE CASCADE ON UPDATE CASCADE, FOREIGN KEY (command_uuid) - REFERENCES commands (command_uuid) + REFERENCES nano_commands (command_uuid) ON DELETE CASCADE ON UPDATE CASCADE, -- considering not enforcing these CHECKs to make sure we always @@ -190,7 +190,7 @@ CREATE TABLE command_results ( ); -CREATE TABLE enrollment_queue ( +CREATE TABLE nano_enrollment_queue ( id VARCHAR(255) NOT NULL, command_uuid VARCHAR(127) NOT NULL, @@ -203,11 +203,11 @@ CREATE TABLE enrollment_queue ( PRIMARY KEY (id, command_uuid), FOREIGN KEY (id) - REFERENCES enrollments (id) + REFERENCES nano_enrollments (id) ON DELETE CASCADE ON UPDATE CASCADE, FOREIGN KEY (command_uuid) - REFERENCES commands (command_uuid) + REFERENCES nano_commands (command_uuid) ON DELETE CASCADE ON UPDATE CASCADE ); @@ -216,7 +216,7 @@ CREATE TABLE enrollment_queue ( * those that have received no result yet) will have a status of NULL * (due to the LEFT JOIN against results). */ -CREATE OR REPLACE VIEW view_queue AS +CREATE OR REPLACE VIEW nano_view_queue AS SELECT q.id, q.created_at, @@ -229,19 +229,19 @@ SELECT r.status, r.result FROM - enrollment_queue AS q + nano_enrollment_queue AS q - INNER JOIN commands AS c + INNER JOIN nano_commands AS c ON q.command_uuid = c.command_uuid - LEFT JOIN command_results r + LEFT JOIN nano_command_results r ON r.command_uuid = q.command_uuid AND r.id = q.id ORDER BY q.priority DESC, q.created_at; -CREATE TABLE push_certs ( +CREATE TABLE nano_push_certs ( topic VARCHAR(255) NOT NULL, cert_pem TEXT NOT NULL, @@ -266,7 +266,7 @@ CREATE TABLE push_certs ( ); -CREATE TABLE cert_auth_associations ( +CREATE TABLE nano_cert_auth_associations ( id VARCHAR(255) NOT NULL, sha256 CHAR(64) NOT NULL, From fdba75c813ef0c99897e2f5b2c670a40fcabc639 Mon Sep 17 00:00:00 2001 From: Michal Nicpon Date: Mon, 19 Sep 2022 13:27:59 -0600 Subject: [PATCH 05/11] fix table names bstoken --- storage/mysql/bstoken.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/storage/mysql/bstoken.go b/storage/mysql/bstoken.go index 22c1e7b..700f4ad 100644 --- a/storage/mysql/bstoken.go +++ b/storage/mysql/bstoken.go @@ -7,7 +7,7 @@ import ( func (s *MySQLStorage) StoreBootstrapToken(r *mdm.Request, msg *mdm.SetBootstrapToken) error { _, err := s.db.ExecContext( r.Context, - `UPDATE devices SET nano_bootstrap_token_b64 = ?, bootstrap_token_at = CURRENT_TIMESTAMP WHERE id = ? LIMIT 1;`, + `UPDATE nano_devices SET bootstrap_token_b64 = ?, bootstrap_token_at = CURRENT_TIMESTAMP WHERE id = ? LIMIT 1;`, nullEmptyString(msg.BootstrapToken.BootstrapToken.String()), r.ID, ) @@ -21,7 +21,7 @@ func (s *MySQLStorage) RetrieveBootstrapToken(r *mdm.Request, _ *mdm.GetBootstra var tokenB64 string err := s.db.QueryRowContext( r.Context, - `SELECT nano_bootstrap_token_b64 FROM devices WHERE id = ?;`, + `SELECT bootstrap_token_b64 FROM nano_devices WHERE id = ?;`, r.ID, ).Scan(&tokenB64) if err != nil { From 2d27d243783d46d53e7ffe0897483327396aaf44 Mon Sep 17 00:00:00 2001 From: Lucas Rodriguez Date: Tue, 4 Oct 2022 08:52:38 -0300 Subject: [PATCH 06/11] Add missing prefix --- storage/mysql/mysql.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/mysql/mysql.go b/storage/mysql/mysql.go index fc9e3b2..39301d9 100644 --- a/storage/mysql/mysql.go +++ b/storage/mysql/mysql.go @@ -209,7 +209,7 @@ func (s *MySQLStorage) RetrieveTokenUpdateTally(ctx context.Context, id string) var tally int err := s.db.QueryRowContext( ctx, - `SELECT token_update_tally FROM enrollments WHERE id = ?;`, + `SELECT token_update_tally FROM nano_enrollments WHERE id = ?;`, id, ).Scan(&tally) return tally, err From 0c868c49ef100430c4dda6cb937f06e615d018fb Mon Sep 17 00:00:00 2001 From: Michal Nicpon Date: Wed, 5 Oct 2022 14:39:54 -0600 Subject: [PATCH 07/11] make mysql 5 compatible --- storage/mysql/certauth.go | 4 ++-- storage/mysql/mysql.go | 44 +++++++++++++++++++-------------------- storage/mysql/pushcert.go | 6 +++--- storage/mysql/queue.go | 6 +++--- 4 files changed, 30 insertions(+), 30 deletions(-) diff --git a/storage/mysql/certauth.go b/storage/mysql/certauth.go index c476972..9ddefdd 100644 --- a/storage/mysql/certauth.go +++ b/storage/mysql/certauth.go @@ -41,9 +41,9 @@ func (s *MySQLStorage) IsCertHashAssociated(r *mdm.Request, hash string) (bool, func (s *MySQLStorage) AssociateCertHash(r *mdm.Request, hash string) error { _, err := s.db.ExecContext( r.Context, ` -INSERT INTO nano_cert_auth_associations (id, sha256) VALUES (?, ?) AS new +INSERT INTO nano_cert_auth_associations (id, sha256) VALUES (?, ?) ON DUPLICATE KEY -UPDATE sha256 = new.sha256;`, +UPDATE sha256 = VALUES(sha256);`, r.ID, strings.ToLower(hash), ) diff --git a/storage/mysql/mysql.go b/storage/mysql/mysql.go index 39301d9..d73dbbf 100644 --- a/storage/mysql/mysql.go +++ b/storage/mysql/mysql.go @@ -103,12 +103,12 @@ func (s *MySQLStorage) StoreAuthenticate(r *mdm.Request, msg *mdm.Authenticate) INSERT INTO nano_devices (id, identity_cert, serial_number, authenticate, authenticate_at) VALUES - (?, ?, ?, ?, CURRENT_TIMESTAMP) AS new + (?, ?, ?, ?, CURRENT_TIMESTAMP) ON DUPLICATE KEY UPDATE - identity_cert = new.identity_cert, - serial_number = new.serial_number, - authenticate = new.authenticate, + identity_cert = VALUES(identity_cert), + serial_number = VALUES(serial_number), + authenticate = VALUES(authenticate), authenticate_at = CURRENT_TIMESTAMP;`, r.ID, pemCert, nullEmptyString(msg.SerialNumber), msg.Raw, ) @@ -142,13 +142,13 @@ func (s *MySQLStorage) storeUserTokenUpdate(r *mdm.Request, msg *mdm.TokenUpdate INSERT INTO nano_users (id, device_id, user_short_name, user_long_name, token_update, token_update_at) VALUES - (?, ?, ?, ?, ?, CURRENT_TIMESTAMP) AS new + (?, ?, ?, ?, ?, CURRENT_TIMESTAMP) ON DUPLICATE KEY UPDATE - device_id = new.device_id, - user_short_name = new.user_short_name, - user_long_name = new.user_long_name, - token_update = new.token_update, + device_id = VALUES(device_id), + user_short_name = VALUES(user_short_name), + user_long_name = VALUES(user_long_name), + token_update = VALUES(token_update), token_update_at = CURRENT_TIMESTAMP;`, r.ID, r.ParentID, @@ -182,15 +182,15 @@ func (s *MySQLStorage) StoreTokenUpdate(r *mdm.Request, msg *mdm.TokenUpdate) er INSERT INTO nano_enrollments (id, device_id, user_id, type, topic, push_magic, token_hex, last_seen_at, token_update_tally) VALUES - (?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP, 1) AS new + (?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP, 1) ON DUPLICATE KEY UPDATE - device_id = new.device_id, - user_id = new.user_id, - type = new.type, - topic = new.topic, - push_magic = new.push_magic, - token_hex = new.token_hex, + device_id = VALUES(device_id), + user_id = VALUES(user_id), + type = VALUES(type), + topic = VALUES(topic), + push_magic = VALUES(push_magic), + token_hex = VALUES(token_hex), enabled = 1, last_seen_at = CURRENT_TIMESTAMP, token_update_tally = nano_enrollments.token_update_tally + 1;`, @@ -229,14 +229,14 @@ func (s *MySQLStorage) StoreUserAuthenticate(r *mdm.Request, msg *mdm.UserAuthen INSERT INTO nano_users (id, device_id, user_short_name, user_long_name, `+colName+`, `+colAtName+`) VALUES - (?, ?, ?, ?, ?, CURRENT_TIMESTAMP) AS new + (?, ?, ?, ?, ?, CURRENT_TIMESTAMP) ON DUPLICATE KEY UPDATE - device_id = new.device_id, - user_short_name = new.user_short_name, - user_long_name = new.user_long_name, - `+colName+` = new.`+colName+`, - `+colAtName+` = new.`+colAtName+`;`, + device_id = VALUES(device_id), + user_short_name = VALUES(user_short_name), + user_long_name = VALUES(user_long_name), + `+colName+` = VALUES(`+colName+`), + `+colAtName+` = VALUES(`+colAtName+`);`, r.ID, r.ParentID, nullEmptyString(msg.UserShortName), diff --git a/storage/mysql/pushcert.go b/storage/mysql/pushcert.go index c6346ce..f0e8beb 100644 --- a/storage/mysql/pushcert.go +++ b/storage/mysql/pushcert.go @@ -50,11 +50,11 @@ func (s *MySQLStorage) StorePushCert(ctx context.Context, pemCert, pemKey []byte INSERT INTO nano_push_certs (topic, cert_pem, key_pem, stale_token) VALUES - (?, ?, ?, 0) AS new + (?, ?, ?, 0) ON DUPLICATE KEY UPDATE - cert_pem = new.cert_pem, - key_pem = new.key_pem, + cert_pem = VALUES(cert_pem), + key_pem = VALUES(key_pem), push_certs.stale_token = push_certs.stale_token + 1;`, topic, pemCert, pemKey, ) diff --git a/storage/mysql/queue.go b/storage/mysql/queue.go index 2c86ff4..ea91750 100644 --- a/storage/mysql/queue.go +++ b/storage/mysql/queue.go @@ -124,11 +124,11 @@ func (s *MySQLStorage) StoreCommandReport(r *mdm.Request, result *mdm.CommandRes INSERT INTO nano_command_results (id, command_uuid, status, result, not_now_at, not_now_tally) VALUES - (?, ?, ?, ?, `+notNowConstants+`) AS new + (?, ?, ?, ?, `+notNowConstants+`) ON DUPLICATE KEY UPDATE - status = new.status, - result = new.result`+notNowBumpTallySQL+`;`, + status = VALUES(status), + result = VALUES(result)`+notNowBumpTallySQL+`;`, r.ID, result.CommandUUID, result.Status, From bda2a451105e75d1464dd758b3afdea3d7bdfd33 Mon Sep 17 00:00:00 2001 From: gillespi314 <73313222+gillespi314@users.noreply.github.com> Date: Fri, 16 Dec 2022 17:42:19 -0600 Subject: [PATCH 08/11] Add supported fields to Authenticate struct type --- mdm/checkin.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mdm/checkin.go b/mdm/checkin.go index db9a38a..ada3041 100644 --- a/mdm/checkin.go +++ b/mdm/checkin.go @@ -26,6 +26,8 @@ type Authenticate struct { // Fields that may be present but are not strictly required for the // operation of the MDM protocol. Nice-to-haves. SerialNumber string + Model string + ModelName string } type b64Data []byte From 057e8a4d40a7578c15e7b192f5250c0e4e127112 Mon Sep 17 00:00:00 2001 From: gillespi314 <73313222+gillespi314@users.noreply.github.com> Date: Fri, 16 Dec 2022 17:51:03 -0600 Subject: [PATCH 09/11] Add DeviceName --- mdm/checkin.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/mdm/checkin.go b/mdm/checkin.go index ada3041..c387570 100644 --- a/mdm/checkin.go +++ b/mdm/checkin.go @@ -23,11 +23,15 @@ type Authenticate struct { Topic string Raw []byte `plist:"-"` // Original Authenticate XML plist + // Additional fields required in AuthenticateRequest as specified + // in the Apple documentation. + DeviceName string + Model string + ModelName string + // Fields that may be present but are not strictly required for the // operation of the MDM protocol. Nice-to-haves. SerialNumber string - Model string - ModelName string } type b64Data []byte From aefbe27244404faad554f098840806160c1b2d3f Mon Sep 17 00:00:00 2001 From: gillespi314 <73313222+gillespi314@users.noreply.github.com> Date: Tue, 20 Dec 2022 10:30:47 -0600 Subject: [PATCH 10/11] Revert "Add supported fields to Authenticate struct type" --- certverify/pool.go | 8 +------- cmd/nanomdm/main.go | 12 ++---------- docs/operations-guide.md | 10 ++-------- http/mdm/mdm.go | 22 ++-------------------- mdm/checkin.go | 9 --------- mdm/command.go | 4 ++-- mdm/mdm.go | 17 ----------------- 7 files changed, 9 insertions(+), 73 deletions(-) diff --git a/certverify/pool.go b/certverify/pool.go index 04fcb5c..244c22a 100644 --- a/certverify/pool.go +++ b/certverify/pool.go @@ -11,7 +11,7 @@ type PoolVerifier struct { } // NewPoolVerifier creates a new Verifier -func NewPoolVerifier(rootsPEM []byte, intsPEM []byte, keyUsages ...x509.ExtKeyUsage) (*PoolVerifier, error) { +func NewPoolVerifier(rootsPEM []byte, keyUsages ...x509.ExtKeyUsage) (*PoolVerifier, error) { opts := x509.VerifyOptions{ KeyUsages: keyUsages, Roots: x509.NewCertPool(), @@ -19,12 +19,6 @@ func NewPoolVerifier(rootsPEM []byte, intsPEM []byte, keyUsages ...x509.ExtKeyUs if len(rootsPEM) == 0 || !opts.Roots.AppendCertsFromPEM(rootsPEM) { return nil, errors.New("could not append root CA(s)") } - if len(intsPEM) > 0 { - opts.Intermediates = x509.NewCertPool() - if !opts.Intermediates.AppendCertsFromPEM(intsPEM) { - return nil, errors.New("could not append intermediate CA(s)") - } - } return &PoolVerifier{ verifyOpts: opts, }, nil diff --git a/cmd/nanomdm/main.go b/cmd/nanomdm/main.go index 310e3fa..033b491 100644 --- a/cmd/nanomdm/main.go +++ b/cmd/nanomdm/main.go @@ -50,8 +50,7 @@ func main() { flListen = flag.String("listen", ":9000", "HTTP listen address") flAPIKey = flag.String("api", "", "API key for API endpoints") flVersion = flag.Bool("version", false, "print version") - flRootsPath = flag.String("ca", "", "path to PEM CA cert(s)") - flIntsPath = flag.String("intermediate", "", "path to PEM intermediate cert(s)") + flRootsPath = flag.String("ca", "", "path to CA cert for verification") flWebhook = flag.String("webhook-url", "", "URL to send requests to") flCertHeader = flag.String("cert-header", "", "HTTP header containing URL-escaped TLS client certificate") flDebug = flag.Bool("debug", false, "log debug messages") @@ -82,14 +81,7 @@ func main() { if err != nil { stdlog.Fatal(err) } - var intsPEM []byte - if *flIntsPath != "" { - intsPEM, err = os.ReadFile(*flIntsPath) - if err != nil { - stdlog.Fatal(err) - } - } - verifier, err := certverify.NewPoolVerifier(caPEM, intsPEM, x509.ExtKeyUsageClientAuth) + verifier, err := certverify.NewPoolVerifier(caPEM, x509.ExtKeyUsageClientAuth) if err != nil { stdlog.Fatal(err) } diff --git a/docs/operations-guide.md b/docs/operations-guide.md index 82e4d3e..112af8f 100644 --- a/docs/operations-guide.md +++ b/docs/operations-guide.md @@ -28,15 +28,9 @@ API authorization in NanoMDM is simply HTTP Basic authentication using "nanomdm" ### -ca string -* path to PEM CA cert(s) +* Path to CA cert for verification -NanoMDM validates that the device identity certificate is issued from specific CAs. This switch is the path to a file of PEM-encoded CAs to validate enrollments against. - -### -intermediate string - -* path to PEM intermediate cert(s) - -NanoMDM validates that the device identity certificate is issued from specific CAs. This switch is the path to a file of PEM-encoded intermediate certificates that can be used to build a chain of trust to the CAs to validate enrollments against. +NanoMDM validates that the device identity certificate is issued from specific CAs. This switch is the path to a file of PEM-encoded CAs to validate against. ### -cert-header string diff --git a/http/mdm/mdm.go b/http/mdm/mdm.go index 0002db7..0325280 100644 --- a/http/mdm/mdm.go +++ b/http/mdm/mdm.go @@ -2,7 +2,6 @@ package mdm import ( "errors" - "fmt" "net/http" "strings" @@ -38,21 +37,12 @@ func CheckinHandler(svc service.Checkin, logger log.Logger) http.HandlerFunc { } respBytes, err := service.CheckinRequest(svc, mdmReqFromHTTPReq(r), bodyBytes) if err != nil { - logs := []interface{}{"msg", "check-in request"} + logger.Info("msg", "check-in request", "err", err) httpStatus := http.StatusInternalServerError var statusErr *service.HTTPStatusError if errors.As(err, &statusErr) { httpStatus = statusErr.Status - err = fmt.Errorf("HTTP error: %w", statusErr.Unwrap()) } - // manualy unwrapping the `StatusErr` is not necessary as `errors.As` manually unwraps - var parseErr *mdm.ParseError - if errors.As(err, &parseErr) { - logs = append(logs, "content", string(parseErr.Content)) - err = fmt.Errorf("parse error: %w", parseErr.Unwrap()) - } - logs = append(logs, "http_status", httpStatus, "err", err) - logger.Info(logs...) http.Error(w, http.StatusText(httpStatus), httpStatus) } w.Write(respBytes) @@ -71,20 +61,12 @@ func CommandAndReportResultsHandler(svc service.CommandAndReportResults, logger } respBytes, err := service.CommandAndReportResultsRequest(svc, mdmReqFromHTTPReq(r), bodyBytes) if err != nil { - logs := []interface{}{"msg", "command report results"} + logger.Info("msg", "command report results", "err", err) httpStatus := http.StatusInternalServerError var statusErr *service.HTTPStatusError if errors.As(err, &statusErr) { httpStatus = statusErr.Status - err = fmt.Errorf("HTTP error: %w", statusErr.Unwrap()) - } - var parseErr *mdm.ParseError - if errors.As(err, &parseErr) { - logs = append(logs, "content", string(parseErr.Content)) - err = fmt.Errorf("parse error: %w", parseErr.Unwrap()) } - logs = append(logs, "http_status", httpStatus, "err", err) - logger.Info(logs...) http.Error(w, http.StatusText(httpStatus), httpStatus) } w.Write(respBytes) diff --git a/mdm/checkin.go b/mdm/checkin.go index c387570..425756f 100644 --- a/mdm/checkin.go +++ b/mdm/checkin.go @@ -23,12 +23,6 @@ type Authenticate struct { Topic string Raw []byte `plist:"-"` // Original Authenticate XML plist - // Additional fields required in AuthenticateRequest as specified - // in the Apple documentation. - DeviceName string - Model string - ModelName string - // Fields that may be present but are not strictly required for the // operation of the MDM protocol. Nice-to-haves. SerialNumber string @@ -155,9 +149,6 @@ func (w *checkinUnmarshaller) UnmarshalPlist(f func(interface{}) error) error { func DecodeCheckin(rawMessage []byte) (message interface{}, err error) { w := &checkinUnmarshaller{raw: rawMessage} err = plist.Unmarshal(rawMessage, w) - if err != nil { - err = &ParseError{Err: err, Content: rawMessage} - } message = w.message return } diff --git a/mdm/command.go b/mdm/command.go index 3be9998..f7c1ea1 100644 --- a/mdm/command.go +++ b/mdm/command.go @@ -35,7 +35,7 @@ func DecodeCommandResults(rawResults []byte) (results *CommandResults, err error results = new(CommandResults) err = plist.Unmarshal(rawResults, results) if err != nil { - return nil, &ParseError{Err: err, Content: rawResults} + return } results.Raw = rawResults if results.Status == "" { @@ -58,7 +58,7 @@ func DecodeCommand(rawCommand []byte) (command *Command, err error) { command = new(Command) err = plist.Unmarshal(rawCommand, command) if err != nil { - return nil, &ParseError{Err: err, Content: rawCommand} + return } command.Raw = rawCommand if command.CommandUUID == "" || command.Command.RequestType == "" { diff --git a/mdm/mdm.go b/mdm/mdm.go index 8f1a68c..e3ec762 100644 --- a/mdm/mdm.go +++ b/mdm/mdm.go @@ -5,7 +5,6 @@ import ( "context" "crypto/x509" "errors" - "fmt" ) // Enrollment represents the various enrollment-related data sent with requests. @@ -60,19 +59,3 @@ func (r *Request) Clone() *Request { *r2 = *r return r2 } - -// ParseError represents a failure to parse an MDM structure (usually Apple Plist) -type ParseError struct { - Err error - Content []byte -} - -// Unwrap returns the underlying error of the ParseError -func (e *ParseError) Unwrap() error { - return e.Err -} - -// Error formats the ParseError as a string -func (e *ParseError) Error() string { - return fmt.Sprintf("parse error: %v: raw content: %v", e.Err, string(e.Content)) -} From c0093434bb12d7d8b463df2a2fb302f95c6a2b9b Mon Sep 17 00:00:00 2001 From: gillespi314 <73313222+gillespi314@users.noreply.github.com> Date: Tue, 20 Dec 2022 10:40:29 -0600 Subject: [PATCH 11/11] Add supported fields to Authenticate struct type --- mdm/checkin.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mdm/checkin.go b/mdm/checkin.go index 425756f..7d9b135 100644 --- a/mdm/checkin.go +++ b/mdm/checkin.go @@ -23,6 +23,12 @@ type Authenticate struct { Topic string Raw []byte `plist:"-"` // Original Authenticate XML plist + // Additional fields required in AuthenticateRequest as specified + // in the Apple documentation. + DeviceName string + Model string + ModelName string + // Fields that may be present but are not strictly required for the // operation of the MDM protocol. Nice-to-haves. SerialNumber string