1#!/usr/bin/perl 2 3############################################################################ 4# Copyright (C) 2005-2020 by Oleksandr Shneyder # 5# oleksandr.shneyder@obviously-nice.de # 6# # 7# This program is free software; you can redistribute it and/or modify # 8# it under the terms of the GNU General Public License as published by # 9# the Free Software Foundation; either version 2 of the License, or # 10# (at your option) any later version. # 11# # 12# This program is distributed in the hope that it will be useful, # 13# but WITHOUT ANY WARRANTY; without even the implied warranty of # 14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # 15# GNU General Public License for more details. # 16# # 17# You should have received a copy of the GNU General Public License # 18# along with this program; if not, write to the # 19# Free Software Foundation, Inc., # 20# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # 21############################################################################ 22 23 24 25use File::Path; 26use Proc::Simple; 27use Term::ReadPassword; 28use Getopt::Long; 29use strict; 30 31my $user; 32my $server; 33my $geometry="fullscreen"; 34my $link="lan"; 35my $pack="16m-jpeg-9"; 36my $type="unix-kde"; 37my $stype="desktop"; 38my $kbdlay="us"; 39my $kbdtype="pc105/us"; 40my $setkbd="0"; 41my $accept=0; 42my $sound=1; 43my $cmd="startkde"; 44my $ssh_key=0; 45my $port="22"; 46 47system ("rm -rf ~/.x2go/ssh/askpass*"); 48 49sub printpass 50{ 51 my $prog=shift; 52 my $pass=shift; 53 open (F,">$prog") or die "Couldn't open $prog for writing"; 54 print F '#!/usr/bin/perl 55 $param=shift;'; 56 print F " open (F,\">$prog.log\");"; 57 print F ' print F $param; 58 close (F); 59 if($param =~ m/RSA key/) 60 {'; 61 if($accept){ 62 print F 'print "yes\n";';} 63 else{ 64 print F 'print "no\n";';} 65 print F ' } 66 else 67 {'; 68 print F " print \"$pass\\n\"; 69 }"; 70 close(F); 71 chmod (0700, $prog); 72} 73 74sub checkstat 75{ 76 my $prog=shift; 77 open (F,"<$prog.log") or return; 78 my @outp; 79 my $ln=<F>; 80 for(my $i=0;$ln;$i++) 81 { 82 @outp[$i]=$ln; 83 $ln=<F>; 84 } 85 close(F); 86 if(join(" ",@outp) =~ m/Are you sure you want to continue connecting/) 87 { 88 print "@outp[0]@outp[1]"; 89 print "If you are sure you want to continue connecting, please launch this programm with --add-to-known-hosts yes\n"; 90 exit; 91 } 92} 93 94sub hidepass 95{ 96 my $prog=shift; 97 open (F,">$prog") or die "Couldn't open $prog for writing"; 98 print F "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; 99 close(F); 100} 101 102 103my $pack_methods= 104"nopack 1058 10664 107256 108512 1094k 11032k 11164k 112256k 1132m 11416m 115256-rdp 116256-rdp-compressed 11732k-rdp 11832k-rdp-compressed 11964k-rdp 12064k-rdp-compressed 12116m-rdp 12216m-rdp-compressed 123rfb-hextile 124rfb-tight 125rfb-tight-compressed 1268-tight 12764-tight 128256-tight 129512-tight 1304k-tight 13132k-tight 13264k-tight 133256k-tight 1342m-tight 13516m-tight 1368-jpeg-% 13764-jpeg 138256-jpeg 139512-jpeg 1404k-jpeg 14132k-jpeg 14264k-jpeg 143256k-jpeg 1442m-jpeg 14516m-jpeg-% 1468-png-jpeg-% 14764-png-jpeg 148256-png-jpeg 149512-png-jpeg 1504k-png-jpeg 15132k-png-jpeg 15264k-png-jpeg 153256k-png-jpeg 1542m-png-jpeg 15516m-png-jpeg-% 1568-png-% 15764-png 158256-png 159512-png 1604k-png 16132k-png 16264k-png 163256k-png 1642m-png 16516m-png-% 16616m-rgb-% 16716m-rle-%"; 168 169 170 171sub printargs 172{ 173 print "Usage: $0 --user <username> --server <hostname> [Options]\nOptions:\ 174 --help Print this message\ 175 --help-pack Print availabel pack methods 176 --user <username> Connect as user 'username'\ 177 --server <hostname> Connect to 'hostname'\ 178 --command <cmd> Run command 'cmd', default value 'startkde' 179 --port SSH port, default 22 180 --ssh-key <fname> Us 'fname' as a key for ssh connection 181 --add-to-known-hosts <yes|no> Add RSA key fingerprint to .ssh/known_hosts if authenticity of server can't be established, default value 'no' 182 --use-sound <yes|no> Start sound server and ssh tunel for sound connections, default value 'yes' 183 184 nxagent options: 185 --geometry <Width>x<Height> Set window size, default value 'fullscreen' 186 --link <modem|isdn|adsl|wan|lan> Set link type, default 'lan' 187 --pack <packmethod> Use pack method, default '16m-jpeg-9' 188 --session-type <type> Session type, 'desktop' or 'application' default 'desktop' 189 --kbd-layout <layout> Use keyboard layout, default 'us' 190 --kbd-type <type> Set Keyboard type, default 'pc105/us'\n"; 191exit; 192} 193 194sub printpack 195{ 196 my $m=$pack_methods; 197 $m=~s/%/[0-9]/g; 198 print "$m\n"; 199 exit; 200} 201 202sub check_pack 203{ 204 my $p=shift; 205 if($p =~ m/%/) 206 { 207 return 0; 208 } 209 my @arr=split("-","$p"); 210 my $pm=$pack_methods; 211 212 if(@arr>1) 213 { 214 my $qa=@arr[@arr-1]; 215 my @vals=unpack('cc',$qa); 216 if($qa ge '0' && $qa le '9' && @vals == 1) 217 { 218 $pm=~s/%/$qa/g; 219 } 220 } 221 222 my @met=split("\n","$pm"); 223 for(my $i=0;$i<@met;$i++) 224 { 225 if(@met[$i] eq $p) 226 { 227 return 1; 228 } 229 } 230 return 0; 231} 232 233 234sub getindex 235{ 236 my @sess=@_; 237 print("Number\tStatus\t\tCreation time\t\tDisplay\tClient IP\n"); 238 for(my $i=1;$i<=@sess;$i++) 239 { 240 my @vals=split('\\|',"@sess[$i-1]"); 241 my $status=@vals[4]; 242 if(@vals[4] eq 'S') 243 { 244 $status='Suspended' 245 } 246 elsif(@vals[4] eq 'R') 247 { 248 $status='Running ' 249 } 250 print "$i)\t$status\t@vals[5]\t@vals[2]\t@vals[7]\n"; 251 } 252 print "Enter numer of session to resume or 'n' to start new session: "; 253 my $answ=<STDIN>; 254 chomp($answ); 255 if($answ > 0 && $answ <= @sess) 256 { 257 my @vals=split('\\|',"@sess[$answ-1]"); 258 if(@vals[4] eq 'R') 259 { 260 print("Session is already running on @vals[7], continue? (y/n): "); 261 my $nansw=<STDIN>; 262 chomp($nansw); 263 if($nansw eq 'y') 264 { 265 return $answ; 266 } 267 else 268 { 269 return -1; 270 } 271 } 272 else 273 { 274 return $answ; 275 } 276 } 277 elsif ($answ eq "n") 278 { 279 return 0; 280 } 281 else 282 { 283 print "Input Error\n"; 284 return -1; 285 } 286} 287 288 289 290 291GetOptions("user=s" => \$user, 292"server=s" => \$server, 293"command=s" => \$cmd, 294"port=s" => \$port, 295"ssh-key=s" => \$ssh_key, 296"add-to-known-hosts=s" => \$accept, 297"use-sound=s" => \$sound, 298"geometry=s" => \$geometry, 299"link=s" => \$link, 300"pack=s" => \$pack, 301"session-type=s" => \$stype, 302"kbd-layout=s" => \$kbdlay, 303"kbd-type=s" => \$kbdtype, 304'help-pack' => \&printpack, 305'help' => \&printargs) or printargs; 306printargs unless (($user and $server)); 307 308 309 if($ssh_key) 310 { 311 if ( ! -e $ssh_key) 312 { 313 print "Error, $ssh_key not exists\n"; 314 exit; 315 } 316 } 317 if($kbdlay or $kbdtype) 318 { 319 $setkbd=1; 320 } 321 322 if(($link ne "modem" )&&($link ne "isdn")&&($link ne "adsl")&&($link ne "wan")&&($link ne "lan")) 323 { 324 print "Error parsing command line, wrong \"link\" argument\n"; 325 printargs; 326 exit; 327 } 328 329 if(! check_pack($pack) ) 330 { 331 print "Error parsing command line, wrong \"pack\" argument\n"; 332 printargs; 333 exit; 334 } 335 336 if($accept) 337 { 338 if($accept eq "yes") 339 { 340 $accept=1; 341 } 342 elsif($accept eq "no") 343 { 344 $accept=0; 345 } 346 else 347 { 348 print "Error parsing command line, wrong \"add-to-known-hosts\" argument\n"; 349 printargs; 350 exit; 351 } 352 } 353 354 if($sound != 1) 355 { 356 if($sound eq "yes") 357 { 358 $sound=1; 359 } 360 elsif($sound eq "no") 361 { 362 $sound=0; 363 } 364 else 365 { 366 print "Error parsing command line, wrong \"use-sound\" argument\n"; 367 printargs; 368 exit; 369 } 370 } 371 372 373my $nxroot="$ENV{'HOME'}/.x2go"; 374my $dirpath="$nxroot/ssh"; 375eval 376{ 377 mkpath($dirpath) 378}; 379if ($@) 380{ 381 print "Couldn't create $dirpath: $@"; 382 exit; 383} 384 385my $askpass="$dirpath/askpass"; 386my $pass; 387my $sessions; 388if(!$ssh_key) 389{ 390 $pass=read_password('Password:'); 391 printpass $askpass,$pass; 392 $sessions=`DISPLAY=:0 SSH_ASKPASS=$askpass setsid ssh -p $port $user\@$server "x2golistsessions"`; 393 hidepass $askpass; 394 checkstat $askpass; 395} 396else 397{ 398 $sessions=`ssh -p $port -i $ssh_key $user\@$server "x2golistsessions"`; 399} 400 401my @sess=split("\n","$sessions"); 402my $newses=0; 403 404 405my $snum=-1;#index of session+1,-1 - error, -0 - new session 406if (@sess == 0) 407{ 408 $newses=1; 409} 410else 411{ 412 my @lines=split('\\|',"@sess[0]"); 413 my $status=@lines[4]; 414 if($status eq 'S' && @sess == 1) 415 { 416 $snum=0; 417 } 418 else 419 { 420 while($snum==-1) 421 { 422 $snum=getindex(@sess); 423 } 424 if($snum == 0) 425 { 426 $newses=1; 427 } 428 else 429 { 430 $snum--; 431 } 432 } 433} 434 435my $disp; 436my $snd_port; 437my $gr_port; 438my $cookie; 439my $agentpid; 440my $sname; 441my $t="D"; 442if( $stype eq "application" ) 443{ 444 $t="R"; 445} 446if($newses) 447{ 448 my $outp; 449 if(! $ssh_key) 450 { 451 printpass $askpass,$pass; 452 $outp=`DISPLAY=:0 SSH_ASKPASS=$askpass setsid ssh -p $port $user\@$server "x2gostartagent $geometry $link $pack $type $kbdlay $kbdtype $setkbd $t"`; 453 hidepass $askpass; 454 checkstat $askpass; 455 } 456 else 457 { 458 $outp=`ssh -p $port -i $ssh_key $user\@$server "x2gostartagent $geometry $link $pack $type $kbdlay $kbdtype $setkbd $t"`; 459 } 460 my @lines=split("\n","$outp"); 461 $disp=@lines[0]; 462 $cookie=@lines[1]; 463 $agentpid=@lines[2]; 464 $sname=@lines[3]; 465 $gr_port=@lines[4]; 466 $snd_port=@lines[5]; 467# print ":$disp $cookie $agentpid $sname $gr_port $snd_port\n"; 468} 469else 470{ 471 my @lines=split('\\|',"@sess[$snum]"); 472 $agentpid=@lines[0]; 473 $sname=@lines[1]; 474 $disp=@lines[2]; 475 my $status=@lines[4]; 476 $cookie=@lines[6]; 477 $gr_port=@lines[8]; 478 $snd_port=@lines[9]; 479 480 if($status eq 'R') 481 { 482 if(! $ssh_key) 483 { 484 printpass $askpass,$pass; 485 system("DISPLAY=:0 SSH_ASKPASS=$askpass setsid ssh -p $port $user\@$server \"setsid x2gosuspend-session $sname\""); 486 hidepass $askpass; 487 checkstat $askpass; 488 } 489 else 490 { 491 system("ssh -p $port -i $ssh_key $user\@$server \"setsid x2gosuspend-session $sname\""); 492 } 493 sleep (1); 494 } 495 if(! $ssh_key) 496 { 497 printpass $askpass,$pass; 498 system("DISPLAY=:0 SSH_ASKPASS=$askpass setsid ssh -p $port $user\@$server \"setsid x2goresume-session $sname $geometry $link $pack $kbdlay $kbdtype $setkbd\""); 499 hidepass $askpass; 500 checkstat $askpass; 501 } 502 else 503 { 504 system("ssh -p $port -i $ssh_key $user\@$server \"setsid x2goresume-session $sname $geometry $link $pack $kbdlay $kbdtype $setkbd\""); 505 } 506} 507my $tunnel = Proc::Simple->new(); 508my $snd_tun; 509my $snd_server; 510if($sound) 511{ 512 $snd_tun= Proc::Simple->new(); 513 $snd_server= Proc::Simple->new(); 514 $snd_server->start("artsd -u -N -p $snd_port"); 515} 516if( !$ssh_key) 517{ 518 printpass $askpass,$pass; 519 $tunnel->start("DISPLAY=:0 SSH_ASKPASS=$askpass setsid ssh -p $port -N -L $gr_port:localhost:$gr_port $user\@$server"); 520 if($sound) 521 { 522 $snd_tun->start("DISPLAY=:0 SSH_ASKPASS=$askpass setsid ssh -p $port -N -R $snd_port:localhost:$snd_port $user\@$server"); 523 } 524} 525else 526{ 527 $tunnel->start("ssh -p $port -i $ssh_key -N -L $gr_port:localhost:$gr_port $user\@$server"); 528 if($sound) 529 { 530 $snd_tun->start("ssh -p $port -i $ssh_key -N -R $snd_port:localhost:$snd_port $user\@$server"); 531 } 532} 533 534sleep 2; 535$dirpath="$nxroot/S-$sname"; 536eval 537{ 538 mkpath($dirpath) 539}; 540if ($@) 541{ 542 print "Couldn't create $dirpath: $@"; 543 hidepass $askpass; 544 exit; 545} 546 547my $nx_host="nx/nx,composite=1,root=$nxroot,connect=localhost,cookie=$cookie,port=$gr_port,errors=$dirpath/session"; 548 549open (FILE,">$dirpath/options")or die "Couldnt't open $dirpath/options for writing"; 550print FILE "$nx_host:$disp"; 551close (FILE); 552my $proxy = Proc::Simple->new(); 553$proxy->start("LD_LIBRARY_PATH=\$X2GO_LIB nxproxy -S nx/nx,options=$dirpath/options:$disp 2>>$dirpath/session"); 554if($newses) 555{ 556 if(! $ssh_key) 557 { 558 system("DISPLAY=:0 SSH_ASKPASS=$askpass setsid ssh -p $port $user\@$server \"setsid x2goruncommand $disp $agentpid $sname $snd_port $cmd arts $t >& /dev/null & exit \""); 559 } 560 else 561 { 562 system("ssh -p $port -i $ssh_key $user\@$server \"setsid x2goruncommand $disp $agentpid $sname $snd_port $cmd arts $t>& /dev/null & exit \""); 563 } 564} 565 566#hidepass $askpass; 567#checkstat $askpass; 568while($proxy->poll()) 569{ 570 sleep(1); 571} 572$tunnel->kill(); 573if($sound) 574{ 575 $snd_server->kill(); 576 $snd_tun->kill(); 577} 578system ("rm -rf ~/.x2go/ssh/askpass*"); 579