Help us understand the problem. What is going on with this article?

Android Studio で ネットワークドライブ上にプロジェクトを作成しようとするとエラーになる原因詳細と当面の回避方法

More than 1 year has passed since last update.

Android Studio 利用中に直面した問題についてメッチャ深追いしたのでその結果を載せておく。Samba 周りの話はその手の人には常識なのかもしれない。

問題

Windows 版 Android Studio (ver. 3.1) で Samba をマウントしたディレクトリ (Z:\AndroidStudioProjects 等のドライブレターを割り当てたパス) にプロジェクトを作成しようとすると、 Everyone に Writable 権限がない場合に失敗する

  • そもそも ネットワークドライブにプロジェクトを作成するのは非推奨(だが仕方がない時もある!)
  • メッセージ: Could not ensure the target project location exists and is accessible: (パス名) Please try to specify another path.

原因

  • Android Studio はプロジェクトフォルダ作成直後に書き込み権限をチェックするが、Windows のネットワークフォルダの書き込み権限は正しくチェックできないことがままあり、書き込み権限無しと誤判定される
    • これは、リモートのユーザーID (SID) とローカルのユーザーID (SID) を単純比較しているために起こるように見える
    • ドメインユーザーでマウントしていたり、仮想マシンを複製した場合などで、ローカルとリモートの SID が一致する場合には正しく判定できる
    • Samba は素のままでは SID が idmap_tdb という方法で生成されるためうまくいかない。
    • 特に security = ads の場合は、 winbind をインストールし idmap_ad を有効にすれば、AD と一致した SID を返すようになる (後述)

修正方法: Samba ドライブのファイル所有者の SID を正しく設定する

Samba が報告する SID が AD の SID と一致しないために起こっている場合、Samba 側に winbind を入れて idmap_ad を有効にすればいけた。

winbind を入れたあとは smbd, nmbd を再起動し、 net cache flush してキャッシュをフラッシュすること。

以下は自分の環境でうまくいったもの。

  • AD の DC (Windows Server 2016) をセットアップ
    • 「ユーザーとコンピューター」「表示」「拡張機能」を有効に
    • ユーザーのプロパティの「属性エディター」タブでユーザーの LDAP 属性を編集できるようになるので、 uidNumber など UNIX 属性を追加しておく
    • uidNumber, loginShell, unixHomeDirectory, primaryGroupID
    • 参考: Missing Unix Attributes tab in ADUC on Windows 10 and Windows Server 2016
  • Linux サーバー側 (ubuntu) 参考 Setting up Samba as a Domain Member
    • Kerberos クライアントの設定 (後述 krb5.conf)
    • sssd の設定
    • smb.conf を書く
    • DC に ubuntu を登録 net ads join -U administrator
    • smbd, nmbd, winbind を起動

/etc/krb5.conf

[logging]
    default = FILE:/var/log/krb5.log

[libdefaults]
    default_realm = EARL.TEA.LOCALDOMAIN
    kdc_timesync = 1
    ccache_type = 4
    forwardable = true
    proxiable = true

[realms]
    EARL.TEA.LOCALDOMAIN = {
        kdc = win-n74eqau7up2.earl.tea.localdomain
        admin_server = win-n74eqau7up2.earl.tea.localdomain
        default_domain = EARL.TEA.LOCALDOMAIN
    }

[domain_realm]
    .earl.tea.localdomain = EARL.TEA.LOCALDOMAIN
    earl.tea.localdomain = EARL.TEA.LOCALDOMAIN

/etc/sssd/sssd.conf

[sssd]
services = nss, pam
config_file_version = 2
domains = EARL.TEA.LOCALDOMAIN

[domain/EARL.TEA.LOCALDOMAIN]

id_provider = ad
access_provider = ad

ldap_id_mapping = false

/etc/nsswitch.conf

sssd を入れたら勝手に書き換わっていた。

passwd:         compat sss
group:          compat sss
shadow:         compat sss
gshadow:        files

hosts:          files dns
networks:       files

protocols:      db files
services:       db files sss
ethers:         db files
rpc:            db files

netgroup:       nis sss
sudoers:        files sss

/etc/samba/smb.conf

[global]

workgroup = EARL
client signing = yes
client use spnego = yes
kerberos method = secrets and keytab
realm = EARL.TEA.LOCALDOMAIN
security = ads

dos charset = cp932
unix charset = utf-8

log file = /var/log/samba/log.%m
ldap ssl = no

idmap config EARL:backend = ad
idmap config EARL:schema_mode = rfc2307
idmap config EARL:range = 1001-20000

[homes]
comment = Home Directories
browseable = Yes
read only = No

回避方法: パーミッションを world writeble に

事前に空のフォルダを作成し、 Everyone に対して書き込み権限を与える。
1. Samba ネットワークドライブを公開している Unix 側 では chmod 777 パス で良い
2. マウントしている Windows 側 ではフォルダのプロパティで変更するか、次のようにする
- icacls パス /grant everyone:(F) (フォルダに対するフルコントロール)
- icacls パス /grant everyone:(IO)(OI)(CI)(F) (フルコントロールを子孫フォルダーと子孫ファイルでも継承させる)
- これを半自動化するスクリプトを後に示す

スクリプト化

エンドユーザーにコマンドラインを叩かせるのは運営上厄介なので次のようなスクリプトを作った。


# Z:\AndroidStudioProjects\ 以下に プロジェクトフォルダを作成するスクリプト (2018/4)
# Android Studio が Z:\ にプロジェクトを作成するには Everyone に書き込み権限がないとうまくいかないため.
# (プロジェクト作成ウィザードの Finish ボタンをクリックした時にエラー)

$WORKSPACE_DIR = "Z:\AndroidStudioProjects"

function Read-InputBoxDialog([string]$Message, [string]$WindowTitle, [string]$DefaultText)
{
    Add-Type -AssemblyName Microsoft.VisualBasic
    return [Microsoft.VisualBasic.Interaction]::InputBox($Message, $WindowTitle, $DefaultText)
}

function MakeDirAndGrantEveryone([string]$path)
{
  Z:
  New-Item $path -itemType Directory -Force
  icacls $path /grant "everyone:(IO)(OI)(CI)(F)"
  icacls $path /grant "everyone:(F)"
}

function msg([string] $text)
{
  Write-Host $text -ForegroundColor Cyan
}

Z:

New-Item $WORKSPACE_DIR -itemType Directory -Force


$newProjectName = Read-InputBoxDialog -Message "新しいプロジェクトの名前を入力してください (スペース不可)。"
if( $newProjectName -ne "" ) { 
  $path = Join-Path $WORKSPACE_DIR $newProjectName
  MakeDirAndGrantEveryone( $path )

  echo ""
  echo "******************************************************************************"
  echo "*"
  echo "*   Android Studio を起動し、"
  echo "*"
  msg  "*      $path"
  echo "*"
  echo "*  にプロジェクトを作成してください。"
  echo "*"
  echo "******************************************************************************"
  echo ""
  pause
}

ソースを追った、より細かい話

  1. Android Studio はプロジェクトの作成直後に Java の Files.isWritable を呼んでフォルダへの書き込み権限をチェックする。 NewProjectModel.java:225, FileSystemFileOp.java:174
  2. Samba のネットワークドライブに対して Files.isWritable は 書き込み権限があっても false を返す 参考 OpenJDK issue
  3. Java の Files.isWritable は Windows API の AccessCheck 関数を呼ぶ (sun.nio.fs.WindowsFileSystemProvider.java, sun.nio.fs.WindowsSecurity.java) が、これも false を返すようだ
    • Android Studio 同梱の Open JDK (JRE) 8 と、最新版の Oracle Java で動作確認

各ソフトウェア提供元などの議論

  • Oracle, OpenJDK:
  • Samba: 2003 年に それらしい投稿 を発見したがリプライなし
  • Google: それらしい議論なし
  • Microsoft: AuthzAccessCheck を使うサンプルコードが GetEffectiveRightsFromAcl function のページに掲載されている。 AuthzAccessCheck は サーバーから取得したファイルの security descriptor の各 ACE (権限リスト) を、 現在のユーザー (を表す AUTHZ_CLIENT_CONTEXT_HANDLE) でチェックするだけ。ドメインにログオンしている状態でこれがうまくいっていないということは、 Samba が渡してくる ACE の SID が現在のユーザーの SID と合致していない可能性がある? → そうだった。
keigoi
大学教員。 「型システム入門 (TAPL)」訳者の一人。 OCaml と Haskell が好きです。 かつては IT プランニングという企業において関数型プログラミング言語でソフトウェア開発をしていました。 ソフトウェア形式検証とプログラミング言語に興味があります。 博士(情報科学)。
http://keigoimai.info/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした