2010-09-17 03:26:29 +04:00
/ * * *
This file is part of systemd .
Copyright 2010 Lennart Poettering
systemd is free software ; you can redistribute it and / or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
systemd is distributed in the hope that it will be useful , but
WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
General Public License for more details .
You should have received a copy of the GNU General Public License
along with systemd ; If not , see < http : //www.gnu.org/licenses/>.
* * * /
using Gtk ;
using GLib ;
using Linux ;
using Posix ;
2010-09-17 04:32:48 +04:00
using Notify ;
2010-09-17 03:26:29 +04:00
[ CCode ( cheader_filename = " time.h " ) ]
extern int clock_gettime ( int id , out timespec ts ) ;
public class PasswordDialog : Dialog {
public Entry entry ;
public PasswordDialog ( string message , string icon ) {
set_title ( " System Password " ) ;
set_has_separator ( false ) ;
set_border_width ( 8 ) ;
set_default_response ( ResponseType . OK ) ;
set_icon_name ( icon ) ;
2010-11-26 19:59:53 +03:00
# if LIBNOTIFY07
2010-11-17 15:19:10 +03:00
add_button ( Stock . CANCEL , ResponseType . CANCEL ) ;
add_button ( Stock . OK , ResponseType . OK ) ;
2010-11-26 19:59:53 +03:00
# else
add_button ( STOCK_CANCEL , ResponseType . CANCEL ) ;
add_button ( STOCK_OK , ResponseType . OK ) ;
# endif
2010-09-17 03:26:29 +04:00
Container content = ( Container ) get_content_area ( ) ;
Box hbox = new HBox ( false , 16 ) ;
hbox . set_border_width ( 8 ) ;
content . add ( hbox ) ;
Image image = new Image . from_icon_name ( icon , IconSize . DIALOG ) ;
hbox . pack_start ( image , false , false ) ;
Box vbox = new VBox ( false , 8 ) ;
hbox . pack_start ( vbox , true , true ) ;
Label label = new Label ( message ) ;
vbox . pack_start ( label , false , false ) ;
entry = new Entry ( ) ;
entry . set_visibility ( false ) ;
entry . set_activates_default ( true ) ;
vbox . pack_start ( entry , false , false ) ;
entry . activate . connect ( on_entry_activated ) ;
show_all ( ) ;
}
public void on_entry_activated ( ) {
response ( ResponseType . OK ) ;
}
}
public class MyStatusIcon : StatusIcon {
File directory ;
File current ;
FileMonitor file_monitor ;
string message ;
string icon ;
string socket ;
PasswordDialog password_dialog ;
public MyStatusIcon ( ) throws GLib . Error {
GLib . Object ( icon_name : " dialog-password " ) ;
2011-03-11 03:51:45 +03:00
set_title ( " System Password Request " ) ;
2010-09-17 03:26:29 +04:00
2011-03-11 03:51:45 +03:00
directory = File . new_for_path ( " /var/run/systemd/ask-password/ " ) ;
2010-09-17 03:26:29 +04:00
file_monitor = directory . monitor_directory ( 0 ) ;
file_monitor . changed . connect ( file_monitor_changed ) ;
current = null ;
look_for_password ( ) ;
activate . connect ( status_icon_activate ) ;
}
2011-01-20 20:24:26 +03:00
void file_monitor_changed ( GLib . File file , GLib . File ? other_file , GLib . FileMonitorEvent event_type ) {
2010-09-17 03:26:29 +04:00
if ( ! file . get_basename ( ) . has_prefix ( " ask. " ) )
return ;
if ( event_type = = FileMonitorEvent . CREATED | |
2011-01-20 20:24:26 +03:00
event_type = = FileMonitorEvent . DELETED ) {
try {
look_for_password ( ) ;
} catch ( Error e ) {
show_error ( e . message ) ;
}
}
2010-09-17 03:26:29 +04:00
}
void look_for_password ( ) throws GLib . Error {
if ( current ! = null ) {
if ( ! current . query_exists ( ) ) {
current = null ;
if ( password_dialog ! = null )
password_dialog . response ( ResponseType . REJECT ) ;
}
}
if ( current = = null ) {
FileEnumerator enumerator = directory . enumerate_children ( " standard::name " , FileQueryInfoFlags . NOFOLLOW_SYMLINKS ) ;
FileInfo i ;
while ( ( i = enumerator . next_file ( ) ) ! = null ) {
if ( ! i . get_name ( ) . has_prefix ( " ask. " ) )
continue ;
current = directory . get_child ( i . get_name ( ) ) ;
if ( load_password ( ) )
break ;
current = null ;
}
}
if ( current = = null )
set_visible ( false ) ;
}
2010-09-17 04:32:48 +04:00
bool load_password ( ) throws GLib . Error {
2010-09-17 03:26:29 +04:00
KeyFile key_file = new KeyFile ( ) ;
try {
timespec ts ;
key_file . load_from_file ( current . get_path ( ) , KeyFileFlags . NONE ) ;
string not_after_as_string = key_file . get_string ( " Ask " , " NotAfter " ) ;
clock_gettime ( 1 , out ts ) ;
uint64 now = ( ts . tv_sec * 1000000 ) + ( ts . tv_nsec / 1000 ) ;
uint64 not_after ;
if ( not_after_as_string . scanf ( " %llu " , out not_after ) ! = 1 )
return false ;
if ( not_after < now )
return false ;
socket = key_file . get_string ( " Ask " , " Socket " ) ;
} catch ( GLib . Error e ) {
return false ;
}
try {
message = key_file . get_string ( " Ask " , " Message " ) . compress ( ) ;
} catch ( GLib . Error e ) {
message = " Please Enter System Password! " ;
}
2011-03-11 03:51:45 +03:00
2010-09-17 03:26:29 +04:00
set_tooltip_text ( message ) ;
try {
icon = key_file . get_string ( " Ask " , " Icon " ) ;
} catch ( GLib . Error e ) {
icon = " dialog-password " ;
}
set_from_icon_name ( icon ) ;
set_visible ( true ) ;
2010-09-17 04:32:48 +04:00
2010-11-26 19:59:53 +03:00
# if LIBNOTIFY07
2010-11-17 15:19:10 +03:00
Notification n = new Notification ( title , message , icon ) ;
2010-11-26 19:59:53 +03:00
# else
Notification n = new Notification ( title , message , icon , null ) ;
n . attach_to_status_icon ( this ) ;
# endif
2010-09-17 04:32:48 +04:00
n . set_timeout ( 5000 ) ;
n . show ( ) ;
2010-09-17 03:26:29 +04:00
return true ;
}
2011-01-20 20:24:26 +03:00
void status_icon_activate ( ) {
2010-09-17 03:26:29 +04:00
if ( current = = null )
return ;
if ( password_dialog ! = null ) {
password_dialog . present ( ) ;
return ;
}
password_dialog = new PasswordDialog ( message , icon ) ;
int result = password_dialog . run ( ) ;
string password = password_dialog . entry . get_text ( ) ;
password_dialog . destroy ( ) ;
password_dialog = null ;
if ( result = = ResponseType . REJECT | |
result = = ResponseType . DELETE_EVENT )
return ;
int to_process ;
2011-01-20 20:24:26 +03:00
try {
Process . spawn_async_with_pipes (
null ,
{ " /usr/bin/pkexec " , " /lib/systemd/systemd-reply-password " , result = = ResponseType . OK ? " 1 " : " 0 " , socket } ,
null ,
0 ,
null ,
null ,
out to_process ,
null ,
null ) ;
OutputStream stream = new UnixOutputStream ( to_process , true ) ;
2011-03-11 17:41:37 +03:00
# if VALA_0_10
2011-03-11 16:09:10 +03:00
stream . write ( password , password . length , null ) ;
2011-03-11 17:41:37 +03:00
# else
stream . write ( password . data , null ) ;
2011-03-11 16:09:10 +03:00
# endif
2011-01-20 20:24:26 +03:00
} catch ( Error e ) {
show_error ( e . message ) ;
}
2010-09-17 03:26:29 +04:00
}
}
static const OptionEntry entries [ ] = {
{ null }
} ;
void show_error ( string e ) {
var m = new MessageDialog ( null , 0 , MessageType . ERROR , ButtonsType . CLOSE , " %s " , e ) ;
m . run ( ) ;
m . destroy ( ) ;
}
int main ( string [ ] args ) {
try {
Gtk . init_with_args ( ref args , " [OPTION...] " , entries , " systemd-ask-password-agent " ) ;
2010-09-17 04:32:48 +04:00
Notify . init ( " Password Agent " ) ;
2010-09-17 03:26:29 +04:00
MyStatusIcon i = new MyStatusIcon ( ) ;
Gtk . main ( ) ;
} catch ( GLib . Error e ) {
show_error ( e . message ) ;
}
return 0 ;
}