1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.omadm.service; 18 19 import android.content.ComponentName; 20 import android.content.ContentValues; 21 import android.content.Context; 22 import android.content.Intent; 23 import android.content.ServiceConnection; 24 import android.content.SharedPreferences; 25 import android.content.res.Resources; 26 import android.database.Cursor; 27 import android.database.sqlite.SQLiteDatabase; 28 import android.os.IBinder; 29 import android.text.TextUtils; 30 import android.util.Log; 31 32 import com.android.omadm.plugin.IDmtPlugin; 33 34 import org.xmlpull.v1.XmlPullParser; 35 import org.xmlpull.v1.XmlPullParserException; 36 import org.xmlpull.v1.XmlPullParserFactory; 37 38 import java.io.BufferedInputStream; 39 import java.io.File; 40 import java.io.FileInputStream; 41 import java.io.IOException; 42 import java.io.InputStream; 43 44 public class DMConfigureDB { 45 private static final String TAG = "DMConfigureDB"; 46 private static final boolean DBG = DMClientService.DBG; 47 48 private final DMClientService mContext; 49 50 private static final String DATABASE_NAME = "DMConfigure.db"; 51 52 private final SQLiteDatabase mdb; 53 54 private IDmtPlugin mPluginConnection; 55 56 private String isBoundTo = null; 57 58 protected final Object mLock = new Object(); 59 60 private ServiceConnection mConnection = new ServiceConnection() { 61 62 @Override 63 public void onServiceConnected(ComponentName className, 64 IBinder service) { 65 logd("onServiceConnected"); 66 synchronized (mLock) { 67 // this gets an instance of the IRemoteInterface, which we can use to call on the service 68 mPluginConnection = IDmtPlugin.Stub.asInterface(service); 69 mLock.notifyAll(); 70 } 71 } 72 73 @Override 74 public void onServiceDisconnected(ComponentName arg0) { 75 logd("onServiceDisconnected"); 76 synchronized (mLock) { 77 mPluginConnection = null; 78 } 79 } 80 }; 81 82 static final class AccountInfo { 83 public String acctName; // DM server account name 84 public String serverID; // DM server ID 85 public String addr; // DM server URL 86 public String addrType; // e.g. "URI" 87 public String portNbr; // DM server port, e.g. "443" 88 public String conRef; // e.g. "" 89 public String serverName; // DM server name 90 public String authPref; // e.g. "HMAC" 91 public String serverPW; // HMAC server password 92 public String serverNonce; // HMAC server nonce 93 public String userName; // DM username (e.g. IMSI or MEID) 94 public String clientPW; // HMAC client password 95 public String clientNonce; // HMAC client nonce 96 public String proxyAddr; // HTTP proxy address 97 public String proxyPortNbr; // HTTP proxy port, e.g. "80" 98 } 99 100 public DMConfigureDB(DMClientService context) { 101 mContext = context; 102 mdb = mContext.openOrCreateDatabase(DATABASE_NAME, 0, null); 103 Cursor cur = null; 104 try { 105 cur = mdb.rawQuery("PRAGMA table_info( dmAccounts )", null); 106 int cnt = cur.getCount(); 107 if (DBG) logd("Cursor count for table dmAccounts is " + cnt); 108 // TODO: we need a way for plugins to populate an empty table 109 if (cnt == 0) { 110 onCreate(mdb); 111 } 112 // NOTE: always update all the account info in DM tree 113 loadDmConfig(); 114 loadDmAccount(mdb); 115 116 } catch (Exception e) { 117 loge("exception in DMConfigureDB", e); 118 } finally { 119 if (cur != null) { 120 cur.close(); 121 } 122 } 123 } 124 125 public void closeDatabase() { 126 mdb.close(); 127 unbind(); 128 } 129 130 void onCreate(SQLiteDatabase db) { 131 logd("onCreate"); 132 133 db.execSQL("CREATE TABLE dmAccounts (" + 134 "_id INTEGER PRIMARY KEY AUTOINCREMENT," + 135 "ServerID TEXT UNIQUE ON CONFLICT REPLACE," + 136 "AccName TEXT," + 137 "Addr TEXT," + 138 "AddrType TEXT," + 139 "PortNbr TEXT," + 140 "ConRef TEXT," + 141 "Name TEXT," + 142 "AuthPref TEXT," + 143 "ServerPW TEXT," + 144 "ServerNonce TEXT," + 145 "UserName TEXT," + 146 "ClientPW TEXT," + 147 "ClientNonce TEXT," + 148 "ProxyAddr TEXT," + 149 "ProxyPortNbr TEXT" + 150 ");"); 151 152 db.execSQL("CREATE TABLE dmFlexs (" + 153 "_id INTEGER PRIMARY KEY AUTOINCREMENT," + 154 "name TEXT UNIQUE ON CONFLICT REPLACE," + 155 "value TEXT" + 156 ");"); 157 } 158 159 public String getFotaServerID() { 160 String id = getConfigField("PreferredServerID"); 161 162 if (id != null && !id.isEmpty()) { 163 return id; 164 } 165 166 return getConfigField("FOTAServerID"); 167 } 168 169 public boolean isDmAlertEnabled() { 170 String value = getConfigField("DmAlertEnabled"); 171 return null == value || "true".equalsIgnoreCase(value); 172 } 173 174 public boolean isDmNonceResyncEnabled() { 175 String value = getConfigField("DmNonceResyncEnabled"); 176 return null != value && "true".equalsIgnoreCase(value); 177 } 178 179 /* 180 * Returns SyncML logging level 181 * 0 = do not log syncml messages 182 * 1 = log messages received as is 183 * 2 = convert wbxml to xml messages and log it 184 */ 185 public int getSyncMLLogLevel() { 186 return 1; 187 188 // String value = getConfigField("DmSyncMLLogLevel"); 189 // if (null == value) { 190 // return 0; 191 // } 192 // return Integer.parseInt(value); 193 } 194 195 private String getConfigField(String field) { 196 String value = null; 197 198 Cursor cr = mdb.query("dmFlexs", null, "name='" + field + '\'', null, null, null, null); 199 200 if (cr != null) { 201 if (cr.moveToFirst()) { 202 int index = cr.getColumnIndex("value"); 203 value = cr.getString(index); 204 } 205 cr.close(); 206 } 207 208 if (DBG) logd("get field '" + field + "'=" + value); 209 return value; 210 } 211 212 public void setFotaServerID(String serverID) { 213 ContentValues values = new ContentValues(1); 214 215 //values.put("Name", "FOTAServerID"); 216 values.put("value", serverID); 217 218 mdb.update("dmFlexs", values, "name='FOTAServerID'", null); 219 } 220 221 void setGsmImei(String imei) { 222 ContentValues values = new ContentValues(); 223 values.put("name", "gsmImei"); 224 values.put("value", imei); 225 mdb.insert("dmFlexs", null, values); 226 227 } 228 229 private void loadDmConfig() { 230 //following statements just for debug print 231 getConfigField("CarrierName"); 232 getConfigField("AdditionalCharge"); 233 getConfigField("PreferredServerID"); 234 235 // FIXME: this should be removed along with get/setGsmImei() 236 if (DMSettingsHelper.isPhoneTypeLTE()) { 237 SharedPreferences p = mContext.getSharedPreferences(DMHelper.IMEI_PREFERENCE_KEY, 0); 238 String gsmImei = p.getString(DMHelper.IMEI_VALUE_KEY, null); 239 logd("gsmImei in loadDmConfig is " + gsmImei); 240 //ed.clear(); 241 if (null == gsmImei || gsmImei.isEmpty()) { 242 // this is needed to avoid showing DMService app force close 243 logd("set the imei value to zero"); 244 gsmImei = "0"; 245 } else if (gsmImei.length() > 15) { 246 logd("imei length exceeding 15 digits so trim it to 15"); 247 gsmImei = gsmImei.substring(0, 15); 248 } 249 setGsmImei(gsmImei); 250 } 251 /////////////////////////////////////////// 252 253 } 254 255 private void loadDmAccount(SQLiteDatabase db) { 256 AccountInfo ai = new AccountInfo(); 257 boolean isFirst = true; 258 259 Cursor cr = db.rawQuery("SELECT * FROM dmAccounts", null); 260 261 if (cr != null) { 262 if (cr.moveToFirst()) { 263 do { 264 ai.acctName = cr.getString(cr.getColumnIndex("AccName")); 265 logd("[Factory]account=" + ai.acctName); 266 267 ai.serverID = cr.getString(cr.getColumnIndex("ServerID")); 268 if (DBG) logd("[Factory]serverID=" + ai.serverID); 269 270 ai.addr = cr.getString(cr.getColumnIndex("Addr")); 271 if (DBG) logd("[Factory]addr=" + ai.addr); 272 273 ai.addrType = cr.getString(cr.getColumnIndex("AddrType")); 274 if (DBG) logd("[Factory]addrType=" + ai.addrType); 275 276 ai.portNbr = cr.getString(cr.getColumnIndex("PortNbr")); 277 if (DBG) logd("[Factory]portNbr=" + ai.portNbr); 278 279 ai.conRef = cr.getString(cr.getColumnIndex("ConRef")); 280 if (DBG) logd("[Factory]conRef=" + ai.conRef); 281 282 ai.serverName = cr.getString(cr.getColumnIndex("Name")); 283 if (DBG) logd("[Factory]serverName=" + ai.serverName); 284 285 ai.authPref = cr.getString(cr.getColumnIndex("AuthPref")); 286 if (DBG) logd("[Factory]authPref=" + ai.authPref); 287 288 ai.serverPW = cr.getString(cr.getColumnIndex("ServerPW")); 289 if (DBG) logd("[Factory]serverPW=" + ai.serverPW); 290 291 ai.serverNonce = cr.getString(cr.getColumnIndex("ServerNonce")); 292 if (DBG) logd("[Factory]serverNonce=" + ai.serverNonce); 293 294 ai.userName = cr.getString(cr.getColumnIndex("UserName")); 295 if (DBG) logd("[Factory]userName=" + ai.userName); 296 297 ai.clientPW = cr.getString(cr.getColumnIndex("ClientPW")); 298 if (DBG) logd("[Factory]clientPW=" + ai.clientPW); 299 300 ai.clientNonce = cr.getString(cr.getColumnIndex("ClientNonce")); 301 if (DBG) logd("[Factory]clientNonce=" + ai.clientNonce); 302 303 ai.proxyAddr = cr.getString(cr.getColumnIndex("ProxyAddr")); 304 if (DBG) logd("[Factory]proxyAddr=" + ai.proxyAddr); 305 306 ai.proxyPortNbr = cr.getString(cr.getColumnIndex("ProxyPortNbr")); 307 if (DBG) logd("[Factory]proxyPortNbr=" + ai.proxyPortNbr); 308 309 if (writeAccount2Dmt(ai) && isFirst) { 310 if (DBG) logd("[Factory]setFotaServerID: " + ai.serverID); 311 312 ContentValues values = new ContentValues(); 313 values.put("name", "FOTAServerID"); 314 values.put("value", ai.serverID); 315 db.insert("dmFlexs", null, values); 316 317 isFirst = false; 318 } 319 320 } while (cr.moveToNext()); 321 322 cr.close(); 323 return; 324 } 325 cr.close(); 326 } 327 328 try { 329 XmlPullParser xpp = null; 330 String[] accountInfo = null; 331 int eventType = 0; 332 int num_accounts = 0; 333 InputStream in = getDMAccXmlInput(); 334 335 if (in != null) { 336 XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); 337 factory.setNamespaceAware(true); 338 xpp = factory.newPullParser(); 339 xpp.setInput(in, null); 340 eventType = xpp.getEventType(); 341 } else { 342 logd("Reading dmAccounts from res"); 343 Resources res = mContext.getResources(); 344 accountInfo = res.getStringArray(R.array.dm_account_info); 345 if (accountInfo == null) { 346 if (DBG) logd("accountInfo == null"); 347 return; 348 } else { 349 logd("Number of accounts = " + accountInfo.length); 350 } 351 } 352 353 while ((in != null && eventType != XmlPullParser.END_DOCUMENT) || 354 (in == null && num_accounts < accountInfo.length)) { 355 if (in == null || 356 (eventType == XmlPullParser.START_TAG && "Account".equals(xpp.getName()))) { 357 String[] account = null; 358 if (in == null) { 359 account = accountInfo[num_accounts].split(", "); 360 if (account == null) { 361 loge("account == null; invalid account info"); 362 } else { 363 if (DBG) logd("Account # " + (num_accounts + 1) + 364 "; number of fields = " + account.length); 365 } 366 } 367 368 ai.acctName = getAttributeValue(xpp, "AccName", account, 0); 369 logd("account=" + ai.acctName); 370 371 ai.serverID = getAttributeValue(xpp, "ServerID", account, 1); 372 if (DBG) logd("serverID=" + ai.serverID); 373 374 ai.addr = getRealString(getAttributeValue(xpp, "Addr", account, 2)); 375 if (DBG) logd("addr=" + ai.addr); 376 377 ai.addrType = getAttributeValue(xpp, "AddrType", account, 3); 378 if (DBG) logd("addrType=" + ai.addrType); 379 380 ai.portNbr = getAttributeValue(xpp, "PortNbr", account, 4); 381 if (DBG) logd("portNbr=" + ai.portNbr); 382 383 ai.conRef = getAttributeValue(xpp, "ConRef", account, 5); 384 if (DBG) logd("conRef=" + ai.conRef); 385 386 ai.serverName = getAttributeValue(xpp, "ServerName", account, 6); 387 if (DBG) logd("serverName=" + ai.serverName); 388 389 ai.authPref = getAttributeValue(xpp, "AuthPref", account, 7); 390 if (DBG) logd("authPref=" + ai.authPref); 391 392 ai.serverPW = getAttributeValue(xpp, "ServerPW", account, 8); 393 if (DBG) logd("serverPW=" + ai.serverPW); 394 395 ai.serverNonce = getAttributeValue(xpp, "ServerNonce", account, 9); 396 if (DBG) logd("serverNonce=" + ai.serverNonce); 397 398 ai.userName = getAttributeValue(xpp, "UserName", account, 10); 399 if (DBG) logd("userName=" + ai.userName); 400 401 ai.clientPW = getAttributeValue(xpp, "ClientPW", account, 11); 402 if (DBG) logd("clientPW=" + ai.clientPW); 403 404 ai.clientNonce = getAttributeValue(xpp, "ClientNonce", account, 12); 405 if (DBG) logd("clientNonce=" + ai.clientNonce); 406 407 ai.proxyAddr = getRealString(getAttributeValue(xpp, "ProxyAddr", account, 13)); 408 if (DBG) logd("proxyAddr=" + ai.proxyAddr); 409 410 ai.proxyPortNbr = getRealString(getAttributeValue(xpp, "ProxyPortNbr", account, 14)); 411 if (DBG) logd("addr=" + ai.proxyPortNbr); 412 413 // FIXME: check should be on account name instead of isFirst 414 if (writeAccount2Dmt(ai) && isFirst) { 415 if (DBG) logd("setFotaServerID: " + ai.serverID); 416 417 ContentValues values = new ContentValues(); 418 values.put("name", "FOTAServerID"); 419 values.put("value", ai.serverID); 420 db.insert("dmFlexs", null, values); 421 isFirst = false; 422 } 423 } 424 425 if (in != null) { 426 eventType = xpp.next(); 427 } else { 428 num_accounts++; 429 } 430 } 431 432 if (in != null) { 433 in.close(); 434 } 435 436 } catch (IOException e) { 437 loge("IOException in loadDmAccount", e); 438 } catch (XmlPullParserException e) { 439 loge("XmlPullParserException in loadDmAccount", e); 440 } 441 } 442 443 private String getAttributeValue(XmlPullParser xpp, String attribute, String[] account, int idx) { 444 if (xpp != null) { 445 return xpp.getAttributeValue(null, attribute); 446 } else if (account != null && idx < account.length) { 447 return account[idx]; 448 } else { 449 return null; 450 } 451 } 452 453 private boolean writeAccount2Dmt(AccountInfo ai) { 454 if (DBG) logd("enter writeAccount2Dmt"); 455 456 String acctName = ai.serverID; // e.g. "sprint"; this is also the value for ServerID 457 String dmServerNodePath = "./DMAcc/" + acctName; 458 459 logd("XXX DELETING old server node path: " + dmServerNodePath); 460 NativeDM.deleteNode(dmServerNodePath); 461 462 if (NativeDM.createInterior(dmServerNodePath) != DMResult.SYNCML_DM_SUCCESS) { 463 loge("createInterior '" + acctName + "' Error"); 464 return false; 465 } 466 467 if (NativeDM.createLeaf(dmServerNodePath + "/ServerID", ai.serverID) 468 != DMResult.SYNCML_DM_SUCCESS) { 469 loge("createInterior '" + dmServerNodePath + "/ServerId' Error"); 470 return false; 471 } 472 473 if (NativeDM.createLeaf(dmServerNodePath + "/AppID", "w7") != DMResult.SYNCML_DM_SUCCESS) { 474 loge("createInterior '" + dmServerNodePath + "/AppID' Error"); 475 return false; 476 } 477 478 if (NativeDM.createLeaf(dmServerNodePath + "/Name", ai.serverName) 479 != DMResult.SYNCML_DM_SUCCESS) { 480 loge("createLeaf '" + dmServerNodePath + "/Name' Error"); 481 return false; 482 } 483 484 if (NativeDM.createLeaf(dmServerNodePath + "/PrefConRef", ai.conRef) 485 != DMResult.SYNCML_DM_SUCCESS) { 486 loge("createLeaf '" + dmServerNodePath + "/ConRef' Error"); 487 return false; 488 } 489 490 if (NativeDM.createLeaf(dmServerNodePath + "/AAuthPref", ai.authPref) 491 != DMResult.SYNCML_DM_SUCCESS) { 492 loge("createLeaf '" + dmServerNodePath + "/AAuthPref' Error"); 493 return false; 494 } 495 496 dmServerNodePath += "/AppAddr"; 497 if (NativeDM.createInterior(dmServerNodePath) != DMResult.SYNCML_DM_SUCCESS) { 498 loge("createInterior '" + dmServerNodePath + "' Error"); 499 return false; 500 } 501 502 dmServerNodePath += "/1"; // limited to one server address per account 503 504 if (NativeDM.createInterior(dmServerNodePath) != DMResult.SYNCML_DM_SUCCESS) { 505 loge("createInterior '" + dmServerNodePath + "' Error"); 506 return false; 507 } 508 509 if ("sprint".equalsIgnoreCase(ai.serverID)) { 510 String address = DMHelper.getServerUrl(mContext); 511 if (!TextUtils.isEmpty(address)) { 512 logd("Overriding server URL to: " + address); 513 ai.addr = address; 514 } 515 } 516 517 if (NativeDM.createLeaf(dmServerNodePath + "/Addr", ai.addr) 518 != DMResult.SYNCML_DM_SUCCESS) { 519 loge("createLeaf '" + dmServerNodePath + "/Addr' Error"); 520 return false; 521 } 522 523 if (NativeDM.createLeaf(dmServerNodePath + "/AddrType", ai.addrType) 524 != DMResult.SYNCML_DM_SUCCESS) { 525 loge("createLeaf '" + dmServerNodePath + "/AddrType' Error"); 526 return false; 527 } 528 529 dmServerNodePath += "/Port"; 530 if (NativeDM.createInterior(dmServerNodePath) != DMResult.SYNCML_DM_SUCCESS) { 531 loge("createInterior '" + dmServerNodePath + "' Error"); 532 return false; 533 } 534 535 dmServerNodePath += "/1"; // limited to one port number per server address 536 537 if (NativeDM.createInterior(dmServerNodePath) != DMResult.SYNCML_DM_SUCCESS) { 538 loge("createInterior '" + dmServerNodePath + "' Error"); 539 return false; 540 } 541 542 if (NativeDM.createLeaf(dmServerNodePath + "/PortNbr", ai.portNbr) 543 != DMResult.SYNCML_DM_SUCCESS) { 544 loge("createLeaf '" + dmServerNodePath + "/PortNbr' Error"); 545 return false; 546 } 547 548 // collection of authentication credentials 549 dmServerNodePath = "./DMAcc/" + acctName + "/AppAuth"; 550 551 if (NativeDM.createInterior(dmServerNodePath) != DMResult.SYNCML_DM_SUCCESS) { 552 loge("createInterior '" + dmServerNodePath + "' Error"); 553 return false; 554 } 555 556 // server credentials for authenticating the server from the OMA DM client 557 dmServerNodePath += "/Server"; 558 559 if (NativeDM.createInterior(dmServerNodePath) != DMResult.SYNCML_DM_SUCCESS) { 560 loge("createInterior '" + dmServerNodePath + "' Error"); 561 return false; 562 } 563 564 String authLevel = "SRVCRED"; 565 566 if (NativeDM.createLeaf(dmServerNodePath + "/AAuthLevel", authLevel) 567 != DMResult.SYNCML_DM_SUCCESS) { 568 loge("createLeaf '" + dmServerNodePath + "/AAuthLevel' Error"); 569 return false; 570 } 571 572 if (NativeDM.createLeaf(dmServerNodePath + "/AAuthType", ai.authPref) 573 != DMResult.SYNCML_DM_SUCCESS) { 574 loge("createLeaf '" + dmServerNodePath + "/AAuthType' Error"); 575 return false; 576 } 577 578 if (NativeDM.createLeaf(dmServerNodePath + "/AAuthName", acctName) 579 != DMResult.SYNCML_DM_SUCCESS) { 580 loge("createLeaf '" + dmServerNodePath + "/AAuthName' Error"); 581 return false; 582 } 583 584 if (ai.serverID.equalsIgnoreCase("sprint") || 585 ai.serverID.equalsIgnoreCase("com.vzwdmserver")) { 586 String intentName; 587 String serviceName; 588 if (ai.serverID.equalsIgnoreCase("sprint")) { 589 intentName = "com.android.sdm.plugins.sprintdm.SprintDMPlugin"; 590 serviceName = "SprintDMService"; 591 } else { 592 intentName = "com.android.sdm.plugins.connmo.ConnmoPlugin"; 593 serviceName = "ConnmoService"; 594 } 595 logd("ServerID is " + ai.serverID); 596 if (isBoundTo == null || !isBoundTo.equalsIgnoreCase(ai.serverID)) { 597 unbind(); 598 Intent intent = new Intent(intentName); 599 if (mContext.bindService(intent, mConnection, Context.BIND_AUTO_CREATE)) { 600 isBoundTo = ai.serverID; 601 synchronized (mLock) { 602 if (mPluginConnection == null) { 603 logd("Waiting for binding to " + serviceName); 604 try { 605 mLock.wait(); 606 } catch (Exception e) { 607 loge("Exception in writeAccount2Dmt->wait: ", e); 608 } 609 } 610 } 611 } 612 } else { 613 logd("Already bound to " + serviceName); 614 } 615 } else { 616 unbind(); 617 } 618 619 boolean hasWriteServerPW = false; 620 try { 621 if (mPluginConnection != null) { 622 String serverPW = mPluginConnection.getServerPW(ai.serverPW); 623 if (serverPW != null) { 624 ai.serverPW = serverPW; 625 logd("ServerPW from plugin: " + serverPW); 626 } else { 627 // This must be for vzw 628 byte[] svrPasswd = hexStringToBytes(ai.serverPW); 629 if (NativeDM.createLeaf(dmServerNodePath + "/AAuthSecret", svrPasswd) 630 != DMResult.SYNCML_DM_SUCCESS) { 631 loge("CreateLeaf '"+dmServerNodePath + "/AAuthSecret' Error"); 632 return false; 633 } 634 hasWriteServerPW = true; 635 } 636 } else { 637 logd("Using default ServerPW from dmAccounts: " + ai.serverPW); 638 } 639 } catch (Exception e) { 640 loge("Exception in writeAccount2Dmt->getServerPW", e); 641 } 642 643 if (!hasWriteServerPW && NativeDM.createLeaf(dmServerNodePath + "/AAuthSecret", ai.serverPW) 644 != DMResult.SYNCML_DM_SUCCESS) { 645 loge("createLeaf '" + dmServerNodePath + "/AAuthSecret' Error"); 646 return false; 647 } 648 649 if (NativeDM.createLeaf(dmServerNodePath + "/AAuthData", ai.serverNonce) 650 != DMResult.SYNCML_DM_SUCCESS) { 651 loge("createLeaf '" + dmServerNodePath + "/AAuthData' Error"); 652 return false; 653 } 654 655 // client credentials for authenticating ourselves to the OMA DM server 656 String dmClientNodePath = "./DMAcc/" + acctName + "/AppAuth/Client"; 657 658 if (NativeDM.createInterior(dmClientNodePath) != DMResult.SYNCML_DM_SUCCESS) { 659 loge("createInterior '" + dmServerNodePath + "' Error"); 660 return false; 661 } 662 663 String clientAuthLevel = "CLCRED"; 664 665 if (NativeDM.createLeaf(dmClientNodePath + "/AAuthLevel", clientAuthLevel) 666 != DMResult.SYNCML_DM_SUCCESS) { 667 loge("createLeaf '" + dmClientNodePath + "/AAuthLevel' Error"); 668 return false; 669 } 670 671 String clientAuthType = ai.authPref; 672 if (NativeDM.createLeaf(dmClientNodePath + "/AAuthType", clientAuthType) 673 != DMResult.SYNCML_DM_SUCCESS) { 674 loge("createLeaf '" + dmClientNodePath + "/AAuthType' Error"); 675 return false; 676 } 677 678 boolean hasWriteUserName = false; 679 try { 680 if (mPluginConnection != null) { 681 String username = mPluginConnection.getUsername(ai.userName); 682 if (username != null) { 683 ai.userName = username; 684 logd("Username from plugin: " + username); 685 } else { 686 // This must be for vzw 687 byte[] clientName = hexStringToBytes(ai.userName);//"e0e5e7eaebeb"); 688 if (NativeDM.createLeaf(dmClientNodePath + "/AAuthName", clientName) 689 != DMResult.SYNCML_DM_SUCCESS) { 690 loge("CreateLeaf '"+dmClientNodePath + "/AAuthName' Error"); 691 return false; 692 } 693 hasWriteUserName = true; 694 } 695 } else { 696 logd("Using default username from dmAccounts: " + ai.userName); 697 } 698 } catch (Exception e) { 699 loge("Exception in writeAccount2Dmt->getUsername", e); 700 } 701 702 if (!hasWriteUserName && NativeDM.createLeaf(dmClientNodePath + "/AAuthName", ai.userName) 703 != DMResult.SYNCML_DM_SUCCESS) { 704 loge("createLeaf '" + dmClientNodePath + "/AAuthName' Error"); 705 return false; 706 } 707 708 boolean hasWriteClientPW = false; 709 try { 710 if (mPluginConnection != null) { 711 String clientPW = mPluginConnection.getClientPW(ai.clientPW); 712 if (clientPW != null) { 713 ai.clientPW = clientPW; 714 logd("ClientPW from plugin: " + clientPW); 715 } else { 716 // This must be for vzw 717 byte[] clientPasswd=hexStringToBytes(ai.clientPW);//"ebe8efeeecec"); 718 if (NativeDM.createLeaf(dmClientNodePath + "/AAuthSecret", clientPasswd) != 719 DMResult.SYNCML_DM_SUCCESS) { 720 loge("CreateLeaf '" + dmClientNodePath + "/AAuthSecret' Error"); 721 return false; 722 } 723 hasWriteClientPW = true; 724 } 725 } else { 726 logd("Using default ClientPW from dmAccounts: " + ai.clientPW); 727 } 728 } catch (Exception e) { 729 loge("Exception in writeAccount2Dmt->getClientPW", e); 730 } 731 732 if (!hasWriteClientPW && NativeDM.createLeaf(dmClientNodePath + "/AAuthSecret", ai.clientPW) 733 != DMResult.SYNCML_DM_SUCCESS) { 734 loge("createLeaf '" + dmClientNodePath + "/AAuthSecret' Error"); 735 return false; 736 } 737 738 String clientNonce = ai.clientNonce; 739 if (NativeDM.createLeaf(dmClientNodePath + "/AAuthData", clientNonce) 740 != DMResult.SYNCML_DM_SUCCESS) { 741 loge("createLeaf '" + dmClientNodePath + "/AAuthData' Error"); 742 return false; 743 } 744 745 logd("leave writeAccount2Dmt: success"); 746 return true; 747 } 748 749 private InputStream getDMAccXmlInput() { 750 try { 751 File file = new File("/system/etc/", "dmAccounts.xml"); 752 if (file.exists()) { 753 InputStream in = new BufferedInputStream(new FileInputStream(file)); 754 logd("Load config from /system/etc/dmAccounts.xml"); 755 return in; 756 } else { 757 return null; 758 } 759 } catch (IOException e) { 760 loge("IOException in getDMAccXmlInput", e); 761 return null; 762 } 763 } 764 765 private String getRealString(String ins) { 766 if (ins != null && !ins.isEmpty() && ins.charAt(0) == '$') { 767 SharedPreferences prefs = mContext.getSharedPreferences("dmconfig", 0); 768 String key = ins.substring(1); 769 if (prefs.contains(key)) { 770 return prefs.getString(key, "unknown"); 771 } 772 } 773 return ins; 774 } 775 776 private void unbind() { 777 if (isBoundTo != null) { 778 logd("Unbinding from " + isBoundTo); 779 mContext.unbindService(mConnection); 780 isBoundTo = null; 781 synchronized (mLock) { 782 mPluginConnection = null; 783 } 784 } 785 } 786 787 private static byte[] hexStringToBytes(String s) { 788 byte[] ret; 789 790 if (s == null) return null; 791 792 int sz = s.length(); 793 794 ret = new byte[sz/2]; 795 796 for (int i=0 ; i <sz ; i+=2) { 797 ret[i/2] = (byte) ((hexCharToInt(s.charAt(i)) << 4) 798 | hexCharToInt(s.charAt(i+1))); 799 } 800 801 return ret; 802 } 803 804 private static int hexCharToInt(char c) { 805 if (c >= '0' && c <= '9') return (c - '0'); 806 if (c >= 'A' && c <= 'F') return (c - 'A' + 10); 807 if (c >= 'a' && c <= 'f') return (c - 'a' + 10); 808 809 throw new RuntimeException ("invalid hex char '" + c + "'"); 810 } 811 812 // private static void testSprintHashGenerator() { 813 // String equip = "A000001A2B3C4F"; 814 // String server = "sprint"; 815 // String secret = "foobar"; 816 // 817 // logd("XXXXX B64(MD5(\"foobar\") = " + sprintHashGenerator("foobar")); 818 // logd("XXXXX f(equip,server,secret) = " + sprintHashGenerator(equip + server + secret)); 819 // logd("XXXXX f(server,equip,secret) = " + sprintHashGenerator(server + equip + secret)); 820 // } 821 822 private static void logd(String msg) { 823 Log.d(TAG, msg); 824 } 825 826 private static void loge(String msg) { 827 Log.e(TAG, msg); 828 } 829 830 private static void loge(String msg, Throwable tr) { 831 Log.d(TAG, msg, tr); 832 } 833 } 834