Làm cách nào để sao chép các tập tin cần quyền truy cập root bằng scp?


168

Tôi có một máy chủ Ubuntu mà tôi đang kết nối bằng SSH.

Tôi cần tải tệp từ máy của mình /var/www/lên máy chủ, các tệp trong /var/www/được sở hữu bởi root.

Sử dụng PuTTY, sau khi tôi đăng nhập, trước tiên tôi phải nhập sudo suvà nhập mật khẩu để có thể sửa đổi các tệp /var/www/.

Nhưng khi tôi sao chép tệp bằng WinSCP, tôi không thể tạo / sửa đổi tệp /var/www/vì người dùng tôi đang kết nối không có quyền đối với tệp /var/www/và tôi không thể nói sudo sunhư tôi làm trong trường hợp có phiên ssh .

Bạn có biết làm thế nào tôi có thể đối phó với điều này?

Nếu tôi đang làm việc trên máy cục bộ của mình, tôi sẽ gọi gksudo nautilusnhưng trong trường hợp này tôi chỉ có quyền truy cập đầu cuối vào máy.


Điều này có vẻ giống như một câu hỏi cho nhà cung cấp máy chủ ảo của bạn, hoặc cho các nhà phát triển putty hoặc woncp.
dobey

7
@dobey bạn sai lầm ghê gớm, đó là về đặc quyền của Ubuntu!
Dimitris Sapikas

7
Tại sao điều này bị đóng cửa? Đây là một câu hỏi hoàn toàn hợp lệ về việc sao chép các tệp bằng scp - mọi nhà phát triển web đều quen thuộc với tình huống này
Serge


Tôi có một vấn đề tương tự. Tôi tạo một tệp (HTML trong trường hợp này) trên máy tính Windows và cố gắng sao chép nó bằng thư mục WinSCP vào / var / www / html / website. Và nó nói rằng có một vấn đề cho phép. Bởi vì tôi có thể sao chép vào thư mục / nhà của mình, tôi đã sao chép tệp theo hai bước, nhưng nó không thuận tiện :-) Tôi đã thử thêm người dùng của mình vào nhóm dữ liệu www, nhưng không được. Bất kỳ ý tưởng tại sao thêm người dùng vào dữ liệu www vẫn không cho phép người dùng sao chép tệp vào thư mục thuộc sở hữu của nhóm dữ liệu www?
JanezKranjski

Câu trả lời:


126

Bạn nói đúng, không có sudokhi làm việc với scp. Cách giải quyết là sử dụng scpđể tải tệp lên thư mục mà người dùng của bạn có quyền tạo tệp, sau đó đăng nhập qua ssh và sử dụng sudođể di chuyển / sao chép tệp đến đích cuối cùng.

scp -r folder/ user@server.tld:/some/folder/you/dont/need/sudo
ssh user@server.tld
 $ sudo mv /some/folder /some/folder/requiring/perms 
# YOU MAY NEED TO CHANGE THE OWNER like:
# sudo chown -R user:user folder

Một giải pháp khác là thay đổi quyền / quyền sở hữu các thư mục bạn tải tệp lên, để người dùng không có đặc quyền của bạn có thể ghi vào các thư mục đó.

Nói chung, làm việc trong roottài khoản phải là một ngoại lệ, không phải là một quy tắc - cách bạn đặt câu hỏi khiến tôi nghĩ rằng có thể bạn đang lạm dụng nó một chút, điều này dẫn đến các vấn đề về quyền - trong trường hợp bình thường bạn không cần đặc quyền siêu quản trị để truy cập các tập tin của riêng bạn.

Về mặt kỹ thuật, bạn có thể định cấu hình Ubuntu để cho phép đăng nhập từ xa trực tiếp root, nhưng tính năng này bị vô hiệu hóa vì một lý do, vì vậy tôi khuyên bạn không nên làm điều đó.


Tôi đã không nhận được giải pháp đầu tiên, bạn có thể vui lòng trở thành một người đặc biệt hơn không?
Dimitris Sapikas

Khi tôi nói các tập tin của riêng tôi, ý tôi là / var / www, tôi đang sử dụng vps của mình làm máy chủ web .... trên thư mục của riêng tôi, tôi có quyền truy cập đầy đủ
Dimitris Sapikas

7
Re. Giải pháp đầu tiên. 1. scp -R mysite dimitris@myserver.com:/home/dimitris/2. ssh dimitris@myserver.com3. sudo mv ~/mysite /var/www- đó là một quá trình 2 bước, trước tiên bạn scpcác tập tin vào thư mục nhà của bạn, sau đó bạn đăng nhập qua ssh và sao chép / di chuyển các tập tin đến nơi họ nên được
Sergey

36

Một phương pháp khác là sao chép bằng tar + ssh thay vì scp:

tar -c -C ./my/local/dir \
  | ssh dimitris@myserver.com "sudo tar -x --no-same-owner -C /var/www"

2
Đây là cách tốt nhất để làm điều đó.
mttdbrd 30/03/2015

2
Tôi không thể làm cho phương pháp này hoạt động thành công. Như đã viết tôi nhận được sudo: sorry, you must have a tty to run sudo. Nếu tôi thêm "-t" để phân bổ TTY thì tôi nhận được Pseudo-terminal will not be allocated because stdin is not a terminal.. Tôi không thể thấy điều này làm việc mà không có mật khẩu sudo.
IBBoard

1
@IBBoard: thử giải pháp tại đây bằng ssh -t:ssh -t dimitris@myserver.com "sudo tar -x --no-same-owner -C /var/www"
Alexander Bird

2
@AlexanderBird Mặc dù nó hoạt động trong nhiều trường hợp, tôi không chắc nó hoạt động ở đây vì chúng tôi đang cố gắng đưa một tarball qua kết nối SSH. Xem serverfault.com/questions/14389/
Mạnh

Đây là những gì cuối cùng đã làm việc cho tôi. Bạn không có quyền vào một tập tin từ xa mà bạn muốn sao chép đến địa phương, thực hiện sudo tar, sau đó giải nén, cho phép thay đổi sử dụng chmodchown, và sau đó sao chép nó vào địa phương. Đặc biệt nếu đó là một thư mục.
đàn

28

Đường tắt

Từ máy chủ đến máy cục bộ:

ssh user@server "sudo cat /etc/dir/file" > /home/user/file

Từ máy cục bộ đến máy chủ:

cat /home/user/file | ssh user@server "sudo tee -a /etc/dir/file"

5
Câu trả lời này được đánh giá thấp. Thật đơn giản, sạch sẽ, đọc hoặc ghi một tập tin gốc với một thao tác nguyên tử duy nhất và không yêu cầu bất cứ điều gì chưa được đảm bảo ở đó nếu bạn đang sử dụng scp. Hạn chế chính là nó không sao chép quyền. Nếu bạn muốn điều đó, giải pháp tar là tốt hơn. Đây là một kỹ thuật mạnh mẽ, đặc biệt nếu được kết hợp với phép thuật xargs / bash để đi qua các đường dẫn ..
markgo2k

Tôi nghĩ rằng câu hỏi là về việc tải một tệp từ địa phương lên từ xa chứ không phải ngược lại
Korayem

1
Làm đẹp. Đây chính xác là những gì tôi đang tìm kiếm cả lên và xuống. Cảm ơn bạn
Jeremy

Chắc chắn là câu trả lời hàng đầu.
Andrew Watson

Điều này có thể được thực hiện cho một thư mục thay vì một tập tin không?
lucidbrot

26

Bạn cũng có thể sử dụng ansibleđể thực hiện điều này.

Sao chép vào máy chủ từ xa bằng mô-đun của ansiblecopy :

ansible -i HOST, -b -m copy -a "src=SRC_FILEPATH dest=DEST_FILEPATH" all

Tìm nạp từ máy chủ từ xa bằng mô-đun của ansiblefetch :

ansible -i HOST, -b -m fetch -a "src=SRC_FILEPATH dest=DEST_FILEPATH flat=yes" all

GHI CHÚ:

  • Dấu phẩy trong -i HOST,cú pháp không phải là một lỗi đánh máy. Đây là cách để sử dụng ansible mà không cần tệp kiểm kê.
  • -blàm cho các hành động trên máy chủ được thực hiện như root. -bmở rộng thành --becomevà mặc định --become-userlà root, với mặc định --become-methodlà sudo.
  • flat=yeschỉ sao chép tệp, không sao chép toàn bộ đường dẫn từ xa dẫn đến tệp
  • Sử dụng các ký tự đại diện trong đường dẫn tệp không được hỗ trợ bởi các mô-đun ansible này.
  • Sao chép một thư mục được hỗ trợ bởi copymô-đun, nhưng không phải bởi fetchmô-đun.

Yêu cầu cụ thể cho câu hỏi này

Đây là một ví dụ cụ thể và được chỉ định đầy đủ, giả sử thư mục trên máy chủ lưu trữ cục bộ của bạn có chứa các tệp được phân phối là sourcedirvà tên máy chủ của mục tiêu từ xa là hostname:

cd sourcedir && \
ansible \
   --inventory-file hostname, \ 
   --become \
   --become-method sudo \
   --become-user root \
   --module-name copy \
   --args "src=. dest=/var/www/" \
   all

Với lời mời ngắn gọn là:

cd sourcedir && \
ansible -i hostname, -b -m copy -a "src=. dest=/var/www/" all

Tái bút, tôi nhận ra rằng nói "chỉ cần cài đặt công cụ tuyệt vời này" là một câu trả lời điếc. Nhưng tôi đã thấy có thể là siêu hữu ích để quản trị các máy chủ từ xa, vì vậy việc cài đặt nó chắc chắn sẽ mang lại cho bạn những lợi ích khác ngoài việc triển khai các tệp.


Tôi thích câu trả lời này nhưng tôi khuyên bạn nên đưa nó vào câu hỏi được hỏi so với bình luận khái quát hơn trước khi upvote. một cái gì đó nhưansible -i "hostname," all -u user --become -m copy -a ...
Mike D

@MikeD: làm thế nào để thay đổi ở trên?
erik.weathers

1
Một cái gì đó giống như -i 'host,'cú pháp hợp lệ? Tôi nghĩ thật dễ dàng để mất dấu chấm câu như vậy khi đọc lệnh. (Đối với người đọc, ý tôi là, nếu không phải là cái vỏ.)
mwfearnley

1
@mwfearnley: chắc chắn, vỏ sẽ xử lý -i 'host,'và giống như -i host,hoặc -i "host,". Nói chung, tôi thích giữ những lời mời này càng ngắn càng tốt để giữ cho chúng không bị nản chí, nhưng bạn nên thoải mái làm cho nó dài dòng và rõ ràng như bạn nghĩ là cần thiết cho rõ ràng.
erik.weathers

2
Cách để đi ra ngoài suy nghĩ! Lớn sử dụng Ansible
Jonatan

12

Khi bạn chạy sudo su, mọi tệp bạn tạo sẽ được sở hữu bởi root, nhưng theo mặc định, không thể đăng nhập trực tiếp với quyền root bằng ssh hoặc scp. Cũng không thể sử dụng sudo với scp, vì vậy các tệp không thể sử dụng được. Khắc phục điều này bằng cách tuyên bố quyền sở hữu đối với các tệp của bạn:

Giả sử tên người dùng của bạn là dimitri, bạn có thể sử dụng lệnh này.

sudo chown -R dimitri:dimitri /home/dimitri

Từ đó trở đi, như đã đề cập trong các câu trả lời khác, cách "Ubuntu" là sử dụng sudo chứ không phải đăng nhập gốc. Đó là một mô hình hữu ích, với những lợi thế bảo mật tuyệt vời.


Tôi đang sử dụng giải pháp này bằng mọi cách, nhưng nếu tôi có thể truy cập đầy đủ vào hệ thống tệp của riêng mình, tôi không muốn nhập sudo chow ...cho mọi thư mục: S
Dimitris Sapikas

2
Việc thay đổi quyền sở hữu tất cả các tệp hệ thống cho người dùng để vượt qua sự thuận tiện rất không được khuyến khích. Nó cho phép bất kỳ lỗi không gian người dùng nào bạn có thể gặp phải để làm tổn hại nghiêm trọng đến bảo mật hệ thống của bạn. Sẽ tốt hơn nhiều khi thay đổi quyền sở hữu các tệp mà bạn cần thay đổi hoặc cập nhật bởi SCP, nhưng để lại mọi thứ khác thuộc quyền sở hữu của root (giống như được cho là vậy). Điều đó nói rằng, phần -Rtrong chownbảo nó thay đổi quyền sở hữu của thư mục đó và tất cả các tệp và thư mục con theo cách đệ quy ... để bạn có thể làm bất cứ điều gì mình thích.
kẻ phản diện

hmm .... có vẻ như làm việc tốt, cảm ơn bạn! xin lỗi tôi không thể upvote (hệ thống không cho phép tôi làm ...)
Dimitris Sapikas

11

Có thể cách tốt nhất là sử dụng rsync( Cygwin / cwRsync trong Windows) qua SSH?

Ví dụ: để tải tệp lên với chủ sở hữu www-data:

rsync -a --rsync-path="sudo -u www-data rsync" path_to_local_data/ login@srv01.example.com:/var/www

Trong trường hợp của bạn, nếu bạn cần quyền root, lệnh sẽ như thế này:

rsync -a --rsync-path="sudo rsync" path_to_local_data/ login@srv01.example.com:/var/www

Xem: scp đến máy chủ từ xa với sudo .


5

Nếu bạn sử dụng các công cụ OpenSSH thay vì PuTTY, bạn có thể thực hiện việc này bằng cách bắt đầu scptruyền tệp trên máy chủ sudo. Hãy chắc chắn rằng bạn có một sshdtrình nền chạy trên máy cục bộ của bạn. Với ssh -Rbạn có thể cung cấp cho máy chủ một cách để liên lạc với máy của bạn.

Trên máy của bạn:

ssh -R 11111:localhost:22 REMOTE_USERNAME@SERVERNAME

Ngoài việc đăng nhập bạn trên máy chủ, điều này sẽ chuyển tiếp mọi kết nối được thực hiện trên cổng 11111 của máy chủ sang cổng 22 của máy bạn: cổng mà bạn sshdđang nghe.

Trên máy chủ, bắt đầu truyền tệp như thế này:

cd /var/www/
sudo scp -P 11111 -r LOCAL_USERNAME@localhost:FOLDERNAME .

1

Bạn có thể sử dụng tập lệnh mà tôi đã viết được lấy cảm hứng từ chủ đề này:

touch /tmp/justtest && scpassudo /tmp/justtest remoteuser@ssh.superserver.com:/tmp/

nhưng điều này đòi hỏi một số thứ điên rồ (được btw. tự động thực hiện bằng tập lệnh)

  1. máy chủ mà tập tin đang được gửi tới sẽ không còn yêu cầu mật khẩu trong khi thiết lập kết nối ssh với máy tính nguồn
  2. do sự cần thiết của việc thiếu dấu nhắc sudo trên máy chủ, sudo sẽ không còn yêu cầu mật khẩu trên máy từ xa, cho người dùng

Đây là kịch bản:

interface=wlan0
if [[ $# -ge 3 ]]; then interface=$3; fi
thisIP=$(ifconfig | grep $interface -b1 | tail -n1 | egrep -o '[0-9.]{4,}' -m1 | head -n 1)
thisUser=$(whoami)
localFilePath=/tmp/justfortest
destIP=192.168.0.2
destUser=silesia
#dest 
#destFolderOnRemoteMachine=/opt/glassfish/glassfish/
#destFolderOnRemoteMachine=/tmp/

if [[ $# -eq 0 ]]; then 
echo -e "Send file to remote server to locatoin where root permision is needed.\n\tusage: $0 local_filename [username@](ip|host):(remote_folder/|remote_filename) [optionalInterface=wlan0]"
echo -e "Example: \n\ttouch /tmp/justtest &&\n\t $0 /tmp/justtest remoteuser@ssh.superserver.com:/tmp/ "
exit 1
fi

localFilePath=$1

test -e $localFilePath 

destString=$2
usernameAndHost=$(echo $destString | cut -f1 -d':')

if [[ "$usernameAndHost" == *"@"* ]]; then
destUser=$(echo $usernameAndHost | cut -f1 -d'@')
destIP=$(echo $usernameAndHost | cut -f2 -d'@')
else
destIP=$usernameAndHost
destUser=$thisUser
fi

destFolderOnRemoteMachine=$(echo $destString | cut -f2 -d':')

set -e #stop script if there is even single error

echo 'First step: we need to be able to execute scp without any user interaction'
echo 'generating public key on machine, which will receive file'
ssh $destUser@$destIP 'test -e ~/.ssh/id_rsa.pub -a -e ~/.ssh/id_rsa || ssh-keygen -t rsa'
echo 'Done'

echo 'Second step: download public key from remote machine to this machine so this machine allows remote machine (this one receiveing file) to login without asking for password'

key=$(ssh $destUser@$destIP 'cat ~/.ssh/id_rsa.pub')
if ! grep "$key" ~/.ssh/authorized_keys; then
echo $key >> ~/.ssh/authorized_keys
echo 'Added key to authorized hosts'
else
echo "Key already exists in authorized keys"
fi

echo "We will want to execute sudo command remotely, which means turning off asking for password"
echo 'This can be done by this tutorial http://stackoverflow.com/a/10310407/781312'
echo 'This you have to do manually: '
echo -e "execute in new terminal: \n\tssh $destUser:$destIP\nPress enter when ready"
read 
echo 'run there sudo visudo'
read
echo 'change '
echo '    %sudo   ALL=(ALL:ALL) ALL'
echo 'to'
echo '    %sudo   ALL=(ALL:ALL) NOPASSWD: ALL'
echo "After this step you will be done."
read

listOfFiles=$(ssh $destUser@$destIP "sudo ls -a")

if [[ "$listOfFiles" != "" ]]; then 
echo "Sending by executing command, in fact, receiving, file on remote machine"
echo 'Note that this command (due to " instead of '', see man bash | less -p''quotes'') is filled with values from local machine'
echo -e "Executing \n\t""identy=~/.ssh/id_rsa; sudo scp -i \$identy $(whoami)@$thisIP:$(readlink -f $localFilePath) $destFolderOnRemoteMachine"" \non remote machine"
ssh $destUser@$destIP "identy=~/.ssh/id_rsa; sudo scp -i \$identy $(whoami)@$thisIP:$(readlink -f $localFilePath) $destFolderOnRemoteMachine"
ssh $destUser@$destIP "ls ${destFolderOnRemoteMachine%\\\\n}/$(basename $localFilePath)"
if [[ ! "$?" -eq 0 ]]; then echo "errror in validating"; else echo -e "SUCCESS! Successfully sent\n\t$localFilePath \nto \n\t$destString\nFind more at http://arzoxadi.tk"; fi
else
echo "something went wrong with executing sudo on remote host, failure"

fi
ENDOFSCRIPT
) | sudo tee /usr/bin/scpassudo && chmod +x /usr/bin/scpassudo

@Braiam yeah, chắc chắn, xin lỗi vì liên kết, kịch bản khá dài và đó là lý do :)
test30

1

Bạn có thể kết hợp ssh, sudo và ví dụ tar để chuyển tệp giữa các máy chủ mà không thể đăng nhập với quyền root và không có quyền truy cập các tệp với người dùng của bạn. Điều này hơi khó, vì vậy tôi đã viết một kịch bản để giúp điều này. Bạn có thể tìm thấy tập lệnh ở đây: https://github.com/sigmunau/sudoscp

hoặc ở đây:

#! / thùng / bash
độ phân giải = 0
từ = $ 1
đến = $ 2
ca
ca
tệp = "$ @"
if test -z "$ từ" -o -z "$ đến" -o -z "$ files"
sau đó
    echo "Cách sử dụng: $ 0 (tệp) *"
    echo "ví dụ: $ 0 server1 server2 / usr / bin / myapp"
    thoát 1
fi

đọc -s -p "Nhập mật khẩu:" sudopassword
tiếng vang ""
temp1 = $ (mktemp)
temp2 = $ (mktemp)
(echo "$ sudopassword"; echo "$ sudopassword" | ssh $ từ sudo -S tar c -P -C / $ files 2> $ temp1) > $ temp2
đồ chua = $ {PIPESTATUS [0]}
nếu [$? -ne 0 -o $ sourceres -ne 0]
sau đó
    tiếng vang "Thất bại!" > & 2
    tiếng vang "$ từ đầu ra:"> & 2
    mèo $ temp1> & 2
    tiếng vang ""> & 2
    tiếng vang "$ đến đầu ra:"> & 2
    mèo $ temp2> & 2
    độ phân giải = 1
fi

rm $ temp1 $ temp2
thoát $ res

Chào mừng bạn đến hỏi Ubuntu. Bạn có thể vui lòng bao gồm các kịch bản trong câu trả lời của bạn? Tôi biết điều đó là không thể nhưng nếu repo github đã bị xóa hoặc url thay đổi thì câu trả lời sẽ bị hủy. Tốt hơn là bao gồm tập lệnh trực tiếp và để lại repo github làm nguồn.
Michael Lindman

0

Đây là phiên bản sửa đổi của câu trả lời của Willie Wheeler giúp chuyển (các) tệp qua tar nhưng cũng hỗ trợ chuyển mật khẩu sang sudo trên máy chủ từ xa.

(stty -echo; read passwd; stty echo; echo $passwd; tar -cz foo.*) \
  | ssh remote_host "sudo -S bash -c \"tar -C /var/www/ -xz; echo\""

Một chút phép thuật bổ sung ở đây là tùy chọn -S để sudo. Từ trang sudo man:

-S, --stdin Viết lời nhắc đến lỗi tiêu chuẩn và đọc mật khẩu từ đầu vào tiêu chuẩn thay vì sử dụng thiết bị đầu cuối. Mật khẩu phải được theo sau bởi một ký tự dòng mới.

Bây giờ chúng tôi thực sự muốn đầu ra của tar được chuyển thành ssh và điều đó chuyển hướng stdin của ssh sang stdout của tar, loại bỏ bất kỳ cách nào để chuyển mật khẩu vào sudo từ thiết bị đầu cuối tương tác. (Chúng ta có thể sử dụng tính năng ASKPASS của sudo ở đầu xa nhưng đó là một câu chuyện khác.) các subshell vào ssh. Điều này cũng có thêm lợi thế là không để lại biến môi trường chứa mật khẩu của chúng ta lơ lửng trong vỏ tương tác.

Bạn sẽ nhận thấy tôi đã không thực hiện 'đọc' với tùy chọn -p để in lời nhắc. Điều này là do lời nhắc mật khẩu từ sudo được chuyển trở lại stderr của shell tương tác của chúng tôi thông qua ssh. Bạn có thể tự hỏi "làm thế nào sudo thực thi khi nó chạy bên trong ssh bên phải đường ống của chúng tôi?" Khi chúng ta thực thi nhiều lệnh và chuyển đầu ra của một lệnh này sang shell khác, shell cha (vỏ tương tác trong trường hợp này) sẽ thực thi từng lệnh trong chuỗi ngay sau khi thực hiện lệnh trước đó. Khi mỗi lệnh phía sau một đường ống được thực thi, shell cha sẽ đính kèm (chuyển hướng) stdout của phía bên trái sang stdin của phía bên phải. Đầu ra sau đó trở thành đầu vào khi nó đi qua các quy trình.

$ (stty -echo; read passwd; stty echo; echo $passwd; tar -cz foo.*) | ssh 
remote_host "sudo -S bash -c \"tar -C /var/www/ -xz; echo\""
[sudo] password for bruce: 
[1]+  Stopped                 ( stty -echo; read passwd; stty echo; echo 
$passwd; tar -cz foo.* ) | ssh remote_host "sudo -S bash -c \"tar -C 
/var/www/ -xz; echo\""

$ pstree -lap $$
bash,7168
  ├─bash,7969
  ├─pstree,7972 -lap 7168
  └─ssh,7970 remote_host sudo -S bash -c "tar -C /var/www/ -xz; echo"`

Vỏ tương tác của chúng tôi là PID 7168, lớp con của chúng tôi là PID 7969 và quy trình ssh của chúng tôi là PID 7970.

Hạn chế duy nhất là đọc sẽ chấp nhận đầu vào trước khi sudo có thời gian để gửi lại lời nhắc. Trên một kết nối nhanh và máy chủ từ xa nhanh, bạn sẽ không nhận thấy điều này nhưng bạn có thể nếu chậm. Bất kỳ sự chậm trễ sẽ không ảnh hưởng đến khả năng nhập dấu nhắc; nó chỉ có thể xuất hiện sau khi bạn bắt đầu gõ.

Lưu ý Tôi chỉ cần thêm một mục nhập tệp máy chủ cho "remote_host" vào máy cục bộ của mình để dùng thử.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.