2
* local_system.cpp - namespace localSystem, providing an interface for
3
* transparent usage of operating-system-specific functions
5
* Copyright (c) 2006-2008 Tobias Doerffel <tobydox/at/users/dot/sf/dot/net>
7
* This file is part of iTALC - http://italc.sourceforge.net
9
* This program is free software; you can redistribute it and/or
10
* modify it under the terms of the GNU General Public
11
* License as published by the Free Software Foundation; either
12
* version 2 of the License, or (at your option) any later version.
14
* This program is distributed in the hope that it will be useful,
15
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17
* General Public License for more details.
19
* You should have received a copy of the GNU General Public
20
* License along with this program (see COPYING); if not, write to the
21
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22
* Boston, MA 02111-1307, USA.
32
#include <QtCore/QCoreApplication>
33
#include <QtCore/QDir>
34
#include <QtCore/QMutex>
35
#include <QtCore/QProcess>
36
#include <QtCore/QSettings>
37
#include <QtCore/QDateTime>
38
#include <QtGui/QWidget>
39
#include <QtNetwork/QTcpServer>
44
#include <QtCore/QLibrary>
46
static const char * tr_accels = QT_TRANSLATE_NOOP(
48
"UPL (note for translators: the first three characters of "
49
"this string are the accellerators (underlined characters) "
50
"of the three input-fields in logon-dialog of windows - "
51
"please keep this note as otherwise there are strange errors "
52
"concerning logon-feature)" );
54
#define _WIN32_WINNT 0x0501
64
// taken from qt-win-opensource-src-4.2.2/src/corelib/io/qsettings.cpp
65
QString windowsConfigPath( int _type )
69
QLibrary library( "shell32" );
70
typedef BOOL( WINAPI* GetSpecialFolderPath )( HWND, char *, int, BOOL );
71
GetSpecialFolderPath SHGetSpecialFolderPath = (GetSpecialFolderPath)
72
library.resolve( "SHGetSpecialFolderPathA" );
73
if( SHGetSpecialFolderPath )
76
SHGetSpecialFolderPath( 0, path, _type, FALSE );
77
result = QString::fromLocal8Bit( path );
91
#ifdef HAVE_SYS_SOCKET_H
92
#include <sys/socket.h>
95
#ifdef HAVE_ARPA_INET_H
96
#include <arpa/inet.h>
99
#ifdef HAVE_NETINET_IN_H
100
#include <netinet/in.h>
107
#include "local_system.h"
111
static localSystem::p_pressKey __pressKey;
112
static QString __log_file;
113
static QFile * __debug_out = NULL;
117
static QString properLineEnding( QString _out )
119
if( _out.right( 1 ) != "\012" )
124
if( _out.right( 1 ) != "\015" )
126
_out.replace( QString( "\012" ), QString( "\015\012" ) );
130
if( _out.right( 1 ) != "\015" ) // MAC
132
_out.replace( QString( "\012" ), QString( "\015" ) );
140
void msgHandler( QtMsgType _type, const char * _msg )
142
if( localSystem::logLevel == 0 )
147
if( QString( _msg ).contains( "timers cannot be stopped",
148
Qt::CaseInsensitive ) )
153
if( __debug_out == NULL )
155
QString tmp_path = QDir::rootPath() +
162
foreach( const QString s, QProcess::systemEnvironment() )
164
if( s.toLower().left( 5 ) == "temp=" )
166
tmp_path = s.toLower().mid( 5 );
169
else if( s.toLower().left( 4 ) == "tmp=" )
171
tmp_path = s.toLower().mid( 4 );
175
if( !QDir( tmp_path ).exists() )
177
if( QDir( QDir::rootPath() ).mkdir( tmp_path ) )
179
QFile::setPermissions( tmp_path,
180
QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner |
181
QFile::ReadUser | QFile::WriteUser | QFile::ExeUser |
182
QFile::ReadGroup | QFile::WriteGroup | QFile::ExeGroup |
183
QFile::ReadOther | QFile::WriteOther | QFile::ExeOther );
186
const QString log_path = tmp_path + QDir::separator();
187
__debug_out = new QFile( log_path + __log_file );
188
__debug_out->open( QFile::WriteOnly | QFile::Append |
196
if( localSystem::logLevel > 8)
198
out = QDateTime::currentDateTime().toString() + QString( ": [debug] %1" ).arg( _msg ) + "\n";
202
if( localSystem::logLevel > 5 )
204
out = QDateTime::currentDateTime().toString() + QString( ": [warning] %1" ).arg( _msg ) + "\n";
208
if( localSystem::logLevel > 3 )
210
out = QDateTime::currentDateTime().toString() + QString( ": [critical] %1" ).arg( _msg ) + "\n";
214
if( localSystem::logLevel > 1 )
216
out = QDateTime::currentDateTime().toString() + QString( ": [fatal] %1" ).arg( _msg ) + "\n";
219
out = QDateTime::currentDateTime().toString() + QString( ": [unknown] %1" ).arg( _msg ) + "\n";
222
if( out.trimmed().size() )
224
out = properLineEnding( out );
225
__debug_out->write( out.toUtf8() );
226
printf( "%s", out.toUtf8().constData() );
231
void initResources( void )
233
Q_INIT_RESOURCE(italc_core);
236
namespace localSystem
239
int IC_DllExport logLevel = 6;
242
void initialize( p_pressKey _pk, const QString & _log_file )
245
__log_file = _log_file;
247
QCoreApplication::setOrganizationName( "iTALC Solutions" );
248
QCoreApplication::setOrganizationDomain( "italcsolutions.org" );
249
QCoreApplication::setApplicationName( "iTALC" );
251
QSettings settings( QSettings::SystemScope, "iTALC Solutions", "iTALC" );
253
if( settings.contains( "settings/LogLevel" ) )
255
logLevel = settings.value( "settings/LogLevel" ).toInt();
258
qInstallMsgHandler( msgHandler );
266
int freePort( int _default_port )
269
if( t.listen( QHostAddress::LocalHost, _default_port ) )
271
return( _default_port );
273
t.listen( QHostAddress::LocalHost );
274
return( t.serverPort() );
280
void sleep( const int _ms )
283
Sleep( static_cast<unsigned int>( _ms ) );
285
struct timespec ts = { _ms / 1000, ( _ms % 1000 ) * 1000 * 1000 } ;
286
nanosleep( &ts, NULL );
293
void execInTerminal( const QString & _cmds )
295
QProcess::startDetached(
307
void broadcastWOLPacket( const QString & _mac )
309
const int PORT_NUM = 65535;
310
const int MAC_SIZE = 6;
311
const int OUTBUF_SIZE = MAC_SIZE*17;
312
unsigned char mac[MAC_SIZE];
313
char out_buf[OUTBUF_SIZE];
315
if( sscanf( _mac.toAscii().constData(),
316
"%2x:%2x:%2x:%2x:%2x:%2x",
317
(unsigned int *) &mac[0],
318
(unsigned int *) &mac[1],
319
(unsigned int *) &mac[2],
320
(unsigned int *) &mac[3],
321
(unsigned int *) &mac[4],
322
(unsigned int *) &mac[5] ) != MAC_SIZE )
324
qWarning( "invalid MAC-address" );
328
for( int i = 0; i < MAC_SIZE; ++i )
333
for( int i = 1; i < 17; ++i )
335
for(int j = 0; j < MAC_SIZE; ++j )
337
out_buf[i*MAC_SIZE+j] = mac[j];
343
if( WSAStartup( MAKEWORD( 1, 1 ), &info ) != 0 )
345
qCritical( "cannot initialize WinSock!" );
350
// UDP-broadcast the MAC-address
351
unsigned int sock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
352
struct sockaddr_in my_addr;
353
my_addr.sin_family = AF_INET; // Address family to use
354
my_addr.sin_port = htons( PORT_NUM ); // Port number to use
355
my_addr.sin_addr.s_addr = inet_addr( "255.255.255.255" ); // send to
359
if( setsockopt( sock, SOL_SOCKET, SO_BROADCAST, (char *) &optval,
360
sizeof( optval ) ) < 0 )
362
qCritical( "can't set sockopt (%d).", errno );
366
sendto( sock, out_buf, sizeof( out_buf ), 0,
367
(struct sockaddr*) &my_addr, sizeof( my_addr ) );
378
QProcess::startDetached( "etherwake " + _mac );
385
static inline void pressAndReleaseKey( int _key )
387
__pressKey( _key, TRUE );
388
__pressKey( _key, FALSE );
392
void logonUser( const QString & _uname, const QString & _passwd,
393
const QString & _domain )
397
// first check for process "explorer.exe" - if we find it, a user
398
// is logged in and we do not send our key-sequences as it probably
400
DWORD aProcesses[1024], cbNeeded;
402
if( !EnumProcesses( aProcesses, sizeof(aProcesses), &cbNeeded ) )
407
DWORD cProcesses = cbNeeded / sizeof(DWORD);
409
bool user_logged_on = FALSE;
410
for( DWORD i = 0; i < cProcesses; i++ )
412
HANDLE hProcess = OpenProcess( PROCESS_QUERY_INFORMATION |
414
FALSE, aProcesses[i] );
416
if( hProcess == NULL ||
417
!EnumProcessModules( hProcess, &hMod, sizeof( hMod ),
422
TCHAR szProcessName[MAX_PATH];
423
GetModuleBaseName( hProcess, hMod, szProcessName,
424
sizeof(szProcessName)/sizeof(TCHAR) );
425
for( TCHAR * ptr = szProcessName; *ptr; ++ptr )
427
*ptr = tolower( *ptr );
429
if( strcmp( szProcessName, "explorer.exe" ) == 0 )
431
user_logged_on = TRUE;
442
if( GetKeyState( VK_CAPITAL ) & 1 )
445
ZeroMemory( input, sizeof( input ) );
446
input[0].type = input[1].type = INPUT_KEYBOARD;
447
input[0].ki.wVk = input[1].ki.wVk = VK_CAPITAL;
448
input[1].ki.dwFlags = KEYEVENTF_KEYUP;
449
SendInput( 2, input, sizeof( INPUT ) );
452
pressAndReleaseKey( XK_Escape );
453
pressAndReleaseKey( XK_Escape );
455
// send Secure Attention Sequence (SAS) for making sure we can enter
456
// username and password
457
__pressKey( XK_Alt_L, TRUE );
458
__pressKey( XK_Control_L, TRUE );
459
pressAndReleaseKey( XK_Delete );
460
__pressKey( XK_Control_L, FALSE );
461
__pressKey( XK_Alt_L, FALSE );
463
const ushort * accels = QObject::tr( tr_accels ).utf16();
465
/* Need to handle 2 cases here; if an interactive login message is
466
* defined in policy, this window will be displayed with an "OK" button;
467
* if not the login window will be displayed. Sending a space will
468
* dismiss the message, but will also add a space to the currently
469
* selected field if the login windows is active. The solution is:
470
* 1. send the "username" field accelerator (which won't do anything
471
* to the message window, but will select the "username" field of
472
* the login window if it is active)
473
* 2. Send a space keypress to dismiss the message. (adds a space
474
* to username field of login window if active)
475
* 3. Send the "username" field accelerator again; which will select
476
* the username field for the case where the message was displayed
477
* 4. Send a backspace keypress to remove any space that was added to
478
* the username field if there is no message.
480
__pressKey( XK_Alt_L, TRUE );
481
pressAndReleaseKey( accels[0] );
482
__pressKey( XK_Alt_L, FALSE );
484
pressAndReleaseKey( XK_space );
486
__pressKey( XK_Alt_L, TRUE );
487
pressAndReleaseKey( accels[0] );
488
__pressKey( XK_Alt_L, FALSE );
490
pressAndReleaseKey( XK_BackSpace );
493
for( int i = 0; i < _uname.size(); ++i )
495
pressAndReleaseKey( _uname.utf16()[i] );
499
__pressKey( XK_Alt_L, TRUE );
500
pressAndReleaseKey( accels[1] );
501
__pressKey( XK_Alt_L, FALSE );
503
pressAndReleaseKey( XK_Tab );
506
for( int i = 0; i < _passwd.size(); ++i )
508
pressAndReleaseKey( _passwd.utf16()[i] );
512
if( !_domain.isEmpty() )
514
__pressKey( XK_Alt_L, TRUE );
515
pressAndReleaseKey( accels[2] );
516
__pressKey( XK_Alt_L, FALSE );
517
for( int i = 0; i < _domain.size(); ++i )
519
pressAndReleaseKey( _domain.utf16()[i] );
524
pressAndReleaseKey( XK_Return );
530
static const QString userRoleNames[] =
540
QString userRoleName( const ISD::userRoles _role )
542
return( userRoleNames[_role] );
546
inline QString keyPath( const ISD::userRoles _role, const QString _group,
549
QSettings settings( QSettings::SystemScope, "iTALC Solutions",
551
if( _role <= ISD::RoleNone || _role >= ISD::RoleCount )
553
qWarning( "invalid role" );
556
const QString fallback_dir =
562
+ _group + QDir::separator() + userRoleNames[_role] +
564
( _only_path ? "" : "key" );
565
const QString val = settings.value( "keypaths" + _group + "/" +
566
userRoleNames[_role] ).toString();
569
settings.setValue( "keypaths" + _group + "/" +
570
userRoleNames[_role], fallback_dir );
571
return( fallback_dir );
575
if( _only_path && val.right( 4 ) == "\\key" )
577
return( val.left( val.size() - 4 ) );
584
QString privateKeyPath( const ISD::userRoles _role, bool _only_path )
586
return( keyPath( _role, "private", _only_path ) );
590
QString publicKeyPath( const ISD::userRoles _role, bool _only_path )
592
return( keyPath( _role, "public", _only_path ) );
598
void setKeyPath( QString _path, const ISD::userRoles _role,
599
const QString _group )
601
_path = _path.left( 1 ) + _path.mid( 1 ).
602
replace( QString( QDir::separator() ) + QDir::separator(),
605
QSettings settings( QSettings::SystemScope, "iTALC Solutions",
607
if( _role <= ISD::RoleNone || _role >= ISD::RoleCount )
609
qWarning( "invalid role" );
612
settings.setValue( "keypaths" + _group + "/" +
613
userRoleNames[_role], _path );
617
void setPrivateKeyPath( const QString & _path, const ISD::userRoles _role )
619
setKeyPath( _path, _role, "private" );
625
void setPublicKeyPath( const QString & _path, const ISD::userRoles _role )
627
setKeyPath( _path, _role, "public" );
633
QString snapshotDir( void )
636
return( settings.value( "paths/snapshots",
638
windowsConfigPath( CSIDL_PERSONAL ) +
640
QObject::tr( "iTALC-snapshots" )
642
personalConfigDir() + "snapshots"
644
).toString() + QDir::separator() );
650
QString globalConfigPath( void )
653
return( settings.value( "paths/globalconfig", personalConfigDir() +
654
"globalconfig.xml" ).toString() );
660
QString personalConfigDir( void )
663
const QString d = settings.value( "paths/personalconfig" ).toString();
664
return( d.isEmpty() ?
666
windowsConfigPath( CSIDL_APPDATA ) +
667
QDir::separator() + "iTALC"
669
QDir::homePath() + QDir::separator() +
680
QString personalConfigPath( void )
683
const QString d = settings.value( "paths/personalconfig" ).toString();
684
return( d.isEmpty() ?
685
personalConfigDir() + "personalconfig.xml"
693
QString globalStartmenuDir( void )
696
return( windowsConfigPath( CSIDL_COMMON_STARTMENU ) +
699
return( "/usr/share/applnk/Applications/" );
706
QString parameter( const QString & _name )
708
return( QSettings().value( "parameters/" + _name ).toString() );
714
bool ensurePathExists( const QString & _path )
716
if( _path.isEmpty() || QDir( _path ).exists() )
721
QString p = QDir( _path ).absolutePath();
722
if( !QFileInfo( _path ).isDir() )
724
p = QFileInfo( _path ).absolutePath();
727
while( !QDir( p ).exists() && !p.isEmpty() )
729
dirs.push_front( QDir( p ).dirName() );
730
p.chop( dirs.front().size() + 1 );
734
return( QDir( p ).mkpath( dirs.join( QDir::separator() ) ) );
742
BOOL enablePrivilege( LPCTSTR lpszPrivilegeName, BOOL bEnable )
749
if( !OpenProcessToken( GetCurrentProcess(),
750
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY | TOKEN_READ, &hToken ) )
755
if( !LookupPrivilegeValue( NULL, lpszPrivilegeName, &luid ) )
760
tp.PrivilegeCount = 1;
761
tp.Privileges[0].Luid = luid;
762
tp.Privileges[0].Attributes = bEnable ? SE_PRIVILEGE_ENABLED : 0;
764
ret = AdjustTokenPrivileges( hToken, FALSE, &tp, 0, NULL, NULL );
766
CloseHandle( hToken );
774
void activateWindow( QWidget * _w )
776
_w->activateWindow();
779
SetWindowPos( _w->winId(), HWND_TOPMOST, 0, 0, 0, 0,
780
SWP_NOMOVE | SWP_NOSIZE );
781
SetWindowPos( _w->winId(), HWND_NOTOPMOST, 0, 0, 0, 0,
782
SWP_NOMOVE | SWP_NOSIZE );
787
} // end of namespace localSystem