From 5934f4d286176e266b6a26c24e2500f6fa661567 Mon Sep 17 00:00:00 2001 From: foxriver76 Date: Tue, 22 Oct 2024 21:01:33 +0200 Subject: [PATCH 1/4] the UI upgrade now runs as the same user as the js-controller --- CHANGELOG.md | 4 ++ packages/controller/src/lib/upgradeManager.ts | 45 ++++++++++++++++++- packages/controller/src/main.ts | 14 +++++- 3 files changed, 59 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6cc09e015..135982c8c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,10 @@ Placeholder for the next version (at the beginning of the line): ## __WORK IN PROGRESS__ --> + +## __WORK IN PROGRESS__ - Lucy +* (@foxriver76) the UI upgrade now runs as the same user as the js-controller + ## 7.0.0 (2024-10-06) - Lucy **Breaking changes** * Backups created with 7.0.x cannot be restored with previous version diff --git a/packages/controller/src/lib/upgradeManager.ts b/packages/controller/src/lib/upgradeManager.ts index d9a0c04ad..61eb64f2c 100644 --- a/packages/controller/src/lib/upgradeManager.ts +++ b/packages/controller/src/lib/upgradeManager.ts @@ -11,12 +11,16 @@ import fs from 'fs-extra'; import type { Socket } from 'node:net'; import type { Duplex } from 'node:stream'; import url from 'node:url'; +import process from 'node:process'; +/** The upgrade arguments provided to the constructor of the UpgradeManager */ export interface UpgradeArguments { /** Version of controller to upgrade too */ version: string; /** Admin instance which triggered the upgrade */ adminInstance: number; + uid: number; + gid: number; } interface Certificates { @@ -63,6 +67,10 @@ class UpgradeManager { private readonly adminInstance: number; /** Desired controller version */ private readonly version: string; + /** Group id the process should run as */ + private readonly gid: number; + /** User id the process should run as */ + private readonly uid: number; /** Response send by webserver */ private readonly response: ServerResponse = { running: true, @@ -85,6 +93,27 @@ class UpgradeManager { this.adminInstance = args.adminInstance; this.version = args.version; this.logger = this.setupLogger(); + this.gid = args.gid; + this.uid = args.uid; + + this.applyUser(); + } + + applyUser(): void { + if (!process.setuid || !process.setgid) { + const errMessage = 'Cannot ensure user and group ids on this system, because no POSIX platform'; + this.log(errMessage, true); + throw new Error(errMessage); + } + + try { + process.setgid(this.gid); + process.setuid(this.uid); + } catch (e) { + const errMessage = `Could not ensure user and group ids on this system: ${e.message}`; + this.log(errMessage, true); + throw new Error(errMessage); + } } /** @@ -103,6 +132,8 @@ class UpgradeManager { const version = additionalArgs[0]; const adminInstance = parseInt(additionalArgs[1]); + const uid = parseInt(additionalArgs[2]); + const gid = parseInt(additionalArgs[3]); const isValid = !!valid(version); @@ -116,7 +147,17 @@ class UpgradeManager { throw new Error('Please provide a valid admin instance'); } - return { version, adminInstance }; + if (isNaN(uid)) { + UpgradeManager.printUsage(); + throw new Error('Please provide a valid uid'); + } + + if (isNaN(gid)) { + UpgradeManager.printUsage(); + throw new Error('Please provide a valid gid'); + } + + return { version, adminInstance, uid, gid }; } /** @@ -163,7 +204,7 @@ class UpgradeManager { * Print how the module should be used */ static printUsage(): void { - console.info('Example usage: "node upgradeManager.js "'); + console.info('Example usage: "node upgradeManager.js "'); } /** diff --git a/packages/controller/src/main.ts b/packages/controller/src/main.ts index 70269edb0..8342109d9 100644 --- a/packages/controller/src/main.ts +++ b/packages/controller/src/main.ts @@ -2760,7 +2760,12 @@ async function processMessage(msg: ioBroker.SendableMessage): Promise { * @param options Arguments passed to the UpgradeManager process */ async function startUpgradeManager(options: UpgradeArguments): Promise { - const { version, adminInstance } = options; + const { version, adminInstance, uid, gid } = options; const upgradeProcessPath = require.resolve('./lib/upgradeManager'); let upgradeProcess: cp.ChildProcess; const isSystemd = await tools.isIoBrokerInstalledAsSystemd(); + logger.error(`${hostLogPrefix} ${process.getuid ? process.getuid().toString() : 'asfasfasfasf'}`); + logger.error(`${hostLogPrefix} ${process.getgid ? process.getgid().toString() : 'asfasfasfasf'}`); + if (isSystemd) { upgradeProcess = spawn( 'sudo', @@ -5864,6 +5872,8 @@ async function startUpgradeManager(options: UpgradeArguments): Promise { upgradeProcessPath, version, adminInstance.toString(), + uid.toString(), + gid.toString(), ], { detached: true, From 2f18b4dffb06dcfb79bb7346c70b30ef52ec5665 Mon Sep 17 00:00:00 2001 From: foxriver76 Date: Tue, 22 Oct 2024 21:10:22 +0200 Subject: [PATCH 2/4] jsdoc --- packages/controller/src/lib/upgradeManager.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/controller/src/lib/upgradeManager.ts b/packages/controller/src/lib/upgradeManager.ts index 61eb64f2c..362545880 100644 --- a/packages/controller/src/lib/upgradeManager.ts +++ b/packages/controller/src/lib/upgradeManager.ts @@ -19,7 +19,9 @@ export interface UpgradeArguments { version: string; /** Admin instance which triggered the upgrade */ adminInstance: number; + /** User id the process should run as */ uid: number; + /** Group id the process should run as */ gid: number; } From 7d48a0ea5ecab081ba4e7e9c1c3121320fc75dd1 Mon Sep 17 00:00:00 2001 From: foxriver76 Date: Tue, 22 Oct 2024 21:12:46 +0200 Subject: [PATCH 3/4] jsdoc --- packages/controller/src/lib/upgradeManager.ts | 3 +++ packages/controller/src/main.ts | 3 --- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/controller/src/lib/upgradeManager.ts b/packages/controller/src/lib/upgradeManager.ts index 362545880..c99f0e181 100644 --- a/packages/controller/src/lib/upgradeManager.ts +++ b/packages/controller/src/lib/upgradeManager.ts @@ -101,6 +101,9 @@ class UpgradeManager { this.applyUser(); } + /** + * To prevent commands (including npm) running as root, we apply the passed in gid and uid + */ applyUser(): void { if (!process.setuid || !process.setgid) { const errMessage = 'Cannot ensure user and group ids on this system, because no POSIX platform'; diff --git a/packages/controller/src/main.ts b/packages/controller/src/main.ts index 8342109d9..edfc6e5cd 100644 --- a/packages/controller/src/main.ts +++ b/packages/controller/src/main.ts @@ -5859,9 +5859,6 @@ async function startUpgradeManager(options: UpgradeArguments): Promise { const isSystemd = await tools.isIoBrokerInstalledAsSystemd(); - logger.error(`${hostLogPrefix} ${process.getuid ? process.getuid().toString() : 'asfasfasfasf'}`); - logger.error(`${hostLogPrefix} ${process.getgid ? process.getgid().toString() : 'asfasfasfasf'}`); - if (isSystemd) { upgradeProcess = spawn( 'sudo', From 58a60532913240775f6bb9839f106f510bdd4d6b Mon Sep 17 00:00:00 2001 From: foxriver76 Date: Tue, 22 Oct 2024 21:15:55 +0200 Subject: [PATCH 4/4] make method private --- packages/controller/src/lib/upgradeManager.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/controller/src/lib/upgradeManager.ts b/packages/controller/src/lib/upgradeManager.ts index c99f0e181..14bcd02d5 100644 --- a/packages/controller/src/lib/upgradeManager.ts +++ b/packages/controller/src/lib/upgradeManager.ts @@ -104,7 +104,7 @@ class UpgradeManager { /** * To prevent commands (including npm) running as root, we apply the passed in gid and uid */ - applyUser(): void { + private applyUser(): void { if (!process.setuid || !process.setgid) { const errMessage = 'Cannot ensure user and group ids on this system, because no POSIX platform'; this.log(errMessage, true);