Revision: 38800 http://trac.macosforge.org/projects/macports/changeset/38800 Author: pmagrath@macports.org Date: 2008-07-31 13:02:09 -0700 (Thu, 31 Jul 2008) Log Message: ----------- Add privilege escalation support. If say "port install cowsay" is run without necessary privileges, it will be re-run with sudo. Modified Paths: -------------- branches/gsoc08-privileges/base/src/port/port.tcl branches/gsoc08-privileges/base/src/port1.0/portdestroot.tcl branches/gsoc08-privileges/base/src/port1.0/portextract.tcl branches/gsoc08-privileges/base/src/port1.0/portinstall.tcl branches/gsoc08-privileges/base/src/port1.0/portutil.tcl Modified: branches/gsoc08-privileges/base/src/port/port.tcl =================================================================== --- branches/gsoc08-privileges/base/src/port/port.tcl 2008-07-31 19:55:22 UTC (rev 38799) +++ branches/gsoc08-privileges/base/src/port/port.tcl 2008-07-31 20:02:09 UTC (rev 38800) @@ -348,7 +348,11 @@ array set options $portspec(options) } uplevel 1 $block - cd $savedir + if {[file exists $savedir]} { + cd $savedir + } else { + cd ~ + } } } @@ -2456,6 +2460,9 @@ ui_debug "$errorInfo" break_softcontinue "Unable to open port: $result" 1 status } + + #ui_debug "worker ($workername) $target $portname" + if {[catch {set result [mportexec $workername $target]} result]} { global errorInfo mportclose $workername @@ -2465,10 +2472,22 @@ mportclose $workername + + # start gsoc08-privileges + if { [geteuid] != 0 && $result == 1 } { + # TODO: find a way to detect definitely that the error is privileges related. + ui_warn "Attempting to re-run with 'sudo port'. Command: 'sudo port $target $portname'." + set result 0 + ui_msg [exec sudo port $target $portname] + ui_debug "'sudo port $target $portname' has completed." + } + # end gsoc08-privileges + # Process any error that wasn't thrown and handled already if {$result} { break_softcontinue "Status $result encountered during processing." 1 status } + } return $status Modified: branches/gsoc08-privileges/base/src/port1.0/portdestroot.tcl =================================================================== --- branches/gsoc08-privileges/base/src/port1.0/portdestroot.tcl 2008-07-31 19:55:22 UTC (rev 38799) +++ branches/gsoc08-privileges/base/src/port1.0/portdestroot.tcl 2008-07-31 20:02:09 UTC (rev 38800) @@ -312,6 +312,10 @@ # Restore umask umask $oldmask + + # start gsoc08-privileges + chownAsRoot $destroot + # end gsoc08-privileges return 0 } Modified: branches/gsoc08-privileges/base/src/port1.0/portextract.tcl =================================================================== --- branches/gsoc08-privileges/base/src/port1.0/portextract.tcl 2008-07-31 19:55:22 UTC (rev 38799) +++ branches/gsoc08-privileges/base/src/port1.0/portextract.tcl 2008-07-31 20:02:09 UTC (rev 38800) @@ -92,8 +92,7 @@ } proc extract_main {args} { - global UI_PREFIX euid egid worksrcpath macportsuser - global filespath + global UI_PREFIX filespath worksrcpath if {![exists distfiles] && ![exists extract.only]} { # nothing to do @@ -112,18 +111,7 @@ } # start gsoc08-privileges - if { [getuid] == 0 && [geteuid] == [name_to_uid "$macportsuser"] } { - # if started with sudo but have dropped the privileges - seteuid $euid - ui_debug "euid changed to: [geteuid]" - chown ${worksrcpath} ${macportsuser} - ui_debug "chowned $worksrcpath to $macportsuser" - seteuid [name_to_uid "$macportsuser"] - ui_debug "euid changed to: [geteuid]" - } else { - ui_debug "no need to chown $worksrcpath. uid=[getuid]. euid=[geteuid]." - } - + chownAsRoot $worksrcpath # end gsoc08-privileges } Modified: branches/gsoc08-privileges/base/src/port1.0/portinstall.tcl =================================================================== --- branches/gsoc08-privileges/base/src/port1.0/portinstall.tcl 2008-07-31 19:55:22 UTC (rev 38799) +++ branches/gsoc08-privileges/base/src/port1.0/portinstall.tcl 2008-07-31 20:02:09 UTC (rev 38800) @@ -54,26 +54,13 @@ proc install_start {args} { global UI_PREFIX portname portversion portrevision variations portvariants - global macportsuser euid egid install.asroot + global install.asroot ui_msg "$UI_PREFIX [format [msgcat::mc "Installing %s @%s_%s%s"] $portname $portversion $portrevision $portvariants]" # start gsoc08-privileges - ui_msg [tbool install.asroot] - if { [tbool install.asroot] } { - # if port isn't marked as not needing root - if { [getuid] == 0 && [geteuid] == [name_to_uid "$macportsuser"] } { - # if started with sudo but have dropped the privileges - ui_debug "Can't run install on this port without elevated privileges." - ui_debug "Going to escalate privileges back to root." - setegid $egid - seteuid $euid - ui_debug "euid changed to: [geteuid]. egid changed to: [getegid]." - } - - if { [getuid] != 0 } { - return -code error "You can not run this port without elevated privileges. You need to re-run with 'sudo port'."; - } + # if port isn't marked as not needing root + elevateToRoot "install" } # end gsoc08-privileges Modified: branches/gsoc08-privileges/base/src/port1.0/portutil.tcl =================================================================== --- branches/gsoc08-privileges/base/src/port1.0/portutil.tcl 2008-07-31 19:55:22 UTC (rev 38799) +++ branches/gsoc08-privileges/base/src/port1.0/portutil.tcl 2008-07-31 20:02:09 UTC (rev 38800) @@ -1397,6 +1397,7 @@ proc open_statefile {args} { global workpath worksymlink place_worksymlink portname portpath ports_ignore_older global altprefix macportsuser euid egid usealtworkpath env applications_dir portbuildpath distpath + global portname # start gsoc08-privileges @@ -1435,7 +1436,7 @@ set username [uid_to_name $userid] if { $userid !=0 } { - ui_msg "Insufficient privileges to perform action for all users." + ui_msg "Insufficient privileges to perform action on port '$portname' for all users." ui_msg "Action will be performed for current user (${username}) only." ui_msg "Install actions should be executed using sudo." } @@ -2286,3 +2287,38 @@ } +proc chownAsRoot {path} { + global euid macportsuser + + if { [getuid] == 0 && [geteuid] == [name_to_uid "$macportsuser"] } { + # if started with sudo but have dropped the privileges + seteuid $euid + ui_debug "euid changed to: [geteuid]" + chown ${path} ${macportsuser} + ui_debug "chowned $path to $macportsuser" + seteuid [name_to_uid "$macportsuser"] + ui_debug "euid changed to: [geteuid]" + } elseif { [getuid] == 0 } { + # if started with sudo but have elevated back to root already + chown ${path} ${macportsuser} + } else { + ui_debug "not need to chown $path. uid=[getuid]. euid=[geteuid]." + } +} + +proc elevateToRoot {action} { + global euid egid macportsuser + + if { [getuid] == 0 && [geteuid] == [name_to_uid "$macportsuser"] } { + # if started with sudo but have dropped the privileges + ui_debug "Can't run $action on this port without elevated privileges. Escalating privileges back to root." + setegid $egid + seteuid $euid + ui_debug "euid changed to: [geteuid]. egid changed to: [getegid]." + } + + if { [getuid] != 0 } { + return -code error "You can not run this port without elevated privileges. You need to re-run with 'sudo port'."; + } +} +