Created
February 6, 2020 18:00
-
-
Save retrohacker/f5ec254eeef99a3f7200cbe32d28e5a3 to your computer and use it in GitHub Desktop.
Modify a tarball's header content
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const fs = require('fs'); | |
const Header = require('tar/lib/header'); | |
const fd = fs.openSync('./service.tar', 'r+'); | |
const childProcess = require('child_process'); | |
const args = require('yargs') | |
.option('u', { | |
alias: 'user', | |
demandOption: true, | |
describe: 'the user to set permission bits to', | |
type: 'string' | |
}) | |
.argv | |
const file = args._[0]; | |
if(!file) { | |
throw new Error('filename is required'); | |
} | |
// Ensure file exists | |
fs.statSync(file); | |
// Resolve username to uid/gid/group | |
const user = args.user; | |
const uid = childProcess.execSync(`id -u ${user}`).toString().trim(); | |
const gid = childProcess.execSync(`id -g ${user}`).toString().trim(); | |
const group = childProcess.execSync(`getent group ${gid}`).toString().trim().split(':')[0]; | |
console.log(user, uid, group, gid); | |
// Tar stores uid and gid in octal | |
const uidString = Number(uid).toString(8); | |
const gidString = Number(uid).toString(8); | |
// Tar blocks are 512 bytes each. Anything that doesn't fill a block gets zero | |
// padded. | |
let block = 0; | |
let BLOCK_SIZE = 512; | |
const buffer = Buffer.alloc(BLOCK_SIZE); | |
let exit = false; | |
while(true) { | |
const bytesRead = fs.readSync(fd, buffer, 0, BLOCK_SIZE, block * BLOCK_SIZE); | |
const header = new Header(buffer); | |
if(header.nullBlock === false && header.cksumValid === false) { | |
console.log(header); | |
throw new Error('Invalid checksum!') | |
} | |
if(header.nullBlock === true && exit === true) { | |
break; | |
} | |
if(header.nullBlock === true) { | |
exit = true; | |
continue; | |
} | |
const oldUid = header.uid; | |
const oldGid = header.gid; | |
// Zero out the uid/user/gid/group blocks in the header | |
buffer.fill(0, 108, 124) // uid and gid | |
buffer.fill(0, 265, 329) // username and groupname | |
buffer.fill(0, 148, 156) // chksum | |
buffer.write(uidString, 108, 8, 'ascii'); | |
buffer.write(gidString, 116, 8, 'ascii'); | |
buffer.write(user, 265, 32, 'ascii'); | |
buffer.write(group, 297, 32, 'ascii'); | |
// Recompute chksum | |
let sum = 256 | |
for (let i = 0; i < 0 + 512; i++) { | |
sum += buffer[i] | |
} | |
buffer.write(sum.toString(8), 148, 8, 'ascii'); | |
const newHeader = new Header(buffer); | |
console.log(`${header.path} user: ${header.uid} => ${newHeader.uid} && group: ${header.gid} => ${newHeader.gid} && cksum: ${header.cksum} => ${newHeader.cksum}`); | |
// Update the header on disk | |
fs.writeSync(fd, buffer, 0, BLOCK_SIZE, block * BLOCK_SIZE); | |
let seekTo = ( block * BLOCK_SIZE ) + header.size; | |
while(block * BLOCK_SIZE < seekTo) { | |
block = block + 1; | |
} | |
block = block + 1; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment