1: <?php
2: declare(strict_types=1);
3: /**
4: * +------------------------------------------------------------+
5: * | apnscp |
6: * +------------------------------------------------------------+
7: * | Copyright (c) Apis Networks |
8: * +------------------------------------------------------------+
9: * | Licensed under Artistic License 2.0 |
10: * +------------------------------------------------------------+
11: * | Author: Matt Saladna (msaladna@apisnetworks.com) |
12: * +------------------------------------------------------------+
13: */
14:
15: use Opcenter\Terminal;
16:
17: /**
18: * Provides common functionality associated with SSH
19: *
20: * @package core
21: */
22: class Ssh_Module extends Module_Skeleton implements \Module\Skeleton\Contracts\Hookable
23: {
24: const PAM_SVC_NAME = 'ssh';
25: const DEPENDENCY_MAP = [
26: 'siteinfo',
27: 'ipinfo',
28: 'ipinfo6',
29: 'users',
30: 'auth'
31: ];
32:
33: /**
34: * {{{ void __construct(void)
35: *
36: * @ignore
37: */
38:
39: public function __construct()
40: {
41: parent::__construct();
42: $this->exportedFunctions = array(
43: '*' => PRIVILEGE_SITE,
44: 'enabled' => PRIVILEGE_SITE | PRIVILEGE_USER
45: );
46: }
47:
48: public function deny_user(string $user): bool
49: {
50: return (new Util_Pam($this->getAuthContext()))->remove($user, self::PAM_SVC_NAME);
51: }
52:
53: public function permit_user(string $user): bool
54: {
55: if ($this->auth_is_demo()) {
56: return error('SSH disabled for demo account');
57: }
58:
59: return (new Util_Pam($this->getAuthContext()))->add($user, self::PAM_SVC_NAME);
60: }
61:
62: public function _edit_user(string $userold, string $usernew, array $oldpwd)
63: {
64: if ($userold === $usernew) {
65: return;
66: }
67:
68: if (!$this->enabled() || !$this->user_permitted($userold)) {
69: return true;
70: }
71: // @TODO nuke active ssh sessions?
72: $pam = new Util_Pam($this->getAuthContext());
73: $pam->remove($userold, self::PAM_SVC_NAME);
74: $pam->add($usernew, self::PAM_SVC_NAME);
75:
76: return true;
77: }
78:
79: public function enabled()
80: {
81: $check = (bool)$this->getServiceValue('ssh', 'enabled');
82: if ($this->permission_level & PRIVILEGE_USER) {
83: $check = $check && $this->user_permitted($this->username);
84: }
85:
86: return $check;
87: }
88:
89: public function port_range(): array
90: {
91: if (!$this->getServiceValue('ssh', 'enabled') || !SSH_USER_DAEMONS) {
92: return array();
93: }
94:
95: return Terminal::formatPortRange(
96: $this->getServiceValue('ssh', 'port_index', [])
97: );
98: }
99:
100: public function user_enabled($user = null)
101: {
102: deprecated_func('Use user_permitted');
103: return $this->user_permitted($user);
104: }
105:
106: public function user_permitted($user = null)
107: {
108: if (!$this->getConfig('ssh', 'enabled')) {
109: warn('ssh not enabled on account');
110: return false;
111: }
112:
113: return (new Util_Pam($this->getAuthContext()))->check($user ?? $this->username, self::PAM_SVC_NAME);
114: }
115:
116: public function _housekeeping()
117: {
118: if (SSH_EMBED_TERMINAL && !APNSCPD_HEADLESS) {
119: dlog('Loading terminal...');
120: Service_Terminal::autostart();
121: } else {
122: Service_Terminal::stop();
123: }
124: }
125:
126: public function _create()
127: {
128: // stupid thor...
129: $conf = $this->getAuthContext()->getAccount()->new;
130: $admin = $conf['siteinfo']['admin_user'];
131: $pam = new Util_Pam($this->getAuthContext());
132: if ($this->auth_is_demo() && $pam->check($admin, self::PAM_SVC_NAME)) {
133: $pam->remove($admin, self::PAM_SVC_NAME);
134: }
135: }
136:
137: public function _verify_conf(\Opcenter\Service\ConfigurationContext $ctx): bool
138: {
139: return true;
140: }
141:
142: public function _delete()
143: {
144: // TODO: Implement _delete() method.
145: }
146:
147: public function _edit()
148: {
149: // TODO: Implement _edit() method.
150: }
151:
152: public function _create_user(string $user)
153: {
154: // TODO: Implement _create_user() method.
155: }
156:
157: public function _delete_user(string $user)
158: {
159: // TODO: Implement _delete_user() method.
160: }
161:
162:
163: }