authpolicy: Implement daemon and D-Bus interface with Samba stub

Provides complete D-Bus interface with two new methods to refresh
user and device policy. Separates main/daemon from D-Bus interface
implementation and adds Samba interface stub to be implemented in a
subsequent CL. The D-Bus methods will be called by Chrome to
authenticate, join a device to a AD domain and fetch policy.

Code requires the CL below to compile.

BUG=chromium:653509
TEST=Emerges. Daemon runs, but just stub code so far.

CQ-DEPEND=CL:403068

Change-Id: Ic5eb4621f1c21fccc26e7e3f656b6751fdceba96
Reviewed-on: https://chromium-review.googlesource.com/403872
Commit-Ready: Lutz Justen <ljusten@chromium.org>
Tested-by: Lutz Justen <ljusten@chromium.org>
Tested-by: Roman Sorokin <rsorokin@chromium.org>
Reviewed-by: Lutz Justen <ljusten@chromium.org>
Reviewed-by: Roman Sorokin <rsorokin@chromium.org>
diff --git a/authpolicy/authpolicy.cc b/authpolicy/authpolicy.cc
index ce6f5c1..627f0e1 100644
--- a/authpolicy/authpolicy.cc
+++ b/authpolicy/authpolicy.cc
@@ -2,108 +2,215 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include <base/logging.h>
-#include <brillo/daemons/dbus_daemon.h>
-#include <brillo/dbus/async_event_sequencer.h>
+#include "authpolicy/authpolicy.h"
+
+#include <utility>
+#include <vector>
+
+#include <base/strings/stringprintf.h>
+#include <bindings/chrome_device_policy.pb.h>
+#include <bindings/device_management_backend.pb.h>
+#include <brillo/dbus/dbus_method_invoker.h>
 #include <chromeos/dbus/service_constants.h>
-#include <install_attributes/libinstallattributes.h>
 
-#include "authpolicy/org.chromium.AuthPolicy.h"
+#include "authpolicy/errors.h"
+#include "authpolicy/policy/preg_policy_encoder.h"
+#include "authpolicy/policy/proto/cloud_policy.pb.h"
+#include "authpolicy/samba_interface.h"
 
-using brillo::dbus_utils::AsyncEventSequencer;
+namespace em = enterprise_management;
 
-namespace org {
-namespace chromium {
+using brillo::dbus_utils::ExtractMethodCallResults;
+
 namespace authpolicy {
 
-const char kObjectServicePath[] = "/org/chromium/AuthPolicy/ObjectManager";
+AuthPolicy::AuthPolicy(
+    brillo::dbus_utils::ExportedObjectManager* object_manager)
+    : org::chromium::AuthPolicyAdaptor(this),
+      dbus_object_(object_manager, object_manager->GetBus(),
+                   org::chromium::AuthPolicyAdaptor::GetObjectPath()),
+      session_manager_proxy_(nullptr),
+      weak_ptr_factory_(this) {}
 
-class Domain : public org::chromium::AuthPolicyInterface {
- public:
-  explicit Domain(brillo::dbus_utils::ExportedObjectManager* object_manager)
-      : dbus_object_{new brillo::dbus_utils::DBusObject{
-        object_manager, object_manager->GetBus(),
-            org::chromium::AuthPolicyAdaptor::GetObjectPath()}} {
-      }
+void AuthPolicy::RegisterAsync(
+    const AsyncEventSequencer::CompletionAction& completion_callback) {
+  RegisterWithDBusObject(&dbus_object_);
+  dbus_object_.RegisterAsync(completion_callback);
+  session_manager_proxy_ = dbus_object_.GetBus()->GetObjectProxy(
+      login_manager::kSessionManagerServiceName,
+      dbus::ObjectPath(login_manager::kSessionManagerServicePath));
+  DCHECK(session_manager_proxy_);
+}
 
-  ~Domain() override = default;
-  bool AuthenticateUser(
-      brillo::ErrorPtr* error,
-      const std::string& in_user_principal_name,
-      const dbus::FileDescriptor& in_password_fd,
-      int32_t* out_code,
-      std::string* account_id) override {
+bool AuthPolicy::AuthenticateUser(brillo::ErrorPtr* error,
+                                  const std::string& in_user_principal_name,
+                                  const dbus::FileDescriptor& in_password_fd,
+                                  int32_t* out_error_code,
+                                  std::string* out_account_id) {
+  LOG(INFO) << "Received 'AuthenticateUser' request";
+  *out_error_code = 0;
+
+  // Call samba to authenticate user and get account id.
+  const char* error_code;
+  if (!samba_.AuthenticateUser(in_user_principal_name, in_password_fd.value(),
+                               out_account_id, &error_code)) {
+    brillo::Error::AddToPrintf(error, FROM_HERE, errors::kDomain,
+                               error_code, "Failed to authenticate user.");
     return false;
   }
 
-  bool JoinADDomain(
-      brillo::ErrorPtr* error,
-      const std::string& in_machine_name,
-      const std::string& in_user_principal_name,
-      const dbus::FileDescriptor& in_password_fd,
-      int32_t* out_code) override {
+  LOG(INFO) << "AuthenticateUser succeeded";
+  return true;
+}
+
+bool AuthPolicy::JoinADDomain(brillo::ErrorPtr* error,
+                              const std::string& in_machine_name,
+                              const std::string& in_user_principal_name,
+                              const dbus::FileDescriptor& in_password_fd,
+                              int32_t* out_error_code) {
+  LOG(INFO) << "Received 'JoinADDomain' request";
+  *out_error_code = 0;
+
+  // Call samba to join machine to the AD domain.
+  const char* error_code;
+  if (!samba_.JoinMachine(in_machine_name, in_user_principal_name,
+                          in_password_fd.value(), &error_code)) {
+    brillo::Error::AddToPrintf(error, FROM_HERE, errors::kDomain,
+                               error_code, "Failed to join AD domain.");
     return false;
   }
 
-  void RegisterAsync(
-      const AsyncEventSequencer::CompletionAction& completion_callback) {
-    scoped_refptr<AsyncEventSequencer> sequencer(new AsyncEventSequencer());
-    dbus_adaptor_.RegisterWithDBusObject(dbus_object_.get());
-    dbus_object_->RegisterAsync(
-              sequencer->GetHandler("Failed exporting Domain.", true));
-    sequencer->OnAllTasksCompletedCall({completion_callback});
+  LOG(INFO) << "JoinADDomain succeeded";
+  return true;
+}
+
+void AuthPolicy::RefreshUserPolicy(PolicyResponseCallback response,
+                                   const std::string& in_account_id) {
+  LOG(INFO) << "Received 'RefreshUserPolicy' request";
+
+  // Fetch GPOs for the current user.
+  const char* error_code;
+  std::vector<base::FilePath> gpo_file_paths;
+  if (!samba_.FetchUserGpos(in_account_id, &gpo_file_paths, &error_code)) {
+    response->ReplyWithError(FROM_HERE, errors::kDomain, error_code,
+                             "Failed to fetch user policy.");
+    return;
   }
 
- private:
-  org::chromium::AuthPolicyAdaptor dbus_adaptor_{this};
-  std::unique_ptr<brillo::dbus_utils::DBusObject> dbus_object_;
-};
-
-class Daemon : public brillo::DBusServiceDaemon {
- public:
-  Daemon() : DBusServiceDaemon(::authpolicy::kAuthPolicyInterface,
-    kObjectServicePath) {
+  // Load GPOs into policy.
+  em::CloudPolicySettings policy;
+  if (!policy::ParsePRegFilesIntoUserPolicy(gpo_file_paths, &policy,
+                                            &error_code)) {
+    response->ReplyWithError(FROM_HERE, errors::kDomain, error_code,
+                             "Failed to parse user policy preg files.");
+    return;
   }
 
- protected:
-  void RegisterDBusObjectsAsync(AsyncEventSequencer* sequencer) override {
-    domain_.reset(new Domain(object_manager_.get()));
-    domain_->RegisterAsync(
-        sequencer->GetHandler("Domain.RegisterAsync() failed.", true));
+  LOG(INFO) << "User policy fetch and parsing succeeded";
+
+  // Send policy to Session Manager.
+  StoreUserPolicy(in_account_id, policy, std::move(response));
+}
+
+void AuthPolicy::RefreshDevicePolicy(PolicyResponseCallback response) {
+  LOG(INFO) << "Received 'RefreshDevicePolicy' request";
+
+  // Fetch GPOs for the device.
+  const char* error_code;
+  std::vector<base::FilePath> gpo_file_paths;
+  if (!samba_.FetchDeviceGpos(&gpo_file_paths, &error_code)) {
+    response->ReplyWithError(FROM_HERE, errors::kDomain, error_code,
+                             "Failed to refresh device policy");
+    return;
   }
 
-  void OnShutdown(int* return_code) override {
-    DBusServiceDaemon::OnShutdown(return_code);
-    domain_.reset();
+  // Load GPOs into policy.
+  em::ChromeDeviceSettingsProto policy;
+  if (!policy::ParsePRegFilesIntoDevicePolicy(gpo_file_paths, &policy,
+                                              &error_code)) {
+    response->ReplyWithError(FROM_HERE, errors::kDomain, error_code,
+                             "Failed to parse device policy preg files.");
+    return;
   }
 
- private:
-  std::unique_ptr<Domain> domain_;
+  LOG(INFO) << "Device policy fetch and parsing succeeded";
 
-  DISALLOW_COPY_AND_ASSIGN(Daemon);
-};
+  // Send policy to Session Manager.
+  StoreDevicePolicy(policy, std::move(response));
+}
+
+void AuthPolicy::StoreUserPolicy(const std::string& account_id,
+                                 const em::CloudPolicySettings& policy,
+                                 PolicyResponseCallback callback) {
+  em::PolicyFetchResponse policy_response;
+  // Note: No signature required here, AD policy is unsigned!
+  if (!policy.SerializeToString(policy_response.mutable_policy_data())) {
+    callback->ReplyWithError(FROM_HERE, errors::kDomain,
+                             errors::kStorePolicyFailed,
+                             "Failed to serialize user policy protobuf.");
+    return;
+  }
+
+  StorePolicy(policy_response.SerializeAsString(), &account_id,
+              std::move(callback));
+}
+
+void AuthPolicy::StoreDevicePolicy(const em::ChromeDeviceSettingsProto& policy,
+                                   PolicyResponseCallback callback) {
+  em::PolicyFetchResponse policy_response;
+  // Note: No signature required here, AD policy is unsigned!
+  if (!policy.SerializeToString(policy_response.mutable_policy_data())) {
+    callback->ReplyWithError(FROM_HERE, errors::kDomain,
+                             errors::kStorePolicyFailed,
+                             "Failed to serialize device policy protobuf.");
+    return;
+  }
+  StorePolicy(policy_response.SerializeAsString(), nullptr,
+              std::move(callback));
+}
+
+void AuthPolicy::StorePolicy(const std::string& policy_blob,
+                             const std::string* account_id,
+                             PolicyResponseCallback callback) {
+  const char* const method =
+      account_id ? login_manager::kSessionManagerStoreUnsignedPolicyForUser
+                 : login_manager::kSessionManagerStoreUnsignedPolicy;
+
+  LOG(INFO) << "Calling Session Manager D-Bus method " << method;
+  dbus::MethodCall method_call(login_manager::kSessionManagerInterface, method);
+  dbus::MessageWriter writer(&method_call);
+  if (account_id) writer.AppendString(*account_id);
+  writer.AppendArrayOfBytes(
+      reinterpret_cast<const uint8_t*>(policy_blob.data()), policy_blob.size());
+  session_manager_proxy_->CallMethod(
+      &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+      base::Bind(&AuthPolicy::OnPolicyStored, weak_ptr_factory_.GetWeakPtr(),
+                 method, base::Passed(&callback)));
+}
+
+void AuthPolicy::OnPolicyStored(const char* method,
+                                PolicyResponseCallback callback,
+                                dbus::Response* response) {
+  brillo::ErrorPtr error;
+  bool done = false;
+  std::string msg;
+  if (!response) {
+    msg = base::StringPrintf("Call to %s failed. No response.", method);
+  } else if (!ExtractMethodCallResults(response, &error, &done)) {
+    msg = base::StringPrintf("Call to %s failed. %s",
+        method, error ? error->GetMessage().c_str() : "Unknown error.");
+  } else if (!done) {
+    msg = base::StringPrintf("Call to %s failed. Call returned false.", method);
+  }
+
+  if (!msg.empty()) {
+    LOG(ERROR) << msg;
+    callback->ReplyWithError(FROM_HERE, errors::kDomain,
+        errors::kStorePolicyFailed, msg);
+  } else {
+    LOG(INFO) << "Call to " << method << " succeeded.";
+    callback->Return(0);
+  }
+}
 
 }  // namespace authpolicy
-}  // namespace chromium
-}  // namespace org
-
-int main() {
-  // Safety check to ensure that authpolicyd cannot run after the device has
-  // been locked to a mode other than enterprise_ad.  (The lifetime management
-  // of authpolicyd happens through upstart, this check only serves as a second
-  // line of defense.)
-  InstallAttributesReader install_attributes_reader;
-  if (install_attributes_reader.IsLocked()) {
-    const std::string& mode =
-        install_attributes_reader.GetAttribute(
-            InstallAttributesReader::kAttrMode);
-    if (mode != InstallAttributesReader::kDeviceModeEnterpriseAD) {
-      LOG(ERROR) << "OOBE completed but device not in AD management mode.";
-      // Exit with "success" to prevent respawn by upstart.
-      exit(0);
-    }
-  }
-
-  org::chromium::authpolicy::Daemon daemon;
-  return daemon.Run();
-}
diff --git a/authpolicy/authpolicy.gyp b/authpolicy/authpolicy.gyp
index 60b5505..7054de8 100644
--- a/authpolicy/authpolicy.gyp
+++ b/authpolicy/authpolicy.gyp
@@ -40,6 +40,7 @@
       },
       'sources': [
         'authpolicy.cc',
+        'authpolicy_main.cc',
         'dbus_bindings/org.chromium.AuthPolicy.xml',
         'errors.cc',
         'policy/device_policy_encoder.cc',
@@ -58,7 +59,6 @@
           '-linstallattributes-<(libbase_ver)',
         ]
       },
-
     }
   ]
 }
diff --git a/authpolicy/authpolicy.h b/authpolicy/authpolicy.h
new file mode 100644
index 0000000..185bc21
--- /dev/null
+++ b/authpolicy/authpolicy.h
@@ -0,0 +1,86 @@
+// Copyright 2016 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef AUTHPOLICY_AUTHPOLICY_H_
+#define AUTHPOLICY_AUTHPOLICY_H_
+
+#include <memory>
+#include <string>
+
+#include <brillo/dbus/async_event_sequencer.h>
+#include <dbus/object_proxy.h>
+
+#include "authpolicy/org.chromium.AuthPolicy.h"
+#include "authpolicy/samba_interface.h"
+
+using brillo::dbus_utils::AsyncEventSequencer;
+
+namespace enterprise_management {
+class CloudPolicySettings;
+class ChromeDeviceSettingsProto;
+}
+
+namespace authpolicy {
+
+class AuthPolicy : public org::chromium::AuthPolicyAdaptor,
+                   public org::chromium::AuthPolicyInterface {
+ public:
+  using PolicyResponseCallback =
+      std::unique_ptr<brillo::dbus_utils::DBusMethodResponse<int32_t>>;
+
+  explicit AuthPolicy(
+      brillo::dbus_utils::ExportedObjectManager* object_manager);
+  ~AuthPolicy() override = default;
+
+  // Register the D-Bus object and interfaces.
+  void RegisterAsync(
+      const AsyncEventSequencer::CompletionAction& completion_callback);
+
+  // org::chromium::AuthPolicyInterface: (see org.chromium.AuthPolicy.xml)
+  bool AuthenticateUser(brillo::ErrorPtr* error,
+                        const std::string& in_user_principal_name,
+                        const dbus::FileDescriptor& in_password_fd,
+                        int32_t* out_error_code,
+                        std::string* out_account_id) override;
+  bool JoinADDomain(brillo::ErrorPtr* error, const std::string& in_machine_name,
+                    const std::string& in_user_principal_name,
+                    const dbus::FileDescriptor& in_password_fd,
+                    int32_t* out_error_code) override;
+  void RefreshUserPolicy(PolicyResponseCallback response,
+                         const std::string& in_account_id) override;
+  void RefreshDevicePolicy(PolicyResponseCallback response) override;
+
+ private:
+  // Sends the user policy blob to SessionManager.
+  void StoreUserPolicy(const std::string& account_id,
+                       const enterprise_management::CloudPolicySettings& policy,
+                       PolicyResponseCallback callback);
+
+  // Sends the device policy blob to SessionManager.
+  void StoreDevicePolicy(
+      const enterprise_management::ChromeDeviceSettingsProto& policy,
+      PolicyResponseCallback callback);
+
+  // Sends policy to SessionManager. Assumes |policy_blob| contains user policy
+  // if account_id is not nullptr, otherwise assumes it's device policy.
+  void StorePolicy(const std::string& policy_blob,
+                   const std::string* account_id,
+                   PolicyResponseCallback callback);
+
+  // Response callback from SessionManager, logs the result and calls callback.
+  void OnPolicyStored(const char* method, PolicyResponseCallback callback,
+                      dbus::Response* response);
+
+  SambaInterface samba_;
+
+  brillo::dbus_utils::DBusObject dbus_object_;
+  dbus::ObjectProxy* session_manager_proxy_;
+  base::WeakPtrFactory<AuthPolicy> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(AuthPolicy);
+};
+
+}  // namespace authpolicy
+
+#endif  // AUTHPOLICY_AUTHPOLICY_H_
diff --git a/authpolicy/authpolicy_main.cc b/authpolicy/authpolicy_main.cc
new file mode 100644
index 0000000..087051b
--- /dev/null
+++ b/authpolicy/authpolicy_main.cc
@@ -0,0 +1,73 @@
+// Copyright 2016 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <memory>
+
+#include <brillo/syslog_logging.h>
+#include <brillo/daemons/dbus_daemon.h>
+#include <chromeos/dbus/service_constants.h>
+#include <install_attributes/libinstallattributes.h>
+
+#include "authpolicy/authpolicy.h"
+
+namespace {
+
+const char kObjectServicePath[] = "/org/chromium/AuthPolicy/ObjectManager";
+
+}  // namespace
+
+namespace authpolicy {
+
+class Daemon : public brillo::DBusServiceDaemon {
+ public:
+  Daemon() : DBusServiceDaemon(kAuthPolicyServiceName, kObjectServicePath) {}
+
+ protected:
+  void RegisterDBusObjectsAsync(AsyncEventSequencer* sequencer) override {
+    auth_policy_.reset(new AuthPolicy(object_manager_.get()));
+    auth_policy_->RegisterAsync(
+        sequencer->GetHandler("AuthPolicy.RegisterAsync() failed.", true));
+  }
+
+  void OnShutdown(int* return_code) override {
+    DBusServiceDaemon::OnShutdown(return_code);
+    auth_policy_.reset();
+  }
+
+ private:
+  std::unique_ptr<AuthPolicy> auth_policy_;
+
+  DISALLOW_COPY_AND_ASSIGN(Daemon);
+};
+
+}  // namespace authpolicy
+
+int main(int argc, const char* const* argv) {
+  brillo::OpenLog("authpolicyd", true);
+  brillo::InitLog(brillo::kLogToSyslog);
+
+  // Safety check to ensure that authpolicyd cannot run after the device has
+  // been locked to a mode other than enterprise_ad.  (The lifetime management
+  // of authpolicyd happens through upstart, this check only serves as a second
+  // line of defense.)
+  InstallAttributesReader install_attributes_reader;
+  if (install_attributes_reader.IsLocked()) {
+    const std::string& mode =
+        install_attributes_reader.GetAttribute(
+            InstallAttributesReader::kAttrMode);
+    if (mode != InstallAttributesReader::kDeviceModeEnterpriseAD) {
+      LOG(ERROR) << "OOBE completed but device not in AD management mode.";
+      // Exit with "success" to prevent respawn by upstart.
+      exit(0);
+    }
+  }
+
+  // Run daemon
+  LOG(INFO) << "authpolicyd starting";
+  authpolicy::Daemon daemon;
+  int res = daemon.Run();
+  LOG(INFO) << "authpolicyd stopping with exit code " << res;
+
+  return res;
+}
diff --git a/authpolicy/dbus_bindings/org.chromium.AuthPolicy.xml b/authpolicy/dbus_bindings/org.chromium.AuthPolicy.xml
index 660b88d..fb664ad 100644
--- a/authpolicy/dbus_bindings/org.chromium.AuthPolicy.xml
+++ b/authpolicy/dbus_bindings/org.chromium.AuthPolicy.xml
@@ -3,19 +3,64 @@
 <node name="/org/chromium/AuthPolicy"
       xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0">
   <interface name="org.chromium.AuthPolicy">
+    <!--
+         AuthenticateUser:
+         @user_principal_name: user@workgroup.domain.
+         @password_fd: File descriptor of the user's password.
+         @error_code: Returned error code, 0 means success.
+         @account_id: Returned unique account id of the user.
+
+         Authenticates the user with an Active Directory domain.
+    -->
     <method name="AuthenticateUser">
       <arg name="user_principal_name" type="s" direction="in"/>
       <arg name="password_fd" type="h" direction="in"/>
-      <arg name="code" type="i" direction="out"/>
+      <arg name="error_code" type="i" direction="out"/>
       <arg name="account_id" type="s" direction="out" />
       <annotation name="org.chromium.DBus.Method.Kind" value="normal"/>
     </method>
+
+    <!--
+         JoinADDomain:
+         @machine_name: Netbios name of the machine (aka device) to join.
+         @user_principal_name: user@workgroup.domain, used for authentication.
+         @password_fd: File descriptor of the user's password.
+         @error_code: Returned error code, 0 means success.
+
+         Joins the given machine with an Active Directory domain.
+    -->
     <method name="JoinADDomain">
       <arg name="machine_name" type="s" direction="in"/>
       <arg name="user_principal_name" type="s" direction="in"/>
       <arg name="password_fd" type="h" direction="in"/>
-      <arg name="code" type="i" direction="out"/>
+      <arg name="error_code" type="i" direction="out"/>
       <annotation name="org.chromium.DBus.Method.Kind" value="normal"/>
     </method>
+
+    <!--
+         RefreshUserPolicy:
+         @account_id: Unique account id of the user to fetch policy for.
+         @error_code: Returned error code, 0 means success.
+
+         Retrieves user policy for the currently authenticated user and sends it
+         to Session Manager. Must be authenticated, see |AuthenticateUser|.
+    -->
+    <method name="RefreshUserPolicy">
+      <arg name="account_id" type="s" direction="in" />
+      <arg name="error_code" type="i" direction="out"/>
+      <annotation name="org.chromium.DBus.Method.Kind" value="async"/>
+    </method>
+
+    <!--
+         RefreshDevicePolicy:
+         @error_code: Returned error code, 0 means success.
+
+         Retrieves device policy and sends it to Session Manager. Must be joined
+         to an Active Directory domain, see |JoinADDomain|.
+    -->
+    <method name="RefreshDevicePolicy">
+      <arg name="error_code" type="i" direction="out"/>
+      <annotation name="org.chromium.DBus.Method.Kind" value="async"/>
+    </method>
   </interface>
 </node>
diff --git a/authpolicy/errors.cc b/authpolicy/errors.cc
index 22a392a..c9aa767 100644
--- a/authpolicy/errors.cc
+++ b/authpolicy/errors.cc
@@ -6,13 +6,30 @@
 
 namespace errors {
 
-const char kAuthPolicy[] = "authpolicyd";
-const char kPreg[] = "preg_error";
-const char kAuth[] = "auth_error";
-const char kJoin[] = "join_error";
-const char kFetch[]= "fetch_error";
-const char kDownload[]= "download_error";
-const char kCmd[] = "cmd_error";
+const char kDomain[] = "authpolicyd";
+
+const char kCreateDirFailed[] = "create_dir_failed";
+const char kDownloadGpoFailed[] = "download_gpo_failed";
+const char kKInitFailed[] = "kinit_failed";
+const char kNetAdsGpoListFailed[] = "net_ads_gpo_list_failed";
+const char kNetAdsInfoFailed[] = "net_ads_info_failed";
+const char kNetAdsJoinFailed[] = "net_ads_join_failed";
+const char kNetAdsSearchFailed[] = "net_ads_search_failed";
+const char kNotLoggedIn[] = "not_logged_in";
+const char kParseGpoFailed[] = "parse_gpo_failed";
+const char kParseGpoPathFailed[] = "parse_gpo_path_failed";
+const char kParseNetAdsInfoFailed[] = "parse_net_ads_info_failed";
+const char kParseNetAdsSearchFailed[] = "parse_net_ads_search_failed";
+const char kParseSmbConfFailed[] = "parse_smb_conf_failed";
+const char kParseUPNFailed[] = "parse_upn_failed";
+const char kPregFileNotFound[] = "preg_file_not_found";
+const char kPregParseError[] = "preg_parse_error";
+const char kPregReadError[] = "preg_error";
+const char kPregTooBig[] = "preg_too_big";
+const char kReadSmbConfFailed[] = "read_smb_conf_failed";
+const char kSmbClientFailed[] = "smd_client_failed";
+const char kStorePolicyFailed[] = "store_policy_failed";
+const char kWriteSmbConfFailed[] = "write_smb_conf_failed";
 
 }  // namespace errors
 
diff --git a/authpolicy/errors.h b/authpolicy/errors.h
index edf4ef1..17a2b03 100644
--- a/authpolicy/errors.h
+++ b/authpolicy/errors.h
@@ -8,15 +8,32 @@
 namespace errors {
 
 // Brillo error domain, see brillo::Error.
-extern const char kAuthPolicy[];
+extern const char kDomain[];
 
 // Brillo error codes, see brillo::Error.
-extern const char kPreg[];      // PReg parser error.
-extern const char kAuth[];      // Error authenticating.
-extern const char kJoin[];      // Error joining the AD domain.
-extern const char kFetch[];     // Error fetching policy.
-extern const char kDownload[];  // Error downloading GPO.
-extern const char kCmd[];       // Error executing a command.
+extern const char kCreateDirFailed[];        // Failed to create a directory.
+extern const char kDownloadGpoFailed[];      // Failed to download GPO.
+extern const char kKInitFailed[];            // Error authenticating.
+extern const char kNetAdsGpoListFailed[];    // Getting GPO list failed.
+extern const char kNetAdsInfoFailed[];       // Getting DC name failed.
+extern const char kNetAdsJoinFailed[];       // Joining machine to AD failed.
+extern const char kNetAdsSearchFailed[];     // Getting account id failed.
+extern const char kNotLoggedIn[];            // Can't fetch GPOs, not logged in.
+extern const char kParseGpoFailed[];         // Can't parse gpo list result.
+extern const char kParseGpoPathFailed[];     // Failed to parse GPO filesyspath.
+extern const char kParseNetAdsInfoFailed[];  // Can't parse DC name info.
+extern const char
+    kParseNetAdsSearchFailed[];              // Can't parse account id info.
+extern const char kParseSmbConfFailed[];     // Failed to parse samba conf file.
+extern const char kParseUPNFailed[];         // Can't parse user principal name.
+extern const char kPregFileNotFound[];       // Preg file path does not exist.
+extern const char kPregParseError[];         // Failed to parse a preg file.
+extern const char kPregReadError[];          // Failed to load a preg file.
+extern const char kPregTooBig[];             // Preg file was too big.
+extern const char kReadSmbConfFailed[];      // Failed to read samba conf file.
+extern const char kSmbClientFailed[];        // Downloading GPOs failed.
+extern const char kStorePolicyFailed[];      // Can't send to Session Manager.
+extern const char kWriteSmbConfFailed[];     // Failed to write samba conf file.
 
 }  // namespace errors
 
diff --git a/authpolicy/etc/dbus-1/org.chromium.AuthPolicy.conf b/authpolicy/etc/dbus-1/org.chromium.AuthPolicy.conf
index 2273031..e7fcf7d 100644
--- a/authpolicy/etc/dbus-1/org.chromium.AuthPolicy.conf
+++ b/authpolicy/etc/dbus-1/org.chromium.AuthPolicy.conf
@@ -18,5 +18,11 @@
     <allow send_destination="org.chromium.AuthPolicy"
            send_interface="org.chromium.AuthPolicy"
            send_member="JoinADDomain"/>
+    <allow send_destination="org.chromium.AuthPolicy"
+           send_interface="org.chromium.AuthPolicy"
+           send_member="RefreshUserPolicy"/>
+    <allow send_destination="org.chromium.AuthPolicy"
+           send_interface="org.chromium.AuthPolicy"
+           send_member="RefreshDevicePolicy"/>
   </policy>
 </busconfig>
diff --git a/authpolicy/policy/policy_encoder_helper.cc b/authpolicy/policy/policy_encoder_helper.cc
index 639c6e2..a6d5c9a 100644
--- a/authpolicy/policy/policy_encoder_helper.cc
+++ b/authpolicy/policy/policy_encoder_helper.cc
@@ -44,18 +44,16 @@
 namespace helper {
 
 bool LoadPRegFile(const base::FilePath& preg_file,
-                  brillo::ErrorPtr* error,
-                  RegistryDict* dict) {
-  // Report the error if the preg file does not exist.
+                  RegistryDict* out_dict,
+                  const char** out_error_code) {
   if (!base::PathExists(preg_file)) {
-    brillo::Error::AddToPrintf(error, FROM_HERE, errors::kAuthPolicy,
-                               errors::kPreg, "PReg file doesn't exist: %s",
-                               preg_file.value().c_str());
+    LOG(ERROR) << "PReg file " << preg_file.value() << " does not exist";
+    *out_error_code = errors::kPregFileNotFound;
     return false;
   }
 
-  // Load the file.
-  return preg_parser::ReadFile(preg_file, kRegistryKey, dict, error);
+  return preg_parser::ReadFile(preg_file, kRegistryKey, out_dict,
+                               out_error_code);
 }
 
 bool GetAsBoolean(const base::Value* value, bool* bool_value) {
diff --git a/authpolicy/policy/policy_encoder_helper.h b/authpolicy/policy/policy_encoder_helper.h
index 0a73d42..e8192fb 100644
--- a/authpolicy/policy/policy_encoder_helper.h
+++ b/authpolicy/policy/policy_encoder_helper.h
@@ -8,7 +8,6 @@
 #include <string>
 
 #include "base/values.h"
-#include "brillo/errors/error.h"
 
 namespace base {
 class FilePath;
@@ -22,8 +21,8 @@
 
 // Checks a PReg file for existence and loads it into |dict|.
 bool LoadPRegFile(const base::FilePath& preg_file,
-                  brillo::ErrorPtr* error,
-                  RegistryDict* dict);
+                  RegistryDict* out_dict,
+                  const char** out_error_code);
 
 // Similar to base::Value::GetAsBoolean(), but in addition it converts int
 // values of 0 or 1 to bool. Returns true on success and stores the output in
diff --git a/authpolicy/policy/preg_parser.cc b/authpolicy/policy/preg_parser.cc
index 6a137b9..722a684 100644
--- a/authpolicy/policy/preg_parser.cc
+++ b/authpolicy/policy/preg_parser.cc
@@ -248,20 +248,18 @@
 bool ReadFile(const base::FilePath& file_path,
               const base::string16& root,
               RegistryDict* dict,
-              brillo::ErrorPtr* error) {
+              const char** out_error_code) {
   base::MemoryMappedFile mapped_file;
   if (!mapped_file.Initialize(file_path) || !mapped_file.IsValid()) {
-    PLOG(ERROR) << "Failed to map ";
-    brillo::Error::AddToPrintf(error, FROM_HERE, errors::kAuthPolicy,
-                               errors::kPreg, "Failed to map PReg file %s",
-                               file_path.value().c_str());
+    PLOG(ERROR) << "Failed to map " << file_path.value();
+    *out_error_code = errors::kPregReadError;
     return false;
   }
 
   if (mapped_file.length() > kMaxPRegFileSize) {
-    brillo::Error::AddToPrintf(error, FROM_HERE, errors::kAuthPolicy,
-                               errors::kPreg, "PReg file %s too large: %zu",
-                               file_path.value().c_str(), mapped_file.length());
+    LOG(ERROR) << "PReg file " << file_path.value() << " too large: "
+               << mapped_file.length();
+    *out_error_code = errors::kPregTooBig;
     return false;
   }
 
@@ -269,9 +267,8 @@
   const int kHeaderSize = arraysize(kPRegFileHeader);
   if (mapped_file.length() < kHeaderSize ||
       memcmp(kPRegFileHeader, mapped_file.data(), kHeaderSize) != 0) {
-    brillo::Error::AddToPrintf(error, FROM_HERE, errors::kAuthPolicy,
-                               errors::kPreg, "Bad PReg file %s",
-                               file_path.value().c_str());
+    LOG(ERROR) << "Bad policy file " << file_path.value();
+    *out_error_code = errors::kPregParseError;
     return false;
   }
 
@@ -333,10 +330,10 @@
       HandleRecord(key_name.substr(root.size()), value, type, data, dict);
   }
 
-  brillo::Error::AddToPrintf(
-      error, FROM_HERE, errors::kAuthPolicy, errors::kPreg,
-      "Error parsing %s at offset %zu", file_path.value().c_str(),
-      reinterpret_cast<const uint8_t*>(cursor - 1) - mapped_file.data());
+  LOG(ERROR) << "Error parsing " << file_path.value() << " at offset "
+             << reinterpret_cast<const uint8_t*>(cursor - 1) -
+                    mapped_file.data();
+  *out_error_code = errors::kPregParseError;
   return false;
 }
 
diff --git a/authpolicy/policy/preg_parser.h b/authpolicy/policy/preg_parser.h
index 4be5e6b..528ac74 100644
--- a/authpolicy/policy/preg_parser.h
+++ b/authpolicy/policy/preg_parser.h
@@ -14,7 +14,6 @@
 #define AUTHPOLICY_POLICY_PREG_PARSER_H_
 
 #include "base/strings/string16.h"
-#include "brillo/errors/error.h"
 
 namespace base {
 class FilePath;
@@ -32,7 +31,7 @@
 bool ReadFile(const base::FilePath& file_path,
               const base::string16& root,
               RegistryDict* dict,
-              brillo::ErrorPtr* error);
+              const char** out_error_code);
 
 }  // namespace preg_parser
 }  // namespace policy
diff --git a/authpolicy/policy/preg_policy_encoder.cc b/authpolicy/policy/preg_policy_encoder.cc
index 928ac91..e5c6a9c 100644
--- a/authpolicy/policy/preg_policy_encoder.cc
+++ b/authpolicy/policy/preg_policy_encoder.cc
@@ -11,7 +11,6 @@
 
 #include "authpolicy/policy/device_policy_encoder.h"
 #include "authpolicy/policy/policy_encoder_helper.h"
-#include "authpolicy/policy/proto/cloud_policy.pb.h"
 #include "authpolicy/policy/registry_dict.h"
 #include "authpolicy/policy/user_policy_encoder.h"
 
@@ -26,15 +25,15 @@
 namespace policy {
 
 bool ParsePRegFilesIntoUserPolicy(const std::vector<base::FilePath>& preg_files,
-                                  brillo::ErrorPtr* error,
-                                  em::CloudPolicySettings* policy) {
+                                  em::CloudPolicySettings* policy,
+                                  const char** out_error_code) {
   DCHECK(policy);
 
   RegistryDict merged_mandatory_dict;
   RegistryDict merged_recommended_dict;
   for (const base::FilePath& preg_file : preg_files) {
     RegistryDict mandatory_dict;
-    if (!helper::LoadPRegFile(preg_file, error, &mandatory_dict))
+    if (!helper::LoadPRegFile(preg_file, &mandatory_dict, out_error_code))
       return false;
 
     // Recommended policies are stored in their own registry key. This can be
@@ -65,13 +64,13 @@
 
 bool ParsePRegFilesIntoDevicePolicy(
     const std::vector<base::FilePath>& preg_files,
-    brillo::ErrorPtr* error,
-    em::ChromeDeviceSettingsProto* policy) {
+    em::ChromeDeviceSettingsProto* policy,
+    const char** out_error_code) {
   DCHECK(policy);
 
   RegistryDict policy_dict;
   for (const base::FilePath& preg_file : preg_files) {
-    if (!helper::LoadPRegFile(preg_file, error, &policy_dict))
+    if (!helper::LoadPRegFile(preg_file, &policy_dict, out_error_code))
       return false;
   }
 
diff --git a/authpolicy/policy/preg_policy_encoder.h b/authpolicy/policy/preg_policy_encoder.h
index 75ba0a7..6f7c0a4 100644
--- a/authpolicy/policy/preg_policy_encoder.h
+++ b/authpolicy/policy/preg_policy_encoder.h
@@ -31,8 +31,8 @@
 // even though f3 has the higher index.
 bool ParsePRegFilesIntoUserPolicy(
     const std::vector<base::FilePath>& preg_files,
-    brillo::ErrorPtr* error,
-    enterprise_management::CloudPolicySettings* policy);
+    enterprise_management::CloudPolicySettings* policy,
+    const char** out_error_code);
 
 // Loads the given set of |preg_files| and encodes all device policies into the
 // given |policy| blob. If multiple files f1,...,fN are passed in, policies
@@ -40,8 +40,8 @@
 // - Policies in fn overwrite policies in fm if n > m.
 bool ParsePRegFilesIntoDevicePolicy(
     const std::vector<base::FilePath>& preg_files,
-    brillo::ErrorPtr* error,
-    enterprise_management::ChromeDeviceSettingsProto* policy);
+    enterprise_management::ChromeDeviceSettingsProto* policy,
+    const char** out_error_code);
 
 }  // namespace policy
 
diff --git a/authpolicy/samba_interface.h b/authpolicy/samba_interface.h
new file mode 100644
index 0000000..fb9ce2b
--- /dev/null
+++ b/authpolicy/samba_interface.h
@@ -0,0 +1,69 @@
+// Copyright 2016 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef AUTHPOLICY_SAMBA_INTERFACE_H_
+#define AUTHPOLICY_SAMBA_INTERFACE_H_
+
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include "base/files/file_path.h"
+
+// Helper methods for samba AD authentication, machine (device) joining and
+// policy fetching. Note: "Device" and "machine" can be used interchangably
+// here.
+
+namespace authpolicy {
+
+class SambaInterface {
+ public:
+  // STUB CODE, TO BE FILLED.
+
+  // Calls kinit to get a Kerberos ticket-granting-ticket (TGT) for the given
+  // |user_principal_name| (format: user_name@workgroup.domain). If a TGT
+  // already exists, it is renewed. The password must be readable from the pipe
+  // referenced by the file descriptor |password_fd|. On success, the user's
+  // object GUID is returned in |out_account_id|. The GUID uniquely identifies
+  // the user's account.
+  bool AuthenticateUser(const std::string& user_principal_name, int password_fd,
+                        std::string* out_account_id,
+                        const char** out_error_code) {
+    return false;
+  }
+
+  // Joins the local device with name |machine_name| to an AD domain. A user
+  // principal name and password are required for authentication (see
+  // |AuthenticateUser| for details).
+  bool JoinMachine(const std::string& machine_name,
+                   const std::string& user_principal_name, int password_fd,
+                   const char** out_error_code) {
+    return false;
+  }
+
+  // Downloads user policy files from the AD server. |account_id| is the unique
+  // user GUID returned from |AuthenticateUser|. The user's Kerberos
+  // authentication ticket must still be valid. If this operation fails, call
+  // |AuthenticateUser| and try again. User policy is given as Registry.pol
+  // (preg) files, a binary format encoding policy data.
+  bool FetchUserGpos(const std::string& account_id,
+                     std::vector<base::FilePath>* out_gpo_file_paths,
+                     const char** out_error_code) {
+    return false;
+  }
+
+  // Downloads device policy files from the AD server. The device must be joined
+  // to the AD domain already (see |JoinMachine|). During join, a machine
+  // password is stored in a keytab file, which is used for authentication for
+  // policy fetch. Device policy is given as Registry.pol (preg) files, a binary
+  // format encoding policy data.
+  bool FetchDeviceGpos(std::vector<base::FilePath>* out_gpo_file_paths,
+                       const char** out_error_code) {
+    return false;
+  }
+};
+
+}  // namespace authpolicy
+
+#endif  // AUTHPOLICY_SAMBA_INTERFACE_H_