Thực hiện chức năng Bash Script với Sudo


22

Tôi có một kịch bản thực hiện một số điều khác nhau, hầu hết trong số đó không yêu cầu bất kỳ đặc quyền đặc biệt nào. Tuy nhiên, một phần cụ thể, mà tôi đã chứa trong một hàm, cần có quyền root.

Tôi không muốn yêu cầu toàn bộ tập lệnh chạy dưới quyền root và tôi muốn có thể gọi hàm này, với quyền root, từ bên trong tập lệnh. Nhắc nhở mật khẩu nếu cần thiết không phải là vấn đề vì dù sao nó cũng tương tác. Tuy nhiên, khi tôi cố gắng sử dụng sudo functionx, tôi nhận được:

sudo: functionx: command not found

Như tôi dự đoán, exportđã không tạo ra sự khác biệt. Tôi muốn có thể thực thi chức năng trực tiếp trong tập lệnh hơn là phá vỡ nó và thực thi nó như một tập lệnh riêng biệt vì một số lý do.

Có cách nào để tôi có thể làm cho chức năng của mình "hiển thị" thành sudo mà không cần giải nén nó, tìm thư mục phù hợp và sau đó thực thi nó dưới dạng một tập lệnh độc lập không?

Hàm này dài khoảng một trang và chứa nhiều chuỗi, một số trích dẫn kép và một số trích dẫn đơn. Nó cũng phụ thuộc vào một chức năng menu được định nghĩa ở nơi khác trong tập lệnh chính.

Tôi chỉ mong ai đó có sudo ANY có thể chạy chức năng này, vì một trong những điều nó làm là thay đổi mật khẩu.


Thực tế là có một số chức năng liên quan làm cho nó thậm chí còn phức tạp hơn và dễ bị thất bại. Bây giờ bạn phải tìm tất cả các phụ thuộc như vậy (và tất cả các phụ thuộc của chúng, nếu có ... đến nhiều cấp độ sâu) bao gồm bất kỳ chức năng nào khác mà chức năng menu có thể gọi và declarechúng cũng vậy.
cas

Đồng ý, và tôi có thể phải cắn viên đạn và phá vỡ nó (và cố hết sức để xác định chính xác đường đi của nó, cộng với hy vọng người dùng cuối giữ các tệp cùng nhau) nếu không có giải pháp thay thế nào tốt hơn.
BryKKan 11/03/2016

Câu trả lời:


19

Tôi sẽ thừa nhận rằng không có cách đơn giản, trực quan để làm điều này, và đây là một chút hackey. Nhưng, bạn có thể làm điều đó như thế này:

function hello()
{
    echo "Hello!"
}

# Test that it works.
hello

FUNC=$(declare -f hello)
sudo bash -c "$FUNC; hello"

Hay đơn giản hơn:

sudo bash -c "$(declare -f hello); hello"

Nó hoạt động với tôi:

$ bash --version
GNU bash, version 4.3.42(1)-release (x86_64-apple-darwin14.5.0)
$ hello
Hello!
$
$ FUNC=$(declare -f hello)
$ sudo bash -c "$FUNC; hello"
Hello!

Về cơ bản, declare -fsẽ trả về nội dung của hàm, sau đó bạn chuyển sang bash -cnội tuyến.

Nếu bạn muốn xuất tất cả các hàm từ bash bên ngoài, hãy đổi FUNC=$(declare -f hello)thành FUNC=$(declare -f).

Chỉnh sửa

Để giải quyết các ý kiến ​​về trích dẫn, xem ví dụ này:

$ hello()
> {
> echo "This 'is a' test."
> }
$ declare -f hello
hello ()
{
    echo "This 'is a' test."
}
$ FUNC=$(declare -f hello)
$ sudo bash -c "$FUNC; hello"
Password:
This 'is a' test.

1
Điều này chỉ hoạt động một cách tình cờ, bởi vì echo "Hello!"nó thực sự giống như echo Hello!(tức là dấu ngoặc kép không tạo ra sự khác biệt cho lệnh echo cụ thể này). Trong nhiều / hầu hết các trường hợp khác, dấu ngoặc kép trong hàm có khả năng phá vỡ bash -clệnh.
cas

1
Điều này không trả lời câu hỏi ban đầu, vì vậy nếu tôi không có giải pháp tốt hơn tôi sẽ chấp nhận nó. Tuy nhiên, nó phá vỡ chức năng cụ thể của tôi (xem phần chỉnh sửa của tôi) vì nó phụ thuộc vào các chức năng được xác định ở nơi khác trong tập lệnh.
BryKKan 11/03/2016

1
tôi đã làm một số xét nghiệm trước đó chiều nay (sử dụng bash -xcthay vì chỉ bash -c) và có vẻ như bashlà đủ thông minh để điều tái quote trong tình huống này, thậm chí đến mức thay thế hai dấu ngoặc kép với dấu nháy đơn và thay đổi 'để '\''nếu cần thiết. Tôi chắc chắn sẽ có một số trường hợp không thể xử lý, nhưng nó chắc chắn hoạt động với ít nhất là các trường hợp đơn giản và phức tạp vừa phải - ví dụ: thửfunction hello() { filename="this is a 'filename' with single quotes and spaces" ; echo "$filename" ; } ; FUNC=$(declare -f hello) ; bash -xc "$FUNC ; hello"
cas

4
@cas declare -fin ra định nghĩa hàm trong một cách mà có thể tái phân tích bởi bash, vì vậy bash -c "$(declare -f)" không làm việc một cách chính xác (giả định rằng lớp vỏ bên ngoài cũng là bash). Ví dụ bạn đã đăng cho thấy nó hoạt động chính xác - trong đó các trích dẫn đã được thay đổi trong dấu vết , bởi vì bash in ra dấu vết theo cú pháp shell, ví dụ: hãy thửbash -xc 'echo "hello world"'
Gilles 'SO- ngừng trở thành ác quỷ'

3
Câu trả lời tuyệt vời. Tôi đã triển khai giải pháp của bạn - Tôi sẽ lưu ý rằng bạn có thể nhập chính tập lệnh từ trong tập lệnh, miễn là bạn lồng nó trong một điều kiện để kiểm tra xem có sudo yourFunctionbị phát hiện không (nếu không bạn sẽ gặp lỗi phân đoạn từ đệ quy)
GrayedFox

5

"Vấn đề" là làm sudosạch môi trường (ngoại trừ một số biến được phép) và đặt một số biến thành các giá trị an toàn được xác định trước để bảo vệ chống lại rủi ro bảo mật. nói cách khác, đây không thực sự là một vấn đề. Đó là một tính năng.

Ví dụ: nếu bạn đặt PATH="/path/to/myevildirectory:$PATH"sudokhông đặt PATH thành giá trị được xác định trước thì bất kỳ tập lệnh nào không chỉ định tên đường dẫn đầy đủ cho TẤT CẢ các lệnh mà nó chạy (tức là hầu hết các tập lệnh) sẽ xem /path/to/myevildirectorytrước bất kỳ thư mục nào khác. Đặt các lệnh như lshoặc grephoặc các công cụ phổ biến khác trong đó và bạn có thể dễ dàng làm bất cứ điều gì bạn thích trên hệ thống.

Cách dễ nhất / tốt nhất là viết lại hàm dưới dạng tập lệnh và lưu nó ở đâu đó trong đường dẫn (hoặc chỉ định đường dẫn đầy đủ đến tập lệnh trên sudodòng lệnh - điều mà bạn sẽ cần phải làm trừ khi sudođược định cấu hình để cho phép bạn để chạy lệnh BẤT K as như root) và làm cho nó có thể thực thi được vớichmod +x /path/to/scriptname.sh

Viết lại một chức năng vỏ như một kịch bản đơn giản như việc chỉ tiết kiệm các lệnh bên trong định nghĩa hàm vào một tập tin (không có function ..., {}dòng).


Điều này không trả lời câu hỏi theo bất kỳ cách nào. Ông đặc biệt muốn tránh đưa nó vào một kịch bản.
Will

1
Cũng sudo -Etránh làm sạch môi trường.
Will

Tôi hiểu ở một mức độ nào đó tại sao nó đang xảy ra. Tôi đã hy vọng có một số phương tiện để tạm thời ghi đè hành vi này. Ở đâu đó, một tùy chọn -E đã được đề cập, mặc dù điều đó không hiệu quả trong trường hợp này. Thật không may, trong khi tôi đánh giá cao lời giải thích về cách biến nó thành một kịch bản độc lập, thì điều đó đặc biệt không trả lời câu hỏi, vì tôi muốn có một phương tiện để tránh điều đó. Tôi không kiểm soát được nơi người dùng cuối đặt tập lệnh và tôi muốn tránh cả các thư mục được mã hóa cứng và bài hát và điệu nhảy cố gắng xác định chính xác kịch bản chính được chạy từ đâu.
BryKKan 11/03/2016

không quan trọng đó là những gì OP yêu cầu hay không. Nếu những gì anh ta muốn hoặc sẽ không hoạt động hoặc chỉ có thể được thực hiện để làm việc bằng cách làm một cái gì đó cực kỳ không an toàn thì họ cần được nói điều đó và cung cấp một giải pháp thay thế - ngay cả khi phương án đó là điều họ tuyên bố rõ ràng họ không muốn (bởi vì đôi khi đó là cách duy nhất hoặc tốt nhất để làm điều đó một cách an toàn). Sẽ là vô trách nhiệm khi nói với ai đó cách tự bắn vào chân mình mà không đưa ra cảnh báo cho họ về hậu quả có thể xảy ra khi chĩa súng vào chân họ và bóp cò.
cas

1
@cas Đó là sự thật. Nó không thể được thực hiện một cách an toàn là một câu trả lời chấp nhận được trong một số trường hợp. Xem chỉnh sửa cuối cùng của tôi mặc dù. Tôi tò mò muốn biết liệu ý kiến ​​của bạn về ý nghĩa bảo mật có giống như vậy không.
BryKKan 11/03/2016

3

Tôi đã viết Sudohàm bash của riêng mình để làm điều đó, nó hoạt động để gọi các hàm và bí danh:

function Sudo {
        local firstArg=$1
        if [ $(type -t $firstArg) = function ]
        then
                shift && command sudo bash -c "$(declare -f $firstArg);$firstArg $*"
        elif [ $(type -t $firstArg) = alias ]
        then
                alias sudo='\sudo '
                eval "sudo $@"
        else
                command sudo "$@"
        fi
}

2

Bạn có thể kết hợp các hàm và bí danh

Thí dụ:

function hello_fn() {
    echo "Hello!" 
}

alias hello='bash -c "$(declare -f hello_fn); hello_fn"' 
alias sudo='sudo '

sau đó sudo hellolàm việc


1

Đây là một biến thể về câu trả lời của Will . Nó bao gồm một catquá trình bổ sung , nhưng cung cấp sự thoải mái của heredoc. Tóm lại, nó như thế này:

f () 
{
    echo ok;
}

cat <<EOS | sudo bash
$(declare -f f)
f
EOS

Nếu bạn muốn có thêm thức ăn cho suy nghĩ, hãy thử điều này:

#!/bin/bash

f () 
{ 
    x="a b"; 
    menu "$x"; 
    y="difficult thing"; 
    echo "a $y to parse"; 
}

menu () 
{
    [ "$1" == "a b" ] && 
    echo "here's the menu"; 
}

cat <<EOS | sudo bash
$(declare -f f)
$(declare -f menu)
f
EOS

Đầu ra là:

here's the menu
a difficult thing to pass

Ở đây chúng ta có menuhàm tương ứng với câu hỏi trong câu hỏi, "được định nghĩa ở nơi khác trong tập lệnh chính". Nếu "nơi khác" có nghĩa là định nghĩa của nó đã được đọc ở giai đoạn này khi chức năng yêu cầu sudođang được thực thi, thì tình huống là tương tự. Nhưng nó có thể chưa được đọc. Có thể có một chức năng khác sẽ kích hoạt định nghĩa của nó. Trong trường hợp declare -f menunày phải được thay thế bằng một cái gì đó tinh vi hơn, hoặc toàn bộ tập lệnh được sửa theo cách mà menuhàm đã được khai báo.


Rất thú vị. Tôi sẽ phải thử nó vào một lúc nào đó. Và vâng, menuhàm sẽ được khai báo trước thời điểm này, như fđược gọi từ menu.
BryKKan

0

Giả sử rằng tập lệnh của bạn là (a) độc lập hoặc (b) có thể nguồn các thành phần của nó dựa trên vị trí của nó (thay vì nhớ vị trí thư mục chính của bạn), bạn có thể làm như thế này:

  • sử dụng $0tên đường dẫn cho tập lệnh, sử dụng tên đó trong sudolệnh và chuyển qua tùy chọn mà tập lệnh sẽ kiểm tra để gọi mật khẩu cập nhật. Miễn là bạn dựa vào việc tìm kiếm tập lệnh trong đường dẫn (thay vì chỉ chạy ./myscript), bạn sẽ nhận được một tên đường dẫn tuyệt đối $0.
  • kể từ khi sudochạy tập lệnh, nó có quyền truy cập vào các chức năng cần thiết trong tập lệnh.
  • ở đầu tập lệnh (đúng hơn là qua các khai báo hàm), tập lệnh sẽ kiểm tra tập lệnh uidvà nhận ra rằng nó đã được chạy với tư cách là người dùng root và thấy rằng nó có tùy chọn được đặt để bảo nó cập nhật mật khẩu, hãy đi và làm cái đó.

Các tập lệnh có thể tự lặp lại vì nhiều lý do: thay đổi đặc quyền là một trong những điều đó.

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.