[38760] branches/gsoc08-framework/MacPorts_Framework
Revision: 38760 http://trac.macosforge.org/projects/macports/changeset/38760 Author: armahg@macports.org Date: 2008-07-30 09:29:11 -0700 (Wed, 30 Jul 2008) Log Message: ----------- Things are about to get messy with MPHelperTool. Need a sane place to revert to if they go really awry. This is it Modified Paths: -------------- branches/gsoc08-framework/MacPorts_Framework/MPHelperTool.m branches/gsoc08-framework/MacPorts_Framework/MPInterpreter.h branches/gsoc08-framework/MacPorts_Framework/MPInterpreter.m branches/gsoc08-framework/MacPorts_Framework/MPInterpreterTest.h branches/gsoc08-framework/MacPorts_Framework/MPInterpreterTest.m branches/gsoc08-framework/MacPorts_Framework/MPMacPortsTest.h branches/gsoc08-framework/MacPorts_Framework/MPMacPortsTest.m branches/gsoc08-framework/MacPorts_Framework/MPNotifications.m branches/gsoc08-framework/MacPorts_Framework/MacPorts.Framework.xcodeproj/project.pbxproj Modified: branches/gsoc08-framework/MacPorts_Framework/MPHelperTool.m =================================================================== --- branches/gsoc08-framework/MacPorts_Framework/MPHelperTool.m 2008-07-30 12:30:35 UTC (rev 38759) +++ branches/gsoc08-framework/MacPorts_Framework/MPHelperTool.m 2008-07-30 16:29:11 UTC (rev 38760) @@ -8,34 +8,181 @@ #import <Cocoa/Cocoa.h> #import <Foundation/Foundation.h> +#import <Security/Security.h> #import "MPInterpreter.h" +#include <stdlib.h> +#include <sys/stat.h> -int main(int argc, char * const *argv) { +// ///////////////////////////////////////////////////////////////////////////// +// exitCleanly +// +// Exits the program with the correct status and releases the autorelease pool. +void exitCleanly(int code, NSAutoreleasePool *pool) +{ + [pool release]; + exit(code); +} + + + +//This code is adapted from : +// http://forums.macrumors.com/showthread.php?t=508394 + +//I will first try implementing this without any Authorization services. +//I just want a helper tool whose user id is set to 0 and can self repair itself +//I will be using message passing for IPC rather than piping or anything else +//like that. Check on IRC if there are any dangers in doing that. + + + + +//Usage +// ./MPHelperTool --self-repair srOptions --rec-count recOptions interpCmd +// So argv is of size 6 ... no more no less + +// srOptions is a C string with value of "yes" or "no" to tell us whether or not +// to run self repair + +//recOptions is a number telling us how many times we have been called recursively + +//interpCmd is a the + +int main(int argc, char const * argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; - NSString * pathtoself = [[NSBundle mainBundle] pathForResource:@"MPHelperTool" - ofType:nil]; + setuid(0); + NSLog(@"UID is %i", geteuid()); + //Check for right number of args + if (argc != 6) { + exitCleanly(TCL_ERROR , pool); + } - NSLog(@"Path to executable is %@", pathtoself); + //The second thing to check for is recOptions ... This method should be called + //recursively at most once. Its a bit weird but I think from the code above, + //this tool repairs itself AND THEN proceeds to execute the required command all in + //one process. This means the number of recursive calls should not exceed one. + //If we fail to self repair at the first try, we should just exit. + + + int recOptions = [[NSString stringWithCString:argv[4] encoding:NSUTF8StringEncoding] intValue]; + if (recOptions > 1) { + exitCleanly(TCL_ERROR, pool); + } + else { + ++recOptions; + } - if (argc == 2) { - MPInterpreter * interp = [MPInterpreter sharedInterpreter]; + MPInterpreter * interp = [MPInterpreter sharedInterpreter]; + NSString * interpCmd = [NSString stringWithCString:argv[5] encoding:NSUTF8StringEncoding]; + NSString * _path_to_self = [[NSBundle mainBundle] pathForResource:@"MPHelperTool" + ofType:nil]; + + //OSStatus status; + BOOL authenticatedMode = YES; + //AuthorizationRef auth; + //AuthorizationExternalForm extAuth; + + //This memory pointer should be valid till _path_to_self is freed or released + //in the autorelease pool .. in other words its save for our purposes + //and we dont' have to worry about releasing memory + const char * path_to_self = [_path_to_self cStringUsingEncoding:NSUTF8StringEncoding]; + + if (!strcmp(argv[1], "--self-repair") && !strcmp(argv[2], "yes") ) + { + NSLog(@"MacPortsFramework MPHelperTool main Self-repair. Starting"); + // We have started ourself in self-repair mode. This means that this executable is not owned by root and/or the setuid bit is not set. We need to recover that... + struct stat st; + int fd_tool; + + + //We don't need this code for now + /* Recover the passed in AuthorizationRef.*/ + + + /* Open tool exclusively, so noone can change it while we bless it */ + fd_tool = open(path_to_self, O_NONBLOCK|O_RDONLY|O_EXLOCK, 0); + + if (fd_tool == -1) + { + NSLog(@"MacPortsFramework MPHelperTool main Self-Repair. Exclusive open while repairing tool failed: %d.",errno); + exitCleanly(-1,pool); + } + + if (fstat(fd_tool, &st)) + { + NSLog(@"MacPortsFramework MPHelperTool main Self-Repair. fstat failed"); + exitCleanly(-1,pool); + } + + if (st.st_uid != 0) + { + fchown(fd_tool, 0, st.st_gid); + } + + + /* Disable group and world writability and make setuid root. */ + fchmod(fd_tool, (st.st_mode & (~(S_IWGRP|S_IWOTH))) | S_ISUID); + + close(fd_tool); + + NSLog(@"MacPortsFramework MPHelperTool main Self-repair. Complete"); + authenticatedMode = YES; + + + /*/Hopefully this works + int result = [interp execute:_path_to_self + withArgs:[NSArray arrayWithObjects:SELF_REPAIR, @"no", REC_COUNT, + [NSString stringWithFormat:@"%d", recOptions], interpCmd, nil]]; + + exitCleanly(result, pool);*/ + + + } + else + { + //To Do + //Add code here to receive Authorization reference from somwhere + + authenticatedMode = YES; + } + + /* If we are not running as root we need to self-repair. But we don't want to do it more than once + which means */ + if (authenticatedMode && geteuid() != 0) + { + NSLog(@"MacPortsFramework MPHelperTool main Normal-Mode. Not running as root! Starting self-repair mode."); + + //We run again in self repair mode. I am assuming that this new "forked" process + // will be able to repair the binary and execute the command successfully ... + //if it fails I guess i should return something to that effect? + int result = [interp execute:_path_to_self + withArgs:[NSArray arrayWithObjects:SELF_REPAIR, @"yes", REC_COUNT, + [NSString stringWithFormat:@"%d", recOptions], interpCmd, nil]]; + + + //Is the above method guaranteed to always complete before the + //program execution gets here? + exitCleanly(result, pool); + + + } + + //Now we can finally execute the method ... whew + if (interpCmd != nil) { NSError * evalError; - ++argv; - NSString * interpCmd = [NSString stringWithCString:*argv]; NSLog(@"Executin Tcl command %@", interpCmd); NSString * result = [interp evaluateStringAsString:interpCmd error:&evalError]; if(result == nil && evalError) { NSLog(@"Command %@ exited with Error %@", interpCmd, evalError); - return TCL_ERROR; + exitCleanly(TCL_ERROR,pool); } else { NSLog(@"Command %@ returned %@", interpCmd, result); - return TCL_OK; + exitCleanly(TCL_OK, pool); } /*while(*argv != NULL) { NSLog(@"Passed parameter is %@", [NSString stringWithCString:*argv]); Modified: branches/gsoc08-framework/MacPorts_Framework/MPInterpreter.h =================================================================== --- branches/gsoc08-framework/MacPorts_Framework/MPInterpreter.h 2008-07-30 12:30:35 UTC (rev 38759) +++ branches/gsoc08-framework/MacPorts_Framework/MPInterpreter.h 2008-07-30 16:29:11 UTC (rev 38760) @@ -43,6 +43,11 @@ #include <tcl.h> #import "MPNotifications.h" + +//Defining some flags for MPHelperTool +#define SELF_REPAIR @"--self-repair" +#define REC_COUNT @"--rec-count" + #define MPPackage @"macports" #define MPPackageVersion @"1.0" #define MP_DEFAULT_PKG_PATH @"/Library/Tcl" @@ -70,8 +75,8 @@ + (MPInterpreter *)sharedInterpreter; - (Tcl_Interp *) sharedTclInterpreter; +- (int) execute:(NSString *)pathToExecutable withArgs:(NSArray*)args; - + (MPInterpreter *)sharedInterpreterWithPkgPath:(NSString *)path; - (id) initWithPkgPath:(NSString *)path; Modified: branches/gsoc08-framework/MacPorts_Framework/MPInterpreter.m =================================================================== --- branches/gsoc08-framework/MacPorts_Framework/MPInterpreter.m 2008-07-30 12:30:35 UTC (rev 38759) +++ branches/gsoc08-framework/MacPorts_Framework/MPInterpreter.m 2008-07-30 16:29:11 UTC (rev 38760) @@ -243,6 +243,17 @@ #pragma Utilities +- (int) execute:(NSString *)pathToExecutable withArgs:(NSArray *)args { + NSTask * task = [[NSTask alloc] init]; + [task setLaunchPath:pathToExecutable]; + [task setArguments:args]; + [task launch]; + [task waitUntilExit]; + int status = [task terminationStatus]; + [task release]; + return status; +} + /*- (NSDictionary *)evaluateArrayAsString:(NSArray *)statement { return [self evaluateStringAsString:[statement componentsJoinedByString:@" "]]; } @@ -257,10 +268,10 @@ Tcl_Obj * interpObj = Tcl_GetObjResult(_interpreter); int length, errCode; NSString * errString = [NSString stringWithUTF8String:Tcl_GetStringFromObj(interpObj, &length)]; - NSLog(@"TclObj string is %@ with length %d", errString , length); + //NSLog(@"TclObj string is %@ with length %d", errString , length); errCode = Tcl_GetErrno(); - NSLog(@"Errno Id is %@ with value %d", [NSString stringWithUTF8String:Tcl_ErrnoId()], errCode); - NSLog(@"Errno Msg is %@", [NSString stringWithUTF8String:Tcl_ErrnoMsg(errCode)]); + //NSLog(@"Errno Id is %@ with value %d", [NSString stringWithUTF8String:Tcl_ErrnoId()], errCode); + //NSLog(@"Errno Msg is %@", [NSString stringWithUTF8String:Tcl_ErrnoMsg(errCode)]); //Handle errors here ... Framework users can do !mportError to find out if //method was successful Modified: branches/gsoc08-framework/MacPorts_Framework/MPInterpreterTest.h =================================================================== --- branches/gsoc08-framework/MacPorts_Framework/MPInterpreterTest.h 2008-07-30 12:30:35 UTC (rev 38759) +++ branches/gsoc08-framework/MacPorts_Framework/MPInterpreterTest.h 2008-07-30 16:29:11 UTC (rev 38760) @@ -43,6 +43,7 @@ - (void)testInitialization; - (void)testGetVariableAsArray; +//- (void)testMPHelperTool; //- (void)testMutableDictionaryFromTclListAsString; //- (void)testEvaluateStringAsString; Modified: branches/gsoc08-framework/MacPorts_Framework/MPInterpreterTest.m =================================================================== --- branches/gsoc08-framework/MacPorts_Framework/MPInterpreterTest.m 2008-07-30 12:30:35 UTC (rev 38759) +++ branches/gsoc08-framework/MacPorts_Framework/MPInterpreterTest.m 2008-07-30 16:29:11 UTC (rev 38760) @@ -59,6 +59,16 @@ /* +- (void)testMPHelperTool { + + //Interesting ... we'll see who MPInterpreter belongs to + //at the time of execution MPHelperTool ... or MacPorts.Framework + [interp execute:[[NSBundle bundleForClass:MPInterpreter] pathForResource:@"MPHelperTool" ofType:nil] + withArgs:[NSArray arrayWithObjects:@"--sel-repair", @"no", @"--rec-count", + @"0", @"mportselfupdate", nil]]; +} + +/* Having trouble coming up with test cases for the methods below. Speak to Randall about that. * Modified: branches/gsoc08-framework/MacPorts_Framework/MPMacPortsTest.h =================================================================== --- branches/gsoc08-framework/MacPorts_Framework/MPMacPortsTest.h 2008-07-30 12:30:35 UTC (rev 38759) +++ branches/gsoc08-framework/MacPorts_Framework/MPMacPortsTest.h 2008-07-30 16:29:11 UTC (rev 38760) @@ -42,7 +42,7 @@ } --(void) testMPHelperTool; + -(void) testPortCreation; -(void) testPrefix; -(void) testSources; @@ -52,5 +52,6 @@ -(void) testSync; -(void) testVersion; //-(void) testInstall; +-(void) testMPHelperTool; @end Modified: branches/gsoc08-framework/MacPorts_Framework/MPMacPortsTest.m =================================================================== --- branches/gsoc08-framework/MacPorts_Framework/MPMacPortsTest.m 2008-07-30 12:30:35 UTC (rev 38759) +++ branches/gsoc08-framework/MacPorts_Framework/MPMacPortsTest.m 2008-07-30 16:29:11 UTC (rev 38760) @@ -111,7 +111,8 @@ pathForResource:@"MPHelperTool" ofType:nil]]; - NSArray * args = [NSArray arrayWithObjects:@"return [macports::version]", nil]; + NSArray * args = [NSArray arrayWithObjects:SELF_REPAIR, @"no", + REC_COUNT, @"0", @"return [macports::version]", nil]; [task setArguments:args]; [task launch]; Modified: branches/gsoc08-framework/MacPorts_Framework/MPNotifications.m =================================================================== --- branches/gsoc08-framework/MacPorts_Framework/MPNotifications.m 2008-07-30 12:30:35 UTC (rev 38759) +++ branches/gsoc08-framework/MacPorts_Framework/MPNotifications.m 2008-07-30 16:29:11 UTC (rev 38760) @@ -85,7 +85,7 @@ [NSNumber numberWithInt:0], MPMSG, [NSNumber numberWithInt:0], MPINFO, [NSNumber numberWithInt:0], MPWARN, [NSNumber numberWithInt:0], MPERROR, [NSNumber numberWithInt:1], MPDEBUG, [NSNumber numberWithInt:0], MPALL, nil]; - NSLog(@"Dictionary is %@ ", [blockOptions description]); + //NSLog(@"Dictionary is %@ ", [blockOptions description]); } return self; } Modified: branches/gsoc08-framework/MacPorts_Framework/MacPorts.Framework.xcodeproj/project.pbxproj =================================================================== --- branches/gsoc08-framework/MacPorts_Framework/MacPorts.Framework.xcodeproj/project.pbxproj 2008-07-30 12:30:35 UTC (rev 38759) +++ branches/gsoc08-framework/MacPorts_Framework/MacPorts.Framework.xcodeproj/project.pbxproj 2008-07-30 16:29:11 UTC (rev 38760) @@ -56,6 +56,7 @@ 6ED12AFB0E3E9F980026773D /* MPNotifications.h in Headers */ = {isa = PBXBuildFile; fileRef = 6E270D070E158CED00BAE687 /* MPNotifications.h */; }; 6ED12AFC0E3E9FA60026773D /* MPNotifications.m in Sources */ = {isa = PBXBuildFile; fileRef = 6E270D080E158CED00BAE687 /* MPNotifications.m */; }; 6ED12B060E3EA9E30026773D /* init.tcl in Resources */ = {isa = PBXBuildFile; fileRef = 48E9939E0C82CEB000219DDF /* init.tcl */; }; + 6ED12C9E0E40C3320026773D /* template.c in Resources */ = {isa = PBXBuildFile; fileRef = 6ED12C9D0E40C3320026773D /* template.c */; }; 8DC2EF530486A6940098B216 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C1666FE841158C02AAC07 /* InfoPlist.strings */; }; 8DC2EF570486A6940098B216 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7B1FEA5585E11CA2CBB /* Cocoa.framework */; }; /* End PBXBuildFile section */ @@ -118,6 +119,8 @@ 6ED12A540E3E55DF0026773D /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = /System/Library/Frameworks/Security.framework; sourceTree = "<absolute>"; }; 6ED12AA20E3E7E7C0026773D /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 6ED12AA60E3E7E900026773D /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; + 6ED12C2D0E405E660026773D /* finkLauncher.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = finkLauncher.c; sourceTree = "<group>"; }; + 6ED12C9D0E40C3320026773D /* template.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = template.c; sourceTree = "<group>"; }; 8DC2EF5A0486A6940098B216 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; }; 8DC2EF5B0486A6940098B216 /* MacPorts.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MacPorts.framework; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ @@ -288,6 +291,8 @@ isa = PBXGroup; children = ( 6ED12A4E0E3E55660026773D /* MPHelperTool.m */, + 6ED12C2D0E405E660026773D /* finkLauncher.c */, + 6ED12C9D0E40C3320026773D /* template.c */, ); name = MPHelperTool; sourceTree = "<group>"; @@ -418,6 +423,7 @@ buildActionMask = 2147483647; files = ( 6ED12B060E3EA9E30026773D /* init.tcl in Resources */, + 6ED12C9E0E40C3320026773D /* template.c in Resources */, ); runOnlyForDeploymentPostprocessing = 0; };
participants (1)
-
armahg@macports.org