DARWIN: Convert prefpane backup ops to privhelper

Convert the prefpane logic to backup various config files to privhelper,
so it can work with macOS 10.8+.

Specifically, define the new privhelper task "backup". Define a new
variant to TaskUtil's executePrivTask() called executePrivTaskBackup()
to use the new task type, and convert the prefpane code to use it.

Remove the backupFile() method, since it's now unused.

The new "backup" task has an argument (filename), so we don't need to
define separate tasks for each file we want to backup. But check the
given filename against a short list of files we know we deal with, just
to make sure we don't accidentally mess with some other system file,
since we're running as root.

Change-Id: I066d8e95a50a52f7509487f9228ba03dd027ea36
Reviewed-on: https://gerrit.openafs.org/15959
Tested-by: BuildBot <buildbot@rampaginggeek.com>
Reviewed-by: Michael Meffie <mmeffie@sinenomine.net>
Reviewed-by: Cheyenne Wills <cwills@sinenomine.net>
Reviewed-by: Mark Vitale <mvitale@sinenomine.net>
Reviewed-by: Andrew Deason <adeason@sinenomine.net>
This commit is contained in:
Marcio Barbosa 2024-11-23 03:44:04 -08:00 committed by Andrew Deason
parent 56915e96d8
commit 75da4edd3c
5 changed files with 125 additions and 40 deletions

View File

@ -387,7 +387,6 @@
-(void) startup;
-(void) scanIpForCell:(DBCellElement*) cellElement allIP:(NSString*)allIP;
-(void) backupConfigurationFiles;
-(void) backupFile:(NSString*)localAfsFilePath;
-(void) saveConfigurationFiles:(BOOL) makeBackup;
-(void) saveCacheConfigurationFiles:(BOOL) makeBackup;
-(void) installConfigurationFile:(NSString*)srcConfFile destPath:(NSString*) destPath;

View File

@ -1197,10 +1197,14 @@
// backup original file
if(makeBackup) {
//cacheinfo
[self backupFile:@"/etc/cacheinfo"];
[TaskUtil executePrivTaskBackup:@"/etc/cacheinfo"];
//afsd.options
[self backupFile:useAfsdConfVersion?AFSD_NEW_PREFERENCE_FILE:AFSD_OLD_PREFERENCE_FILE];
if (useAfsdConfVersion) {
[TaskUtil executePrivTaskBackup:AFSD_NEW_PREFERENCE_FILE];
} else {
[TaskUtil executePrivTaskBackup:AFSD_OLD_PREFERENCE_FILE];
}
}
// install cacheinfo
@ -1264,13 +1268,13 @@
@try{
//This cell
[self backupFile:@"/etc/ThisCell"];
[TaskUtil executePrivTaskBackup:@"/etc/ThisCell"];
//CellServDB
[self backupFile:@"/etc/CellServDB"];
[TaskUtil executePrivTaskBackup:@"/etc/CellServDB"];
//TheseCell
[self backupFile:@"/etc/TheseCells"];
[TaskUtil executePrivTaskBackup:@"/etc/TheseCells"];
} @catch (NSException *e) {
@throw e;
@ -1278,39 +1282,6 @@
}
}
// -------------------------------------------------------------------------------
// -(void) backupFile:(NSString*)localAfsFilePath
// -------------------------------------------------------------------------------
-(void) backupFile:(NSString*)localAfsFilePath
{
NSString *srcString = nil;
NSMutableString *filePath = [[NSMutableString alloc] initWithCapacity:256];
OSStatus err = noErr;
@try{
[filePath setString: installationPath];
[filePath appendString: localAfsFilePath];
//Check if the file at path exist
NSFileManager *fileManager = [NSFileManager defaultManager];
if(![fileManager fileExistsAtPath:[filePath stringByExpandingTildeInPath]]) return;
// store the source path
srcString = [filePath stringByExpandingTildeInPath];
[filePath appendString: @".afscommander_bk"];
// check for presence of bk file
if(![[NSFileManager defaultManager] fileExistsAtPath:[filePath stringByExpandingTildeInPath]]){
// backup the file
err = [futil autorizedCopy:srcString
toPath:[filePath stringByExpandingTildeInPath]];
}
} @catch (NSException *e) {
@throw e;
} @finally {
if(filePath) [filePath release];
}
}
// -------------------------------------------------------------------------------
// checkAfsStatus
// This is called at least once per 60s, so avoid logging normal case that afs _is_ mounted.

View File

@ -17,5 +17,7 @@
+(NSString*) searchExecutablePath:(NSString*)unixCommand;
+(NSString*) executeTaskSearchingPath:(NSString*)unixCommand args:(NSArray*)args;
+(NSString*) executeTask:(NSString*) taskName arguments:(NSArray *)args;
+(int) executePrivTask:(const char *)task filename:(char *)filename;
+(int) executePrivTask:(const char *)task;
+(int) executePrivTaskBackup:(NSString *)filename;
@end

View File

@ -85,6 +85,8 @@
*
* @param[in] task The name of the task to perform (e.g. "startup_enable").
* See privhelper.c:ProcessRequest for what tasks we define.
* @param[in] filename Used for the "backup" task. Don't specify this with
* executePrivTask; use executePrivTaskBackup instead.
*
* @returns Return status of the task
* @retval 0 success
@ -92,7 +94,7 @@
* @retval nonzero The return value of system() of a failed command for the
* task.
*/
+(int) executePrivTask:(const char *)task {
+(int) executePrivTask:(const char *)task filename:(char *)filename {
int status = -1;
OSErr autherr = [[AuthUtil shared] autorize];
@ -135,6 +137,9 @@
}
xpc_dictionary_set_string(msg, "task", task);
xpc_dictionary_set_data(msg, "auth", &extForm, sizeof(extForm));
if (filename != NULL) {
xpc_dictionary_set_string(msg, "filename", filename);
}
xpc_object_t reply = xpc_connection_send_message_with_reply_sync(conn, msg);
if (reply == NULL) {
@ -159,4 +164,12 @@
return status;
}
+(int) executePrivTask:(const char *)task {
return [self executePrivTask:task filename:NULL];
}
+(int) executePrivTaskBackup:(NSString *)filename {
return [self executePrivTask:"backup" filename:[filename UTF8String]];
}
@end

View File

@ -48,6 +48,7 @@
#define AFS_ID "org.openafs.filesystems.afs"
#define AFS_PLIST "/Library/LaunchDaemons/org.openafs.filesystems.afs.plist"
#define AFS_RC "/Library/OpenAFS/Tools/root.client/usr/vice/etc/afs.rc"
#define CONFIG_PREFIX "/var/db/openafs"
/*
* This is the code signing requirement imposed on anyone that connects to our
@ -204,6 +205,94 @@ RunCommand(int log_failure, const char *arg1, const char *arg2,
return status;
}
/*
* To make extra sure we don't accidentally write to some other file on the
* system, check any filename we're given against a specific list of files. If
* the filename we're given isn't one of these, refuse to do anything.
*/
static int
check_filename(const char *filename)
{
const char *allowlist[] = {
"/etc/cacheinfo",
"/etc/config/afs.conf",
"/etc/config/afsd.options",
"/etc/ThisCell",
"/etc/CellServDB",
"/etc/TheseCells",
};
int allowlist_len = sizeof(allowlist) / sizeof(allowlist[0]);
int fname_i;
for (fname_i = 0; fname_i < allowlist_len; fname_i++) {
if (strcmp(filename, allowlist[fname_i]) == 0) {
return 0;
}
}
return -1;
}
/*
* Translate the given 'filename' (e.g., "/etc/ThisCell") into the full path to
* the file on disk.
*/
static char *
GetFullPath(const char *task, const char *filename)
{
int code;
char *path;
code = check_filename(filename);
if (code != 0) {
syslog(LOG_WARNING, "%s: Task '%s' got invalid filename '%s'",
PRIVHELPER_ID, task, filename);
return NULL;
}
code = asprintf(&path, "%s%s", CONFIG_PREFIX, filename);
if (code < 0) {
mem_error();
return NULL;
}
return path;
}
/*
* Copies "filename" to "filename.afscommander_bk".
*/
static int
BackupFile(const char *filename)
{
int code;
char *src_path = NULL;
char *dest_path = NULL;
src_path = GetFullPath("backup", filename);
if (src_path == NULL) {
code = -1;
goto done;
}
code = asprintf(&dest_path, "%s.afscommander_bk", src_path);
if (code < 0) {
dest_path = NULL;
mem_error();
goto done;
}
code = RunCommand(1, "/bin/cp", src_path, dest_path, NULL);
if (code != 0) {
goto done;
}
done:
free(src_path);
free(dest_path);
return code;
}
/**
* Run the requested privileged task.
*
@ -222,6 +311,9 @@ RunCommand(int log_failure, const char *arg1, const char *arg2,
*
* - afsd_stop: Run "afs.rc stop" to stop the OpenAFS client.
*
* - backup: Make a backup copy of the configuration file named in the argument
* "filename". This copies file "X" to "X.afscommander_bk".
*
* @param[in] task The name of the requested task.
* @param[in] event The XPC dictionary containing other task-specific
* arguments.
@ -249,6 +341,14 @@ ProcessRequest(const char *task, xpc_object_t event)
} else if (strcmp(task, "afsd_stop") == 0) {
return RunCommand(1, AFS_RC, "stop", NULL, NULL);
} else if (strcmp(task, "backup") == 0) {
const char *filename = xpc_dictionary_get_string(event, "filename");
if (filename == NULL) {
syslog(LOG_WARNING, "%s: Task backup missing filename", PRIVHELPER_ID);
return -1;
}
return BackupFile(filename);
}
syslog(LOG_WARNING, "%s: Received unknown task '%s'", PRIVHELPER_ID, task);