Skip to content
Snippets Groups Projects
Commit a1bf0ca5 authored by Mestre's avatar Mestre
Browse files

Very first commit

parents
No related branches found
No related tags found
No related merge requests found
Showing
with 2250 additions and 0 deletions
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="gen"/>
<classpathentry kind="src" path="jni"/>
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
<classpathentry kind="output" path="bin"/>
</classpath>
bin/*
gen/*
stuff/*
.settings/*
res/*
.project 0 → 100644
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>DroidSSHdaemon</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.ApkBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>com.android.ide.eclipse.adt.AndroidNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="br.com.bott.droidsshd"
android:versionCode="5"
android:versionName="0.5"
android:installLocation="auto">
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.PERSISTENT_ACTIVITY" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<!-- <uses-permission android:name="android.permission.READ_PHONE_STATE" />-->
<application android:icon="@drawable/ssh_icon"
android:label="@string/app_label"
android:persistent="true">
<service
android:name="br.com.bott.droidsshd.system.DroidSSHdService">
<intent-filter>
<action
android:name="br.com.bott.droidsshd.system.DroidSSHdService">
</action>
</intent-filter>
</service>
<activity
android:name="br.com.bott.droidsshd.DroidSSHd">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="br.com.bott.droidsshd.activity.Preferences"/>
<activity android:name="br.com.bott.droidsshd.activity.InitialSetup"/>
<activity android:name="com.h3r3t1c.filechooser.FileChooser">
<intent-filter>
<action android:name="br.com.bott.droidsshd.AUTHORIZED_KEYS"/>
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<receiver android:name="br.com.bott.droidsshd.system.BootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<category android:name="android.intent.category.HOME" />
</intent-filter>
</receiver>
</application>
<uses-sdk android:minSdkVersion="7" android:targetSdkVersion="8"/>
</manifest>
<!-- <permission android:name="android.permission.PERSISTENT_ACTIVITY" />-->
<!---->
File added
# This file is automatically generated by Android Tools.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file must be checked in Version Control Systems.
#
# To customize properties used by the Ant build system use,
# "build.properties", and override values to adapt the script to your
# project structure.
# Indicates whether an apk should be generated for each density.
split.density=false
# Project target.
target=android-8
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := br_com_bott_droidsshd_system_NativeTask.c
#LOCAL_SHARED_LIBRARIES := libcutils
LOCAL_LDLIBS += -llog
LOCAL_C_INCLUDES += $(JNI_H_INCLUDE)
LOCAL_C_INCLUDES += /home/mestre/android/original_source/system/core/include
LOCAL_MODULE := libNativeTask
include $(BUILD_SHARED_LIBRARY)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include "br_com_bott_droidsshd_system_NativeTask.h"
/* #include <android/log.h> */
JNIEXPORT jint JNICALL Java_br_com_bott_droidsshd_system_NativeTask_runCommand
(JNIEnv *env, jclass class, jstring command)
{
const char *commandString;
commandString = (*env)->GetStringUTFChars(env, command, 0);
int exitcode = system(commandString);
(*env)->ReleaseStringUTFChars(env, command, commandString);
return (jint)exitcode;
}
JNIEXPORT jint JNICALL Java_br_com_bott_droidsshd_system_NativeTask_chmod
(JNIEnv *env, jclass class, jstring path, jint mode)
{
const char *pathString = (*env)->GetStringUTFChars(env, path, 0);
// 0 = success
// -1 = failed to run fchmod
// -2 = can't even open file
int exitcode=-2;
// apparently we don't have 'chmod' available on bionic
// so we work around this by using 'fchmod' :-)
int fd = open(pathString, O_RDONLY);
if (fd) {
exitcode = fchmod(fd, mode);
close(fd);
}
// __android_log_print(ANDROID_LOG_DEBUG, "DroidSSHdNT", "PATH: [%s]", pathString);
// __android_log_print(ANDROID_LOG_DEBUG, "DroidSSHdNT", "MODE DEC: [%d]", mode);
// __android_log_print(ANDROID_LOG_DEBUG, "DroidSSHdNT", "MODE OCT: [%o]", mode);
(*env)->ReleaseStringUTFChars(env, path, pathString);
return (jint)exitcode;
}
JNIEXPORT jint JNICALL Java_br_com_bott_droidsshd_system_NativeTask_symlink
(JNIEnv *env, jclass class, jstring original, jstring destination)
{
const char *originalString;
const char *destinationString;
originalString = (*env)->GetStringUTFChars(env, original, 0);
destinationString = (*env)->GetStringUTFChars(env, destination, 0);
int exitcode = symlink(originalString, destinationString);
(*env)->ReleaseStringUTFChars(env, original, originalString);
(*env)->ReleaseStringUTFChars(env, destination, destinationString);
return (jint)exitcode;
}
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class br_com_bott_droidsshd_system_NativeTask */
#ifndef _Included_br_com_bott_droidsshd_system_NativeTask
#define _Included_br_com_bott_droidsshd_system_NativeTask
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: br_com_bott_droidsshd_system_NativeTask
* Method: runCommand
* Signature: (Ljava/lang/String;)I
*/
JNIEXPORT jint JNICALL Java_br_com_bott_droidsshd_system_NativeTask_runCommand
(JNIEnv *, jclass, jstring);
/*
* Class: br_com_bott_droidsshd_system_NativeTask
* Method: chmod
* Signature: (Ljava/lang/String;I)I
*/
JNIEXPORT jint JNICALL Java_br_com_bott_droidsshd_system_NativeTask_chmod
(JNIEnv *, jclass, jstring, jint);
/*
* Class: br_com_bott_droidsshd_system_NativeTask
* Method: symlink
* Signature: (Ljava/lang/String;Ljava/lang/String;)I
*/
JNIEXPORT jint JNICALL Java_br_com_bott_droidsshd_system_NativeTask_symlink
(JNIEnv *, jclass, jstring, jstring);
#ifdef __cplusplus
}
#endif
#endif
File added
/**
* This file is part of DroidSSHd.
* http://code.google.com/p/droidsshd
*
* DroidSSHd is open source software: you can redistribute it and/or modify
* it under the terms of the Apache License 2.0
*
* DroidSSHd 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.
* @author Augusto Bott (mestre) <augusto@bott.com.br>
*/
package br.com.bott.droidsshd;
import br.com.bott.droidsshd.system.*;
import br.com.bott.droidsshd.tools.*;
import java.util.Iterator;
import android.util.Log;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
//import android.os.Message;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
//import android.widget.ScrollView;
public class DroidSSHd extends Activity {
private static final String TAG = "DroidSSHd";
// http://developer.android.com/reference/java/lang/Thread.html#setDaemon%28boolean%29
// http://stackoverflow.com/questions/3011604/how-do-i-get-preferences-to-work-in-android
// http://stackoverflow.com/questions/2535132/how-do-you-validate-the-format-and-values-of-edittextpreference-entered-in-androi
private Button btnStartStop;
private EditText status_content;
private EditText status_ip_address;
private EditText status_username;
private EditText status_tcp_port;
private CheckBox status_daemon_running_as_root;
private Button preferences_button;
private ReplicantThread mMonitorDaemon;
private Intent mDropbearDaemonHandlerService;
private DroidSSHdService mBoundDaemonHandlerService;
private boolean mDaemonHandlerIsBound;
private long mUpdateUIdelay = 500L;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Base.initialize(getBaseContext());
setContentView(R.layout.act_main);
Base.setDropbearDaemonStatus(Base.DAEMON_STATUS_STOPPED);
setUpUiListeners();
mDropbearDaemonHandlerService = new Intent(this, br.com.bott.droidsshd.system.DroidSSHdService.class);
if ((!Util.validateHostKeys() || (!Util.checkPathToBinaries()))) {
startInitialSetupActivity();
}
}
// DAEMON HANDLER
private ServiceConnection mDaemonHandlerConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className, IBinder service) {
mBoundDaemonHandlerService = ((br.com.bott.droidsshd.system.DroidSSHdService.DropbearDaemonHandlerBinder)service).getService();
if(Base.debug) {
Log.d(TAG, "onServiceConnected DroidSSHdService called");
if (mBoundDaemonHandlerService==null){
Log.d(TAG, "Failed to bind to DroidSSHdService (mBoundDaemonHandlerService is NULL)");
} else {
Log.d(TAG, "mBoundDaemonHandlerService = " + mBoundDaemonHandlerService.toString());
}
}
}
@Override
public void onServiceDisconnected(ComponentName className) {
mBoundDaemonHandlerService = null;
if(Base.debug) {
Log.d(TAG, "onServiceDisconnected called (mBoundDaemonHandlerService set to NULL)");
}
}
};
private void doBindDaemonHandlerService(Intent intent) {
mDaemonHandlerIsBound = bindService(intent, mDaemonHandlerConnection, Context.BIND_AUTO_CREATE);
}
private void doUnbindDaemonHandlerService(Intent intent) {
if (mDaemonHandlerIsBound) {
unbindService(mDaemonHandlerConnection);
mDaemonHandlerIsBound = false;
}
}
protected void startInitialSetupActivity() {
Util.showMsg("Initial/basic setup required");
Intent setup = new Intent(this, br.com.bott.droidsshd.activity.InitialSetup.class);
setup.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
// setup.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
startActivityForResult(setup, R.string.activity_initial_setup);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (Base.debug) {
if (data!=null) {
Log.v(TAG, "onActivityResult(" + requestCode + ", " + resultCode + ", " + data.toString() + ") called");
} else {
Log.v(TAG, "onActivityResult(" + requestCode + ", " + resultCode + ", null) called");
}
}
if(resultCode==RESULT_CANCELED && requestCode==R.string.activity_initial_setup){
Util.showMsg("DroidSSHd setup canceled");
this.finish();
}
/* if (requestCode==R.string.activity_file_chooser) {
if(Base.debug) {
Log.v(TAG, "FileChooser is done");
}
if(resultCode==RESULT_OK){
if(Base.debug){
Log.v(TAG,"path = " + data.getStringExtra("path"));
}
}
}*/
}
protected void setUpUiListeners() {
status_content = (EditText) findViewById(R.id.status_content);
status_ip_address = (EditText) findViewById(R.id.status_ip_address);
status_username = (EditText) findViewById(R.id.status_username);
status_tcp_port = (EditText) findViewById(R.id.status_tcp_port);
status_daemon_running_as_root = (CheckBox) findViewById(R.id.status_daemon_running_as_root);
btnStartStop = (Button) findViewById(R.id.status_button);
btnStartStop.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
btnStartStop.setEnabled(false);
btnStartStop.setFocusable(false);
btnStartStop.setText("Working");
if (Util.isDropbearDaemonRunning()) {
if(Base.debug) {
Log.v(TAG, "btnStartStop pressed: stopping");
}
stopDropbear();
} else {
if(Base.debug) {
Log.v(TAG, "btnStartStop pressed: starting");
}
startDropbear();
}
// setResult(android.app.Activity.RESULT_OK);
}
});
// mStdOut = (EditText) findViewById(R.id.stdout);
// mLogView = (ScrollView) findViewById(R.id.stdout_scrollview);
/* filechooser_button = (Button) findViewById(R.id.filechooser_button);
filechooser_button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent p = new Intent(v.getContext(), com.h3r3t1c.filechooser.FileChooser.class);
startActivityForResult(p, R.string.activity_file_chooser);
}
});*/
preferences_button = (Button) findViewById(R.id.preferences_button);
preferences_button.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
Intent p = new Intent(v.getContext(), br.com.bott.droidsshd.activity.Preferences.class);
startActivity(p);
}
});
}
@Override
protected void onStart() {
super.onStart();
doBindDaemonHandlerService(mDropbearDaemonHandlerService);
}
@Override
protected void onStop() {
super.onStop();
doUnbindDaemonHandlerService(mDropbearDaemonHandlerService);
}
@Override
protected void onResume() {
super.onResume();
Base.refresh();
mHandler.postDelayed(mUpdateUI, mUpdateUIdelay);
// updateStatus();
if(Base.debug) {
Log.d(TAG, "onResume() called");
}
}
public void updateStatus() {
String tmp = "";
Iterator<String> ipAddr = Util.getLocalIpAddress();
while(ipAddr.hasNext()) {
tmp = tmp + ipAddr.next() + " ";
if (ipAddr.hasNext()) {
tmp = tmp + ", ";
}
}
status_ip_address.setText(tmp);
status_username.setText(Base.getUsername());
status_tcp_port.setText(String.valueOf(Base.getDaemonPort()));
status_daemon_running_as_root.setChecked(Base.runDaemonAsRoot());
if (Util.isDropbearDaemonRunning()) {
Base.setDropbearDaemonStatus(Base.DAEMON_STATUS_STARTED);
}
switch (Base.getDropbearDaemonStatus()) {
case Base.DAEMON_STATUS_STOPPING:
btnStartStop.setEnabled(false);
btnStartStop.setFocusable(false);
btnStartStop.setText("Stopping");
status_content.setText("Working");
break;
case Base.DAEMON_STATUS_STARTING:
btnStartStop.setEnabled(false);
btnStartStop.setFocusable(false);
btnStartStop.setText("Starting");
status_content.setText("Working");
break;
case Base.DAEMON_STATUS_STARTED:
btnStartStop.setEnabled(true);
btnStartStop.setFocusable(true);
btnStartStop.setText("Stop");
status_content.setText("Running");
break;
case Base.DAEMON_STATUS_STOPPED:
btnStartStop.setEnabled(true);
btnStartStop.setFocusable(true);
btnStartStop.setText("Start");
status_content.setText("Stopped");
break;
default:
break;
}
}
public void startDropbear() {
if (!Util.checkPathToBinaries()) {
if(Base.debug) {
Log.v(TAG, "startDropbear bailing out: status was " + Base.getDropbearDaemonStatus() + ", changed to STOPPED(" + ")" );
}
Base.setDropbearDaemonStatus(Base.DAEMON_STATUS_STOPPED);
mHandler.postDelayed(mUpdateUI, mUpdateUIdelay);
Util.showMsg("Can't find dropbear binaries");
return;
}
if (!Util.validateHostKeys()) {
if(Base.debug) {
Log.v(TAG, "Host keys not found");
}
Base.setDropbearDaemonStatus(Base.DAEMON_STATUS_STOPPED);
mHandler.postDelayed(mUpdateUI, mUpdateUIdelay);
Util.showMsg("Host keys not found");
return;
}
if(Base.getDropbearDaemonStatus() == Base.DAEMON_STATUS_STOPPED) {
Base.setDropbearDaemonStatus(Base.DAEMON_STATUS_STARTING);
if (Base.debug) {
Log.d(TAG, "Status was STOPPED, now it's STARTING");
}
startService(mDropbearDaemonHandlerService);
startLongRunningOperation();
}
}
public void stopDropbear() {
if (Base.debug) {
Log.v(TAG, "stopDropbear() called. Current status = " + Base.getDropbearDaemonStatus() );
}
if ((Base.getDropbearDaemonStatus()==Base.DAEMON_STATUS_STARTED) ||
Base.getDropbearDaemonStatus()==Base.DAEMON_STATUS_STARTING) {
Base.setDropbearDaemonStatus(Base.DAEMON_STATUS_STOPPING);
int pid = Util.getDropbearPidFromPidFile(Base.getDropbearPidFilePath());
if(Base.debug) {
Log.d(TAG, "stopDropbear() killing pid " + pid);
Log.d(TAG, "dropbearDaemonStatus = Base.DAEMON_STATUS_STOPPING");
}
String cmd = "kill -2 " + pid;
// Util.doRun(cmd, Base.runDaemonAsRoot(), mLogviewHandler);
Util.doRun(cmd, Base.runDaemonAsRoot(), null);
stopService(mDropbearDaemonHandlerService);
}
startLongRunningOperation();
Util.releaseWakeLock();
Util.releaseWifiLock();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main_menu, menu);
return true;
// return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch(item.getItemId()) {
case R.id.menu_settings:
Intent p = new Intent(this, br.com.bott.droidsshd.activity.Preferences.class);
startActivity(p);
return true;
case R.id.menu_quit:
Util.showMsg("QUIT");
this.finish();
return true;
case R.id.menu_refreshui:
if(Base.getDropbearDaemonStatus()==Base.DAEMON_STATUS_STARTING) {
Base.setDropbearDaemonStatus(Base.DAEMON_STATUS_STARTED);
}
if(Base.getDropbearDaemonStatus()==Base.DAEMON_STATUS_STOPPING) {
Base.setDropbearDaemonStatus(Base.DAEMON_STATUS_STOPPED);
}
updateStatus();
return true;
case R.id.menu_about:
// Intent i = new Intent();
// i.setAction("android.intent.action.VIEW");
// i.setData("http://www.android.com");
// i.setType(type)
Util.showMsg("About");
return true;
default:
return super.onOptionsItemSelected(item);
}
}
final Handler mHandler = new Handler();
final Runnable mUpdateUI = new Runnable() {
public void run() {
updateStatus();
}
};
// TODO - http://developer.android.com/resources/articles/painless-threading.html
protected void startLongRunningOperation() {
synchronized(this) {
if (Base.debug) {
Log.d(TAG, "startLongRunningOperation called");
}
// TODO - http://developer.android.com/resources/articles/timed-ui-updates.html
// Runnable mUpdateTimeTask = new Runnable() {
// public void run() {
// final long start = mStartTime;
// long millis = SystemClock.uptimeMillis() - start;
// mHandler.postAtTime(this, start + (((minutes * 60) + seconds + 1) * 1000));
// }
// mHandler.removeCallbacks(mUpdateTimeTask);
if(mMonitorDaemon!=null) {
if(mMonitorDaemon.isAlive()) {
mMonitorDaemon.extendLifetimeForAnother(System.currentTimeMillis()+2000);
}
} else {
ReplicantThread mMonitorDaemon = new ReplicantThread(TAG, (System.currentTimeMillis()+2000), 600, mHandler, mUpdateUI, Base.debug);
mMonitorDaemon.start();
}
}
}
/* final protected Handler mLogviewHandler = new Handler() {
@Override
public void handleMessage(Message msg){
// mStdOut.append(msg.getData().getString("line"));
// mLogView.postDelayed(new Runnable() {
// public void run() {
// mLogView.fullScroll(ScrollView.FOCUS_DOWN);
// }
// }, 200);
}
};
*/
}
/**
*
*/
package br.com.bott.droidsshd.activity;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import br.com.bott.droidsshd.R;
import br.com.bott.droidsshd.system.Base;
import br.com.bott.droidsshd.system.Util;
import br.com.bott.droidsshd.tools.ShellSession;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
/**
* @author mestre
*
*/
public class InitialSetup extends Activity {
private static final String TAG = "DroidSSHd-Setup";
protected ProgressDialog dialog;
private Button buttonOk;
private Button buttonCancel;
private TextView textInitialSetup;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (Base.getContext() == null) {
Base.initialize(getBaseContext());
} else {
Base.refresh();
}
// requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.setup);
if (Base.debug) {
Log.d(TAG, "onCreate() called...");
}
textInitialSetup = (TextView) findViewById(R.id.text_initial_setup);
buttonOk = (Button) findViewById(R.id.button_initial_setup_ok);
buttonOk.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
doInitialSetupDone();
}
});
buttonCancel = (Button) findViewById(R.id.button_initial_setup_cancel);
buttonCancel.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
setResult(RESULT_CANCELED, getIntent());
finish();
// finishActivity(R.string.activity_initial_setup);
}
});
}
/* @Override
protected void onResume() {
super.onResume();
Base.refresh();
if (Base.debug) {
Log.d(TAG, "onResume() called...");
}
}
*/
final Handler handler = new Handler() {
public void handleMessage(Message msg) {
int step = msg.getData().getInt("step");
String text = msg.getData().getString("text");
dialog.setProgress(step);
dialog.setMessage(text);
if (step >= dialog.getMax()) {
dialog.dismiss();
}
}
};
protected class ProgressThread extends Thread {
Handler h;
int step;
int total;
ProgressThread(Handler h) {
this.h = h;
}
public void run() {
Message message = null;
Bundle data = new Bundle();
message = new Message();
data.putString("text", "Creating directories");
data.putInt("step", 1);
message.setData(data);
h.sendMessage(message);
// Util.mysleep(200);
setupDirectoryStructure();
message = new Message();
data.putString("text", "Deploying dropbear binaries");
data.putInt("step", 2);
message.setData(data);
h.sendMessage(message);
// Util.mysleep(200);
deployDropbearBinaries();
message = new Message();
data.putString("text", "Generating DSS host key. This may take a while...");
data.putInt("step", 3);
message.setData(data);
h.sendMessage(message);
// Util.mysleep(200);
generateHostKey(Base.DROPBEAR_DSS_HOST_KEY);
message = new Message();
data.putString("text", "Generating RSA host key. This may take a while...");
data.putInt("step", 4);
message.setData(data);
h.sendMessage(message);
// Util.mysleep(500);
generateHostKey(Base.DROPBEAR_RSA_HOST_KEY);
message = new Message();
data.putString("text", "Done. Launching preferences...");
data.putInt("step", 5);
message.setData(data);
h.sendMessage(message);
// Util.mysleep(200);
weAreInFactDone();
}
}
protected void doInitialSetupDone() {
if (Base.debug) {
Log.d(TAG, "doInitialSetupDone() called...");
}
dialog = new ProgressDialog(InitialSetup.this);
dialog.setMessage("Performing initial setup...");
dialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
// dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
dialog.setProgress(0);
dialog.setCancelable(false);
dialog.setMax(5);
dialog.show();
buttonOk.setVisibility(View.INVISIBLE);
buttonCancel.setVisibility(View.INVISIBLE);
textInitialSetup.setVisibility(View.INVISIBLE);
ProgressThread pt = new ProgressThread(handler);
pt.start();
}
protected void weAreInFactDone() {
// dialog.dismiss();
// finish();
setResult(RESULT_OK, getIntent());
finishActivity(R.string.activity_initial_setup);
Intent p = new Intent(Base.getContext(), br.com.bott.droidsshd.activity.Preferences.class);
startActivity(p);
}
protected boolean setupDirectoryStructure() {
// files/bin - binaries
Util.mkdir(Base.getDropbearBinDirPath());
Util.chmod(Base.getDropbearBinDirPath(), 0755);
// files/run - pidfile
Util.mkdir(Base.getDropbearTmpDirPath());
Util.chmod(Base.getDropbearTmpDirPath(), 0775);
// files/etc - authorized pubkeys and host keys
Util.mkdir(Base.getDropbearEtcDirPath());
Util.chmod(Base.getDropbearEtcDirPath(), 0700);
return true;
}
protected boolean deployDropbearBinaries() {
String path = Base.getDropbearBinDirPath() + "/" + Base.DROPBEAR_BIN_MUL;
File dest = new File(path);
if (dest.exists()) {
Log.e(TAG, "deployDropbearBinaries: " + path + " already exists!");
// TODO - dropbearmulti might be there, but... are symlinks/permissions set?
// TODO - yeah, yeah - it's highly unlikely... so probably WONTFIX
return false;
}
try {
InputStream is = getAssets().open(Base.DROPBEAR_BIN_MUL);
FileOutputStream os = new FileOutputStream(path);
byte[] buffer = new byte[4096];
int count;
while ((count = is.read(buffer)) != -1) {
os.write(buffer, 0, count);
}
is.close();
os.close();
} catch (IOException e) {
Log.e(TAG, "Exception when copying asset dropbearmulti: ", e);
e.printStackTrace();
return false;
}
Util.chmod(path, 0755);
Util.symlink(path, Base.getDropbearBinDirPath() + "/"
+ Base.DROPBEAR_BIN_SRV);
Util.symlink(path, Base.getDropbearBinDirPath() + "/"
+ Base.DROPBEAR_BIN_KEY);
Util.symlink(path, Base.getDropbearBinDirPath() + "/"
+ Base.DROPBEAR_BIN_SCP);
return true;
}
public boolean generateHostKey(String which) {
String path = "";
String type = "none";
if (which == Base.DROPBEAR_DSS_HOST_KEY) {
type = "dss";
path = Base.getDropbearDssHostKeyFilePath();
}
if (which == Base.DROPBEAR_RSA_HOST_KEY) {
type = "rsa";
path = Base.getDropbearRsaHostKeyFilePath();
}
if (type == "none") {
Log.e(TAG,
"generateHostKey has been asked to create an unknown type of key: " + which);
return false;
}
String cmd = Base.getDropbearBinDirPath() + "/" + Base.DROPBEAR_BIN_KEY
+ " -t " + type + " -f " + path;
if (Base.debug) {
Log.v(TAG, "generateHostKey('" + which + "'), keyType = " + type);
Log.v(TAG, "cmd = '" + cmd + "'");
}
ShellSession p = new ShellSession(TAG + "-shell", cmd, false,
Base.debug);
try {
p.start();
p.join();
p.waitFor();
} catch (InterruptedException e) {
// TODO - do we really care? :-)
// TODO - I mean: host keys are 'checked' in lots of places already :-)
// TODO - yeah, yeah - it's highly unlikely... so probably WONTFIX
// e.printStackTrace();
}
return true;
}
}
/**
*
*/
package br.com.bott.droidsshd.activity;
import java.io.File;
import br.com.bott.droidsshd.R;
import br.com.bott.droidsshd.system.Base;
import br.com.bott.droidsshd.system.Util;
import br.com.bott.droidsshd.tools.NumberPickerPreference;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.os.Bundle;
import android.preference.CheckBoxPreference;
import android.util.Log;
/**
* @author mestre
*
*/
public class Preferences extends PreferenceActivity
implements OnSharedPreferenceChangeListener {
private static final String TAG = "DroidSSHd-Prefs";
private CheckBoxPreference mDebug;
// private EditTextPreference mPort;
protected NumberPickerPreference mPort;
private Preference mAuthorizedKeys;
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
addPreferencesFromResource(R.xml.preferences);
mDebug = (CheckBoxPreference) findPreference(getString(R.string.pref_debug_key));
if (mDebug.isChecked()) {
Log.v(TAG, "onCreate called");
}
// mPort = (EditTextPreference) findPreference(getString(R.string.pref_dropbear_port_key));
// mPort.getEditText().setKeyListener(new DialerKeyListener());
mPort = (NumberPickerPreference) findPreference(getString(R.string.pref_dropbear_port_key));
mAuthorizedKeys = findPreference("authorized_keys_key");
mAuthorizedKeys.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
public boolean onPreferenceClick(Preference preference) {
Intent p = new Intent(getBaseContext(), com.h3r3t1c.filechooser.FileChooser.class);
startActivityForResult(p, R.string.activity_file_chooser);
return true;
}
});
}
@Override
protected void onResume() {
super.onResume();
if (mDebug.isChecked()) {
Log.v(TAG, "onResume called");
}
getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
// mPort.setSummary(getString(R.string.pref_dropbear_port_summary) + " " + mPort.getText());
mPort.setSummary(getString(R.string.pref_dropbear_port_summary) + " " + mPort.getValue());
}
@Override
protected void onPause() {
super.onPause();
getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this);
}
@Override
public void onBackPressed() {
Intent i = new Intent(this, br.com.bott.droidsshd.DroidSSHd.class);
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(i);
// super.onBackPressed();
}
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
if(mDebug.isChecked()) {
Log.d(TAG, "onSharedPreferenceChanged called with key " + key);
}
if (key.equals(getString(R.string.pref_dropbear_port_key))) {
mPort.setSummary(getString(R.string.pref_dropbear_port_summary) + " " + mPort.getValue());
}
// if (key.equals("authorized_keys_key")){
// Log.v(TAG, "authorized_keys_key changed: " + key);
// }
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if(mDebug.isChecked()) {
if (data!=null) {
Log.d(TAG, "onActivityResult(" + requestCode + ", " + resultCode + ", " + data.toString() + ") called");
} else {
Log.d(TAG, "onActivityResult(" + requestCode + ", " + resultCode + ", null) called");
}
}
if(resultCode==RESULT_OK){
if(mDebug.isChecked()){
Log.v(TAG,"path = " + data.getStringExtra("path"));
}
Base.refresh();
File tmp = new File(data.getStringExtra("path"));
if(tmp.length()<1024) {
Util.copyFile(data.getStringExtra("path"), Base.getDropbearAuthorizedKeysFilePath());
Util.chmod(Base.getDropbearAuthorizedKeysFilePath(), 0600);
Util.showMsg("Public key copied");
} else {
Util.showMsg("The file is too big to be a public key.");
}
}
super.onActivityResult(requestCode, resultCode, data);
}
}
/**
*
*/
package br.com.bott.droidsshd.system;
import br.com.bott.droidsshd.R;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.util.Log;
/**
* @author mestre
*
*/
public class Base {
/**
* CONSTANTS
*/
public static final String TAG = "DroidSSHd-Base";
public static final String THIS_PACKAGE_NAME = "br.com.bott.droidsshd";
public static final String SU_BIN = "/system/xbin/su";
public static final String SH_BIN = "/system/bin/sh";
public static final String DROPBEAR_DIR_KEY = "etc";
public static final String DROPBEAR_DIR_TMP = "run";
public static final String DROPBEAR_DIR_BIN = "bin";
public static final String DROPBEAR_PIDFILE = "dropbear.pid";
public static final String DROPBEAR_DSS_HOST_KEY = "dropbear_dss_host_key";
public static final String DROPBEAR_RSA_HOST_KEY = "dropbear_rsa_host_key";
public static final String DROPBEAR_AUTHORIZED_KEYS = "authorized_keys";
public static final String DROPBEAR_BIN_MUL = "dropbearmulti";
public static final String DROPBEAR_BIN_SRV = "dropbear";
public static final String DROPBEAR_BIN_KEY = "dropbearkey";
public static final String DROPBEAR_BIN_SCP = "scp";
public static final int DAEMON_STATUS_UNKNOWN = -1;
public static final int DAEMON_STATUS_STOPPED = 0;
public static final int DAEMON_STATUS_STARTED = 1;
public static final int DAEMON_STATUS_STARTING = 2;
public static final int DAEMON_STATUS_STOPPING = 3;
// public static final int WIFI_STATUS_UNKNOWN = -1;
// public static final int WIFI_STATUS_DISABLED = 0;
// public static final int WIFI_STATUS_ENABLED = 1;
/**
* GLOBAL STUFF
*/
public static boolean debug;
protected static int daemonPort;
protected static boolean runDaemonAsRoot;
protected static boolean startedAsRoot;
protected static boolean startAtBoot;
protected static boolean startAtBootOnlyIfRunningBefore;
protected static boolean notificationsEnabled;
protected static boolean wakeLock;
protected static boolean wifiLock;
protected static Context context = null;
protected static String username = "android";
protected static String password = "password";
// protected static File homeDir = null;
// private boolean mRestartRequired;
protected static String filesDirPath;
protected static String dropbearEtcDir;
protected static String dropbearTmpDir;
protected static String dropbearBinDir;
protected static String dropbearPidFile;
protected static int dropbearDaemonStatus = DAEMON_STATUS_UNKNOWN;
public static boolean startDaemonAtBoot() {
return startAtBoot;
}
public static boolean startDaemonAtBootOnlyIfRunningBefore() {
return startAtBootOnlyIfRunningBefore;
}
public static boolean runDaemonAsRoot() {
return runDaemonAsRoot;
}
public static void setDaemonStartedAsRoot(boolean b) {
startedAsRoot = b;
}
public static boolean isDropbearDaemonNotificationEnabled() {
return notificationsEnabled;
}
public static int getDropbearDaemonStatus(){
return dropbearDaemonStatus;
}
public static void setDropbearDaemonStatus(int s){
dropbearDaemonStatus=s;
// this should be on a service...
// if (s==Base.DAEMON_STATUS_STOPPED) {
// stopSelf();
// }
}
public static boolean shouldAcquireWakeLock(){
return wakeLock;
}
public static boolean shouldAcquireWifiLock(){
return wifiLock;
}
public static String getFilesDirPath(){
return filesDirPath;
}
private static void setDropbearPidFilePath(String path) {
Base.dropbearPidFile=path;
if (debug) {
Log.d(TAG, "Base.dropbearPidFile = " + path );
}
}
public static String getDropbearPidFilePath(){
return dropbearPidFile;
}
public static void setDaemonPort(int port) {
Base.daemonPort=port;
if (debug) {
Log.d(TAG, "Base.setDaemonPort = " + port );
}
}
public static int getDaemonPort() {
return daemonPort;
}
public static void setDropbearEtcDirPath(String path) {
Base.dropbearEtcDir=path;
if (debug) {
Log.d(TAG, "Base.setDropbearEtcDir = " + path );
}
}
public static String getDropbearEtcDirPath() {
return dropbearEtcDir;
}
public static void setDropbearTmpDirPath(String path) {
Base.dropbearTmpDir=path;
if (debug) {
Log.d(TAG, "Base.setDropbearTmpDir = " + path );
}
}
public static String getDropbearTmpDirPath() {
return dropbearTmpDir;
}
public static void setDropbearBinDirPath(String path) {
Base.dropbearBinDir=path;
if (debug) {
Log.d(TAG, "Base.setDropbearBinDir = " + path );
}
}
public static String getDropbearBinDirPath() {
return dropbearBinDir;
}
public static String getDropbearDssHostKeyFilePath(){
return (dropbearEtcDir + "/" + DROPBEAR_DSS_HOST_KEY);
}
public static String getDropbearRsaHostKeyFilePath(){
return (dropbearEtcDir + "/" + DROPBEAR_RSA_HOST_KEY);
}
public static String getDropbearAuthorizedKeysFilePath(){
return (dropbearEtcDir + "/" + DROPBEAR_AUTHORIZED_KEYS);
}
/* public static File getHomeDir() {
return homeDir;
}
*/
/* public static boolean setHomeDir(File homeDir) {
if(homeDir.isDirectory()) {
Base.homeDir = homeDir;
if (debug) {
Log.d(TAG, "Base.setHomeDir = " + homeDir);
}
return true;
}
if (debug) {
Log.d(TAG, "Base.setHomeDir called but " + homeDir + " is not a directory");
}
return false;
}
*/
public static Context getContext() {
return Base.context;
}
public static void setContext(Context context) {
if (context != null) {
Base.context = context;
if (debug) {
Log.d(TAG, "Base.context = " + context.toString());
}
refresh();
} else {
if (debug) {
Log.d(TAG, "Base.context called but context is null (so not set)");
}
}
}
public static String getUsername() {
return username;
}
public static void setUsername(String username) {
Base.username=username;
}
public static String getPassword() {
return password;
}
public static void refresh() {
if (Base.context != null) {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(Base.getContext());
debug = sp.getBoolean(context.getString(R.string.pref_debug_key), false);
// daemonPort = Integer.parseInt(sp.getString(context.getString(R.string.pref_dropbear_port_key), "50022"));
daemonPort = sp.getInt(context.getString(R.string.pref_dropbear_port_key), 2222);
startAtBoot = sp.getBoolean(context.getString(R.string.pref_dropbear_start_on_boot_key), false);
startAtBootOnlyIfRunningBefore = sp.getBoolean(context.getString(R.string.pref_dropbear_start_on_boot_only_if_was_running_key), true);
notificationsEnabled = sp.getBoolean(context.getString(R.string.pref_interface_notification_key), true);
password = sp.getString(context.getString(R.string.pref_dropbear_auth_password_key), "password");
runDaemonAsRoot = sp.getBoolean(context.getString(R.string.pref_dropbear_as_root_key),false);
// username = sp.getString(context.getString(R.string.pref_dropbear_auth_username_key), "android");
if(runDaemonAsRoot) {
username="root";
} else {
username="android";
}
wakeLock = sp.getBoolean(context.getString(R.string.pref_prevent_device_sleep_key), false);
wifiLock = sp.getBoolean(context.getString(R.string.pref_wifi_lock_key), false);
}
}
public static void initialize(Context context) {
if (context != null) {
Base.context = context;
Base.filesDirPath = Base.context.getFilesDir().getAbsolutePath();
setDropbearEtcDirPath(Base.filesDirPath + "/" + Base.DROPBEAR_DIR_KEY);
setDropbearTmpDirPath(Base.filesDirPath + "/" + Base.DROPBEAR_DIR_TMP);
setDropbearBinDirPath(Base.filesDirPath + "/" + Base.DROPBEAR_DIR_BIN);
setDropbearPidFilePath(Base.dropbearTmpDir + "/" + Base.DROPBEAR_PIDFILE);
}
refresh();
}
}
/**
*
*/
package br.com.bott.droidsshd.system;
//import br.com.bott.droidsshd.lixo.MonitoringService;
//import br.com.bott.droidsshd.R;
import java.io.File;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
//import android.content.SharedPreferences;
//import android.preference.PreferenceManager;
import android.util.Log;
/*
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.os.SystemClock;
import android.preference.PreferenceManager;
*/
/**
* Receives a broadcast message when the device completes
* booting/starting up and checks if anything needs to be
* done. Also used to manually start/stop monitoring services
* and alarms.
*
* @author mestre
*
*/
public class BootReceiver extends BroadcastReceiver {
private static final String TAG = "DroidSSHdBootReceiver";
@Override
public void onReceive(Context context, Intent intent) {
Base.initialize(context);
if (intent.getAction().equals(android.content.Intent.ACTION_BOOT_COMPLETED)) {
File pid = new File(Base.getDropbearPidFilePath());
boolean wasRunningBefore = pid.exists();
boolean startDaemonAtBoot = Base.startDaemonAtBoot();
boolean startDaemonAtBootOnlyIfRunningBefore = Base.startDaemonAtBootOnlyIfRunningBefore();
if (Base.debug) {
Log.d(TAG, "Received BOOT_COMPLETED broadcast");
Log.d(TAG, "startDaemonAtBoot = " + startDaemonAtBoot);
Log.d(TAG, "startDaemonAtBootOnlyIfRunningBefore = " + startDaemonAtBootOnlyIfRunningBefore);
Log.d(TAG, "wasRunningBefore = " + wasRunningBefore);
}
if (wasRunningBefore) {
if (Base.debug) {
Log.d(TAG, "Removing stale PID file");
}
// Util.doRun("rm " + Base.getDropbearPidFilePath(), Base.runDaemonAsRoot(), null);
Util.doRun("rm " + Base.getDropbearPidFilePath(), true, null);
}
if (startDaemonAtBoot) {
if (Base.debug) {
Log.d(TAG, "dropbear daemon configured to START on boot");
}
if (!startDaemonAtBootOnlyIfRunningBefore || (startDaemonAtBootOnlyIfRunningBefore && wasRunningBefore)) {
Log.i(TAG, "Starding Dropbear daemon");
context.startService(new Intent(context, br.com.bott.droidsshd.system.DroidSSHdService.class));
}
} else {
if (Base.debug) {
Log.d(TAG, "dropbear daemon configured to NOT start on boot");
}
}
}
// startAlarm(context);
}
/* private static AlarmManager mgr;
private static PendingIntent pi = null;
public static void cancelAlarm(){
if (mgr != null) {
mgr.cancel(pi);
}
}
public static void startAlarm(Context context){
AlarmSettings settings = Preferences.ReadAlarmSettings(PreferenceManager.getDefaultSharedPreferences(context));
if (settings.isAlarmEnabled()) {
// Set up PendingIntent for the alarm service
mgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(context, AlarmReceiver.class);
pi = PendingIntent.getBroadcast(context, 0, i, 0);
// First intent after a small (2 second) delay and repeat at the user-set intervals
mgr.setRepeating(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + 2000, settings.getAlarmIntervalInMilliseconds(), pi);
}
}
*/
}
/**
*
*/
package br.com.bott.droidsshd.system;
import br.com.bott.droidsshd.R;
import br.com.bott.droidsshd.tools.ShellSession;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Binder;
import android.os.Bundle;
import android.os.FileObserver;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.util.Log;
/**
* @author mestre
*
*/
public class DroidSSHdService extends Service{
private static final String TAG = "DroidSSHdService";
private static NotificationManager mNotificationManager;
private static FileObserver mPidWatchdog;
private static int dropbearDaemonProcessId = 0;
private static boolean dropbearDaemonRunning = false;
private static boolean dropbearDaemonNotificationShown = false;
private Handler serviceHandler = new Handler();
// lock to handle (synchronized) FileObserver calls
private static Object sLock = new Object();
public boolean isDaemonRunning() {
return dropbearDaemonRunning;
}
@Override
public void onCreate() {
super.onCreate();
// TODO - implement further checks on Base.init for special cases
// TODO - i.e. this SVC was started on boot and DroidSSHd activity hasn't run just yet
// TODO - (is it the same ctx? is it null? etc...)
Base.initialize(getBaseContext());
mNotificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
if (Base.debug) {
Log.d(TAG, "onCreate called");
}
}
@Override
public void onStart(Intent intent, int startId) {
if (Base.debug) {
Log.d(TAG, "onStart(" + intent.toString() + ", " + startId + ") called");
}
handleStart(intent, 0, startId);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (Base.debug) {
Log.d(TAG, "onStart(" + intent.toString() + ", " + flags + ", " + startId + ") called");
}
handleStart(intent, flags, startId);
return Service.START_STICKY;
}
private void handleStart(Intent intent, int flags, int startId) {
setUpPidFileWatchdog(Base.getDropbearTmpDirPath());
if (serviceHandler!=null) {
serviceHandler.post(new updateDaemonStatus());
if (!dropbearDaemonRunning) {
serviceHandler.postDelayed(new startDropbear(), 200L);
if (Base.debug) {
Log.d(TAG, "handleStart called, starting dropbear daemon");
}
} else {
if (Base.debug) {
Log.d(TAG, "handleStart called, but dropbear is already running");
}
}
} else {
Log.e(TAG, "handleStart called, but serviceHandler is NULL!");
handleStop();
}
}
private void handleStop() {
if (mPidWatchdog!=null) {
mPidWatchdog.stopWatching();
mPidWatchdog = null;
}
Base.setDropbearDaemonStatus(Base.DAEMON_STATUS_STOPPED);
stopSelf();
}
@Override
public void onDestroy() {
handleStop();
super.onDestroy();
}
protected class startDropbear implements Runnable {
public void run(){
if(Base.debug) {
Log.d(TAG+"-startDropbear", "starting");
}
if (!dropbearDaemonRunning) {
// ShellSession mDaemonSession = new ShellSession(TAG+"-daemon", Base.runDaemonAsRoot(), Base.debug, mLogviewHandler) {
ShellSession mDaemonSession = new ShellSession(TAG+"-daemon", Base.runDaemonAsRoot(), Base.debug, null) {
@Override
protected void onSessionReady() {
if (debug) {
Log.v(tag, "onSessionReady called");
}
int uid;
if (Base.runDaemonAsRoot()) {
uid = 0;
} else {
uid = android.os.Process.myUid();
}
cmd = String.format("%s -d %s -r %s -p %d -P %s -E -R %s -A -N %s -U %s -G %s -C %s",
// -F
Base.getDropbearBinDirPath() + "/" + Base.DROPBEAR_BIN_SRV,
Base.getDropbearDssHostKeyFilePath(),
Base.getDropbearRsaHostKeyFilePath(),
Base.getDaemonPort(),
Base.getDropbearPidFilePath(),
Base.getDropbearAuthorizedKeysFilePath(),
Base.getUsername(),
uid,
uid,
Base.getPassword()
);
if (debug) {
Log.v(tag, "cmd = '" + cmd + "'");
}
// cmd("export HOME=/mnt/sdcard");
// cmd("cd $HOME");
cmd(cmd);
}
@Override
protected void onStdOut(String line) {
if(debug) {
Log.d(tag, "'" + line + "'");
}
if (handler!=null) {
Message message = new Message();
Bundle data = new Bundle();
data.putCharSequence("line", line + "\n");
message.setData(data);
handler.sendMessage(message);
}
}
@Override
protected void onStdErr(String line) {
onStdOut (line);
}
};
mDaemonSession.start();
} else {
Log.i(TAG, "dropbear daemon already running");
}
}
}
private FileObserver createPidWatchdog(String path,int mask) {
FileObserver observer = new FileObserver(path, mask) {
@Override
public void onEvent(int event, String path) {
synchronized(sLock) {
switch (event) {
case FileObserver.CREATE:
Base.setDropbearDaemonStatus(Base.DAEMON_STATUS_STARTING);
if(Base.debug) {
Log.v(TAG, "File " + path + " created");
Log.d(TAG, "mCurrentStatus = Base.DAEMON_STATUS_STARTING");
}
break;
case FileObserver.DELETE:
// if ((Base.getDropbearDaemonStatus()==Base.DAEMON_STATUS_STARTED)
// || (Base.getDropbearDaemonStatus()==Base.DAEMON_STATUS_STARTING)
// || (Base.getDropbearDaemonStatus()==Base.DAEMON_STATUS_STOPPING)) {
Base.setDropbearDaemonStatus(Base.DAEMON_STATUS_STOPPED);
// mPidWatchdog.stopWatching();
// mPidWatchdog = null;
// stopSelf();
// }
hideNotification();
if (Base.debug){
Log.v(TAG, "File " + path + " deleted");
Log.d(TAG, "mCurrentStatus = Base.DAEMON_STATUS_STOPPED");
}
break;
case FileObserver.MODIFY:
Base.setDropbearDaemonStatus(Base.DAEMON_STATUS_STARTED);
showNotification();
if (Base.debug){
Log.v(TAG, "File " + path + " modified");
Log.d(TAG, "mCurrentStatus = Base.DAEMON_STATUS_STARTED");
}
break;
default:
if (Base.debug){
Log.v(TAG, "event = " + event + " path = " + path);
}
break;
}
}
}
};
return observer;
}
private void setUpPidFileWatchdog(String path) {
int mask = FileObserver.CREATE + FileObserver.DELETE + FileObserver.MODIFY;
if (mPidWatchdog!=null) {
if (Base.debug) {
Log.d(TAG, "setUpPidFileWatchdog called but PIDObserver has already been set-up");
}
} else {
mPidWatchdog = createPidWatchdog(path, mask);
mPidWatchdog.startWatching();
}
if (Base.debug) {
Log.d(TAG, "PIDObserver.toString() = " + mPidWatchdog.toString());
Log.d(TAG, "Watching " + path + " mask " + mask);
}
}
protected void showNotification() {
if (Base.isDropbearDaemonNotificationEnabled()) {
Notification notifyDetails = new Notification(R.drawable.ssh_icon, getString(R.string.app_label), System.currentTimeMillis());
Intent intent = new Intent();
intent.setClass(Base.getContext(), br.com.bott.droidsshd.DroidSSHd.class);
intent.setAction(Intent.ACTION_DEFAULT);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
// intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
notifyDetails.setLatestEventInfo(this, getString(R.string.app_label), "Dropbear listening on port " + Base.getDaemonPort(), pendingIntent);
notifyDetails.flags |= Notification.FLAG_ONGOING_EVENT;
notifyDetails.flags |= Notification.DEFAULT_SOUND;
mNotificationManager.notify(R.string.app_label, notifyDetails);
dropbearDaemonNotificationShown=true;
if (Base.shouldAcquireWakeLock()) {
Util.takeWakeLock();
}
if ((Base.shouldAcquireWifiLock()) && (Util.isWifiEnabled())) {
Util.takeWifiLock();
}
}
}
protected void hideNotification() {
if (dropbearDaemonNotificationShown) {
mNotificationManager.cancel(R.string.app_label);
dropbearDaemonNotificationShown=false;
Util.releaseWakeLock();
Util.releaseWifiLock();
}
}
protected class updateDaemonStatus implements Runnable {
public void run(){
if(Base.debug) {
Log.d(TAG+"-updateDaemonStatus", "started");
}
dropbearDaemonProcessId = Util.getDropbearPidFromPidFile(Base.getDropbearPidFilePath());
if (dropbearDaemonProcessId!=0) {
dropbearDaemonRunning = Util.isDropbearDaemonRunning();
} else {
dropbearDaemonRunning = false;
}
if(dropbearDaemonRunning) {
Base.setDropbearDaemonStatus(Base.DAEMON_STATUS_STARTED);
showNotification();
} else {
Base.setDropbearDaemonStatus(Base.DAEMON_STATUS_STOPPED);
hideNotification();
}
}
}
private final IBinder mBinder = new DropbearDaemonHandlerBinder();
public class DropbearDaemonHandlerBinder extends Binder {
public DroidSSHdService getService() {
return DroidSSHdService.this;
}
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
}
package br.com.bott.droidsshd.system;
import android.util.Log;
public class NativeTask {
public static final String TAG = "DroidSSHd NativeTask";
static {
try {
Log.i(TAG, "Trying to load libNativeTask.so");
System.loadLibrary("NativeTask");
} catch (UnsatisfiedLinkError ule) {
Log.e(TAG, "Could not load libNativeTask.so");
}
}
public static native int runCommand(String command);
public static native int chmod(String path, int mode);
public static native int symlink(String origin, String destination);
}
/**
*
*/
package br.com.bott.droidsshd.system;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
import android.content.Context;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiManager.WifiLock;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.PowerManager;
import android.util.Log;
import android.widget.Toast;
//import br.com.bott.droidsshd.WifiLock;
import br.com.bott.droidsshd.tools.ShellSession;
/**
* @author mestre
*
*/
public class Util {
private final static String TAG = "DroidSShd Util";
private static PowerManager.WakeLock wakeLock;
private static WifiLock wifiLock = null;
public static void showMsg(String txt) {
Toast toast = Toast.makeText(Base.getContext(), (CharSequence)txt, Toast.LENGTH_SHORT);
toast.show();
if(Base.debug) {
Log.d(TAG, "showMsg() txt='"+txt+"'");
}
}
public static boolean checkPathToBinaries(){
if( ! new File(Base.getDropbearBinDirPath()+"/dropbear").exists() ) {
Util.showMsg("dropbear not installed");
Log.e(TAG, "Dropbear not installed");
return false;
}
if (Base.debug) {
Log.v(TAG, "dropbear binaries found");
}
return true;
}
public static int getDropbearPidFromPidFile(String path) {
File pidFile = new File(path);
int pid=0;
if( ! pidFile.exists() ) {
if(Base.debug) {
Log.d(TAG, "Dropbear PID file doesn't exist:" + pidFile.getAbsolutePath());
Log.d(TAG, "dropbearDaemonStatus = " + Base.getDropbearDaemonStatus());
}
// TODO - begin of ugly hack to fix a nasty bug
if (Base.getDropbearDaemonStatus()==Base.DAEMON_STATUS_STOPPING) {
if(Base.debug) {
Log.v(TAG,"mCurrentStatus was STOPPING, changed to STOPPED");
}
Base.setDropbearDaemonStatus(Base.DAEMON_STATUS_STOPPED);
// updateStatus();
}
// TODO - end of ugly hack - state changes can be tricky :-(
return 0;
} else {
try {
BufferedReader in = new BufferedReader(new FileReader(pidFile.getAbsolutePath()), 512);
String line;
String tmp="";
while ((line = in.readLine()) != null) {
if (Base.debug){
Log.d(TAG, "getDropbearPid() line = " + line);
}
tmp += line; // + "\n";
}
in.close();
if (Base.debug){
Log.d(TAG, "getDropbearPid() tmp = " + tmp);
}
pid = Integer.parseInt(tmp);
if (Base.debug){
Log.d(TAG, "pidFile = " + pid + " - " + pidFile.getAbsolutePath() + " = " + tmp);
}
}
catch (Exception ex) {
ex.printStackTrace();
if (Base.debug) {
Log.d(TAG, "Can't read Dropbear PID file " + pidFile.getAbsolutePath());
}
return pid;
}
}
return pid;
}
// public static boolean isDropbearDaemonRunning(boolean removeStalePidFile) {
public static boolean isDropbearDaemonRunning() {
// boolean removeStalePidFile = true;
int pid;
pid = Util.getDropbearPidFromPidFile(Base.getDropbearPidFilePath());
// pid = getDropbearPidFromProcessList();
if (pid!=0) {
if(checkDaemonAgainstProcessId(pid)) {
Base.setDropbearDaemonStatus(Base.DAEMON_STATUS_STARTED);
return true;
} else {
if (Base.debug) {
Log.d(TAG, "isDropbearDaemonRunning: we have a stale pidfile");
// Log.d(TAG, "removeStalePidFile = " + removeStalePidFile);
}
// if(removeStalePidFile) {
// doRun("rm " + Base.getDropbearPidFilePath(), Base.asRoot, mLogviewHandler);
doRun("rm " + Base.getDropbearPidFilePath(), Base.runDaemonAsRoot(), null);
// }
Base.setDropbearDaemonStatus(Base.DAEMON_STATUS_STOPPED);
return false;
}
}
return false;
}
protected static boolean checkDaemonAgainstProcessId(int pid) {
// TODO - check if this PID is actually dropbear's
File mProc = new File("/proc/" + pid);
return mProc.isDirectory();
}
public static void doRun(String cmd, boolean asRoot, Handler handler){
ShellSession p = new ShellSession(TAG + "-shell", cmd, handler, asRoot, Base.debug) {
@Override
protected void onStdOut(String line) {
if(debug) {
Log.d(tag, "'" + line + "'");
}
if (handler!=null) {
Message message = new Message();
Bundle data = new Bundle();
data.putCharSequence("line", line + "\n");
message.setData(data);
handler.sendMessage(message);
}
}
@Override
protected void onStdErr(String line) {
onStdOut (line);
}
};
p.start();
}
public static boolean validateHostKeys() {
return ((checkHostKey(Base.DROPBEAR_DSS_HOST_KEY)) &&
(checkHostKey(Base.DROPBEAR_RSA_HOST_KEY)));
}
public static boolean checkHostKey(String whichOne){
File hostKey = new File(Base.getDropbearEtcDirPath() + "/" + whichOne);
if (hostKey.exists()) {
if(Base.debug) {
Log.v(TAG, "Host key found: " + hostKey.getAbsolutePath());
}
} else {
if(Base.debug) {
Log.v(TAG, "Host key NOT found: " + hostKey.getAbsolutePath());
}
return false;
}
return true;
}
public static int chmod(String path, int mode){
int out = NativeTask.chmod(path, mode);
if(Base.debug) {
Log.d(TAG, "chmod " + mode + " " + path + " returned " + out);
}
return out;
}
public static void copyFile(String src, String dst) {
try {
InputStream in = new FileInputStream(src);
OutputStream out = new FileOutputStream(dst);
byte[] buffer = new byte[1024];
int len;
while((len=in.read(buffer))>0) {
out.write(buffer, 0, len);
}
in.close();
out.close();
} catch (FileNotFoundException e) {
Log.e(TAG, "File not found");
e.printStackTrace();
} catch (IOException e) {
Log.e(TAG, "IOException");
e.printStackTrace();
}
}
public static boolean mkdir(String path){
boolean out=false;
File f = new File(path);
if (!f.isDirectory()) {
out=f.mkdirs();
}
if(Base.debug) {
Log.d(TAG, "mkdir " + path + " returned " + out);
}
return out;
}
public static int symlink(String orig, String dest){
int out = NativeTask.symlink(orig, dest);
if(Base.debug) {
Log.d(TAG, "symlink " + orig + " to " + dest + " returned " + out);
}
return out;
}
/*protected int getDropbearPidFromProcessList() {
// TODO
if (mDebug) {
Log.d(TAG, "getDropbearPidFromProcessList() called");
}
String pid;
String temp;
pid = "";
int i;
try{
Process p = Runtime.getRuntime().exec("ps");
p.waitFor();
BufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));
while ( (temp = stdInput.readLine()) != null ) {
if (mDebug) {
Log.d(TAG, "getDropbearPidFromProcessList temp='"+temp+"'");
}
if ( temp.contains(DROPBEAR_BIN) ) {
if (mDebug) {
Log.d(TAG, "getDropbearPidFromProcessList temp='"+temp+"'");
}
String [] cmdArray = temp.split(" +");
for (i=0; i< cmdArray.length; i++) {
if (mDebug) {
Log.d(TAG, "loop i="+ i + " => " + cmdArray[i]);
}
}
pid = cmdArray[1];
}
}
}
catch (IOException e) {
e.printStackTrace();
}
catch (InterruptedException e) {
e.printStackTrace();
}
if ( pid != "") {
i = Integer.parseInt(pid);
if (mDebug) {
Log.d(TAG, "getDropbearPidFromProcessList pid='"+pid+"'");
}
} else {
if (mDebug) {
Log.d(Base.debuggetDropbearPidFromProcessList pid='empty'");
}
}
return 0;
}*/
public static void mysleep(int ms) {
try {
Thread.sleep(ms);
} catch (InterruptedException e) {
Log.e(TAG, "mysleep(" + ms + ") had an InterruptedException");
e.printStackTrace();
}
}
synchronized public static void takeWakeLock() {
if(wakeLock == null) {
PowerManager pm = (PowerManager)Base.getContext().getSystemService(Context.POWER_SERVICE);
wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
wakeLock.setReferenceCounted(false);
if (Base.debug) {
Log.d( TAG, "Acquiring WAKE lock");
}
wakeLock.acquire();
}
}
synchronized public static void releaseWakeLock() {
if(wakeLock != null) {
wakeLock.release();
wakeLock = null;
if (Base.debug) {
Log.d(TAG, "Releasing WAKE lock");
}
} /*else {
if (Base.debug) {
Log.i(TAG, "Couldn't release null wake lock");
}
}*/
}
// http://code.google.com/p/swiftp/source/browse/#svn/trunk/src/org/swiftp
synchronized public static void takeWifiLock() {
if(wifiLock == null) {
WifiManager manager = (WifiManager)Base.getContext().getSystemService(Context.WIFI_SERVICE);
wifiLock = manager.createWifiLock("DroidSSHd");
wifiLock.setReferenceCounted(false);
}
wifiLock.acquire();
if (Base.debug) {
Log.d(TAG, "Acquiring WIFI lock");
}
}
synchronized public static void releaseWifiLock() {
if(wifiLock != null) {
wifiLock.release();
wifiLock = null;
if (Base.debug) {
Log.d(TAG, "Releasing WIFI lock");
}
}
}
synchronized public static boolean isWifiEnabled() {
WifiManager wifiMgr = (WifiManager)Base.getContext().getSystemService(Context.WIFI_SERVICE);
if(wifiMgr.getWifiState() == WifiManager.WIFI_STATE_ENABLED) {
return true;
} else {
return false;
}
}
public static Iterator<String> getLocalIpAddress() {
ArrayList<String> ipAddr = new ArrayList<String>();
try {
for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) {
NetworkInterface intf = en.nextElement();
for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();) {
InetAddress inetAddress = enumIpAddr.nextElement();
if (!inetAddress.isLoopbackAddress()) {
if (Base.debug) {
Log.v(TAG, "Interface " + intf.getDisplayName() + ", IPaddress " + inetAddress.getHostAddress().toString() );
}
ipAddr.add(inetAddress.getHostAddress().toString());
}
}
}
} catch (SocketException ex) {
Log.e(TAG, ex.toString());
return null;
}
return ipAddr.iterator();
}
}
package br.com.bott.droidsshd.tools;
import com.quietlycoding.android.picker.NumberPicker;
import br.com.bott.droidsshd.R;
import android.content.Context;
import android.content.DialogInterface;
import android.preference.DialogPreference;
import android.util.AttributeSet;
//import android.util.Log;
import android.view.View;
public class NumberPickerPreference extends DialogPreference {
// private static final String TAG = "NumberPickerPreference";
// private static final String PREF = "dropbear_port";
protected NumberPicker picker;
public NumberPickerPreference(Context context) {
this(context, null);
}
public NumberPickerPreference(Context context, AttributeSet attrs) {
this(context, attrs, android.R.attr.dialogPreferenceStyle);
}
public NumberPickerPreference(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
setDialogLayoutResource(R.layout.number_picker_pref);
}
@Override
protected void onBindDialogView(View view) {
super.onBindDialogView(view);
picker = (NumberPicker) view.findViewById(R.id.pref_num_picker);
picker.setRange(1, 65535);
picker.setSpeed(50);
picker.setCurrent(getValue());
}
public void onClick(DialogInterface dialog, int which) {
// Log.d(TAG, "which: " + which);
switch (which) {
case DialogInterface.BUTTON_POSITIVE:
// NumberPicker picker = (NumberPicker) getDialog().findViewById(R.id.pref_num_picker);
// picker = (NumberPicker) getDialog().findViewById(R.id.pref_num_picker);
picker.onClick(null);
saveValue(picker.getCurrent());
break;
case DialogInterface.BUTTON_NEGATIVE:
break;
default:
break;
}
}
protected void saveValue(int val) {
getEditor().putInt("dropbear_port", val).commit();
}
public int getValue() {
return getSharedPreferences().getInt("dropbear_port", 2222);
}
}
/**
*
*/
package br.com.bott.droidsshd.tools;
import android.os.Handler;
import android.util.Log;
/**
* @author mestre
*
*/
public class ReplicantThread extends Thread {
protected String tag;
protected long untilWhenMs;
protected long checkEveryMs;
protected long timeLeftMs;
protected boolean notdone;
protected boolean debug;
protected Handler handler;
protected Runnable updater;
public ReplicantThread(String tag, long untilWhenMs, long checkEveryMs, Handler handler, Runnable updater, boolean debug) {
this.debug=debug;
this.notdone=true;
this.untilWhenMs=untilWhenMs;
this.checkEveryMs=checkEveryMs;
this.handler=handler;
this.updater=updater;
this.tag=tag;
this.timeLeftMs=Integer.MAX_VALUE;
setName(tag);
if (this.debug) {
Log.v(this.tag, "new ReplicantThread created");
}
}
public void setDone() {
this.notdone=false;
}
public void extendLifetimeForAnother(long untilWhenMs) {
this.untilWhenMs=untilWhenMs;
this.notdone=true;
}
public void run() {
// while(((timeLeftMs) > 0) && (notdone)){
while(notdone){
handler.post(updater);
try {
sleep(checkEveryMs);
timeLeftMs=untilWhenMs-System.currentTimeMillis();
if (timeLeftMs <= 0) {
notdone=false;
} else {
if(debug) {
Log.v(this.tag + "-DS-" + this.toString(), "Entered the loop " + this.toString());
Log.v(this.tag + "-DS-" + this.toString(), "We'll stop running in at most " + timeLeftMs + " ms");
}
}
} catch (InterruptedException e) {
notdone=false;
e.printStackTrace();
}
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment