/*******************************************************************************
* Copyright (c) 2011 Adam Shanks (ChainsDD)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
/**
** Copyright (C) 2010 Adam Shanks (chainsdd@gmail.com)
**
** This program is free software; you can redistribute it and/or
** modify it under the terms of the GNU General Public License,
** version 2 as published by the Free Software Foundation.
**
** This program 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 this program; if not, write to the Free Software
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**/
package com.noshufou.android.su;
import java.io.IOException;
import java.io.OutputStream;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.net.LocalSocket;
import android.net.LocalSocketAddress;
import android.preference.PreferenceManager;
import android.util.Log;
import com.noshufou.android.su.preferences.Preferences;
import com.noshufou.android.su.provider.PermissionsProvider.Apps;
public class SuRequestReceiver extends BroadcastReceiver {
private static final String TAG = "Su.SuRequestReceiver";
public static final String EXTRA_CALLERUID = "caller_uid";
public static final String EXTRA_UID = "desired_uid";
public static final String EXTRA_CMD = "desired_cmd";
public static final String EXTRA_SOCKET = "socket";
public static final String EXTRA_ALLOW = "allow";
public static final String EXTRA_VERSION_CODE = "version_code";
@Override
public void onReceive(Context context, Intent intent) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
String automaticAction = prefs.getString(Preferences.AUTOMATIC_ACTION, "prompt");
if (automaticAction.equals("deny")) {
sendResult(context, intent, false);
return;
} else if (automaticAction.equals("allow")) {
sendResult(context, intent, true);
return;
}
if (prefs.getBoolean("permissions_dirty", false)) {
Log.d(TAG, "Database is dirty, check here");
String where = Apps.UID + "=? AND " + Apps.EXEC_UID + "=? AND " + Apps.EXEC_CMD + "=?";
Log.d(TAG, where);
Cursor c = context.getContentResolver().query(Apps.CONTENT_URI,
new String[] { Apps.ALLOW },
Apps.UID + "=? AND " + Apps.EXEC_UID + "=? AND " + Apps.EXEC_CMD + "=?",
new String[] { String.valueOf(intent.getIntExtra(EXTRA_CALLERUID, -1)),
String.valueOf(intent.getIntExtra(EXTRA_UID, -1)),
String.valueOf(intent.getStringExtra(EXTRA_CMD)) }, null);
if (c.moveToFirst()) {
Log.d(TAG, "Found an entry");
switch (c.getInt(0)) {
case Apps.AllowType.ALLOW:
Log.d(TAG, "Allow");
sendResult(context, intent, true);
break;
case Apps.AllowType.DENY:
Log.d(TAG, "Deny");
sendResult(context, intent, false);
break;
default:
Log.d(TAG, "Prompt");
showPrompt(context, intent);
}
} else {
Log.d(TAG, "No entry found, prompt");
showPrompt(context, intent);
}
c.close();
return;
}
int sysTimeout = prefs.getInt(Preferences.TIMEOUT, 0);
if ( sysTimeout > 0) {
String key = "active_" + intent.getIntExtra(EXTRA_CALLERUID, 0);
long timeout = prefs.getLong(key, 0);
if (System.currentTimeMillis() < timeout) {
sendResult(context, intent, true);
return;
} else {
showPrompt(context, intent);
return;
}
} else {
showPrompt(context, intent);
return;
}
}
private void showPrompt(Context context, Intent intent) {
Intent prompt = new Intent(context, SuRequestActivity.class);
prompt.putExtras(intent);
prompt.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(prompt);
}
private void sendResult(Context context, Intent intent, boolean allow) {
LocalSocket socket = new LocalSocket();
OutputStream os = null;;
try {
socket.connect(new LocalSocketAddress(
intent.getStringExtra(EXTRA_SOCKET), LocalSocketAddress.Namespace.FILESYSTEM));
os = socket.getOutputStream();
os.write((allow?"ALLOW":"DENY").getBytes());
os.flush();
os.close();
socket.close();
} catch (IOException e) {
Log.e(TAG, "Failed to write to socket", e);
}
}
}