-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathinstall_method5_sys_components.sql
More file actions
363 lines (327 loc) · 14.8 KB
/
install_method5_sys_components.sql
File metadata and controls
363 lines (327 loc) · 14.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
prompt Installing SYS components for Method5...
--#0: Check the user.
@code/check_user must_run_as_sys
--#1: Generate password hashes.
--The password is never known.
--Only hashes are required for management, nobody will ever login as the Method5 user.
--These hashes are safer than passwords but should still be kept secret.
--Do not record the hashes, just retrieve them from the data dictionary when needed.
--Create user and grant it privileges.
declare
--Password contains mixed case, number, and special characters.
--This should meet most password complexity requirements.
--It uses multiple sources for a truly random password.
v_password_youll_never_know varchar2 (30);
v_table_or_view_does_not_exist exception;
pragma exception_init (v_table_or_view_does_not_exist, -942);
begin
--Regenerate the password until it meets requirements for ORA12C_STRONG_VERIFY_FUNCTION
while v_password_youll_never_know is null
or regexp_count(v_password_youll_never_know, '[a-z]') < 2
or regexp_count(v_password_youll_never_know, '[A-Z]') < 2
or regexp_count(v_password_youll_never_know, '[0-9]') < 2
or regexp_count(v_password_youll_never_know, '[^a-zA-Z0-9]') < 2
loop
v_password_youll_never_know :=
--Remove ", ', @, ; since they don't work on all systems.
regexp_replace(dbms_random.string('p', 10), '["''/@;]', null)||
rawtohex(dbms_crypto.randombytes(5))||
substr(to_char(systimestamp, 'FF9'), 1, 6)||
'#$*';
end loop;
--Create user, grant it privileges.
execute immediate 'create user method5 identified by "'||v_password_youll_never_know||'"';
--Necessary master Method5 system privileges and why they are needed:
--If a user creates object in a different schema Method5 must grant them access to write to it.
execute immediate 'grant grant any object privilege to method5';
--Allows users to write tables to another user's schema.
execute immediate 'grant create any table to method5';
--Allows Method5 to monitor progress and update M5_AUDIT with metadata when the results are complete.
execute immediate 'grant create any trigger to method5';
--Allows Method5 to INSERT itno the results, _META, and _ERR tables on a user's schema.
execute immediate 'grant insert any table to method5';
--Allows Method5 to create the M5_RESULTS, M5_METADATA, and M5_ERRORS views on the user's schema.
execute immediate 'grant create any view to method5';
--Allows Method5 to create jobs for the user. The jobs are what gathers the results and enable parallelism.
execute immediate 'grant create any job to method5';
--Allows Method5 read the tables created in the user's schem, so it can update M5_AUDIT and display some useful information to DBMS_OUTPUT.
execute immediate 'grant select any table to method5';
--Allows Method5 to update _META tables with new metadata as the results come in.
execute immediate 'grant update any table to method5';
--Allows Method5 to drop existing tables, for the parameter P_TABLE_EXISTS_ACTION = DROP or TRUNCATE.
execute immediate 'grant drop any table to method5';
--Allows Method5 to drop existing tables, for the parameter P_TABLE_EXISTS_ACTION = DELETE.
execute immediate 'grant delete any table to method5';
--Allows Method5 to sleep, in the M4 procedures, so it can wait for more results.
execute immediate 'grant execute on dbms_lock to method5';
--Allows Method5 to create database links on the user's schemas.
execute immediate 'grant create any procedure to method5';
execute immediate 'grant execute any procedure to method5';
execute immediate 'grant drop any procedure to method5';
--Allows Method5 to manage links, which are central to the application.
execute immediate 'grant create database link to method5';
--Necessary master Method5 object privileges and why they are needed.
--Allows Method5 to run method5.m5_purge_sql_from_shared_pool.
--(That procedure purges one specific type of SQL statement for force hard parsing.
-- it does NOT simply run "alter system flush shared_pool".)
execute immediate 'grant select on sys.gv_$sql to method5';
execute immediate 'grant execute on sys.dbms_shared_pool to method5';
--Allows Method5 to send emails for intrusion detection and administrator daily summaries.
execute immediate 'grant execute on sys.utl_mail to method5';
--Allows Method5 to check for parameters that might not be configured correctly for running lots of jobs.
execute immediate 'grant select on sys.v_$parameter to method5';
--Allows Method5 to check for links in other schemas, to synchronize them if necesary.
execute immediate 'grant select on dba_db_links to method5';
--Allows Method5 to know the profile so it can use the same one remotely.
execute immediate 'grant select on dba_profiles to method5';
--Allows Method5 to see if P_TABLE_NAME already exists.
execute immediate 'grant select on dba_tables to method5';
--Allows Method5 to check if the user's account is locked.
execute immediate 'grant select on dba_users to method5';
--Allows Method5 to find out if some result columns cannot be sorted (such as LOBs).
execute immediate 'grant select on dba_tab_columns to method5';
--Allows Method5 to manage asynchronous jobs (create, alter, stop) and report on job status in admin email.
execute immediate 'grant select on dba_scheduler_jobs to method5';
execute immediate 'grant select on dba_scheduler_running_jobs to method5';
execute immediate 'grant select on dba_scheduler_job_run_details to method5';
execute immediate 'grant manage scheduler to method5';
--Allows Method5 to ensure nobody tries to create an object with the same name as a public synonym.
execute immediate 'grant select on dba_synonyms to method5';
--These *should* be public packages but they are often revoked because of old
--DoD STIG (security technical implementation guidelines) that many organizations use.
execute immediate 'grant execute on sys.dbms_pipe to method5';
execute immediate 'grant execute on sys.dbms_crypto to method5';
execute immediate 'grant execute on sys.dbms_random to method5';
--Allows Method5 to read database and platform name, for both traditional and multi-tenant,
--in the view DB_NAME_OR_CON_NAME_VW.
execute immediate 'grant select on sys.v_$instance to method5';
execute immediate 'grant select on sys.v_$database to method5';
--Optional, but useful and recommended master privilege:
execute immediate 'grant dba to method5';
---Optional privileges:
--Allows populating Method5 data from Oracle Enterprise Manager (OEM).
begin
execute immediate 'grant select on sysman.em_global_target_properties to method5';
execute immediate 'grant select on sysman.mgmt$db_dbninstanceinfo to method5';
exception when v_table_or_view_does_not_exist then null;
end;
--Create database link for retrieving the database link hash.
execute immediate replace(
q'[
create or replace procedure method5.temp_proc_manage_db_link2 is
begin
execute immediate '
create database link m5_install_db_link
connect to method5
identified by "$$PASSWORD$$"
using '' (invalid name since we do not need to make a real connection) ''
';
end;
]', '$$PASSWORD$$', v_password_youll_never_know);
execute immediate 'begin method5.temp_proc_manage_db_link2; end;';
execute immediate 'drop procedure method5.temp_proc_manage_db_link2';
--Clear shared pool in case the password is stored anywhere.
execute immediate 'alter system flush shared_pool';
end;
/
--#2: Audit all statements.
--This is sort-of a shared account and could benefit from extra protection.
audit all statements by method5;
--#3: Create SYS procedure to change database link password hashes.
--This procedure is very limited - it only works for one user, for specific link
--types, when called in a specific context.
begin
sys.dbms_ddl.create_wrapped(ddl => q'<
create or replace procedure sys.m5_change_db_link_pw(
/*
Purpose: Change an M5_ database link password hash to the Method5 password hash.
Since 11.2.0.4 the "IDENTIFIED BY VALUES" syntax does not work.
So the links must be created with a phony password and SYS.LINK$ is updated.
Warning 1: This only works on new database links that haven't been cached.
Warning 2: This procedure modifies undocumented SYS table LINK$.
It has only been tested for 11.2.0.4 and 12.1.0.2. It may not work with
the 18c encrypted data dictionary feature.
*/
p_m5_username varchar2,
p_dblink_username varchar2,
p_dblink_name varchar2)
is
v_owner varchar2(128);
v_name varchar2(128);
v_lineno number;
v_caller_t varchar2(128);
v_clean_dblink varchar2(4000);
begin
--Error if the link name does not start with M5.
if upper(trim(p_dblink_name)) not like 'M5%' then
raise_application_error(-20000, 'This procedure only works for Method5 links.');
end if;
--Cleanup the link name by making it uppercase and removing spaces.
v_clean_dblink := upper(trim(p_dblink_name));
--TODO? This would make it more difficult to ad hoc fix links.
--TODO? Use the Method5 authentication functions?
--Error if the caller is not the Method5 package.
--sys.owa_util.who_called_me(owner => v_owner, name => v_name, lineno => v_lineno, caller_t => v_caller_t);
--
--if v_name is null or v_name <> 'METHOD5' or v_caller_t is null or v_caller_t <> 'PACKAGE BODY' then
-- raise_application_error(-20000, 'This procedure only works in one specific context.');
--end if;
--Change the link password hash to the real password hash.
update sys.link$
set passwordx =
(
--The real password hash.
select passwordx
from sys.link$
join dba_users on link$.owner# = dba_users.user_id
where dba_users.username = p_m5_username
and name like 'M5_INSTALL_DB_LINK%'
)
--Ignore everything on or after the first period. It could be a current or old DB_DOMAIN.
where regexp_replace(name, '\..*') = regexp_replace(v_clean_dblink, '\..*')
and owner# = (select user_id from dba_users where username = upper(trim(p_dblink_username)));
end m5_change_db_link_pw;
>');
end;
/
--#4: Allow the package and DBAs to call the procedure.
grant execute on sys.m5_change_db_link_pw to method5, dba;
--#5: Create SYS procedure to return database hashes.
create or replace procedure sys.get_method5_hashes
--Purpose: Method5 administrators need access to the password hashes.
--But the table SYS.USER$ is hidden in 12c, we only want to expose this one hash.
--
--TODO 1: http://www.red-database-security.com/wp/best_of_oracle_security_2015.pdf
-- The 12c hash is incredibly insecure. Is it safe to remove the "H:" hash?
--TODO 2: Is there a way to derive the 10g hash from the 12c H: hash?
-- Without that, 12c local does not support remote 10g or 11g with case insensitive passwords.
(
p_12c_hash in out varchar2,
p_11g_hash_without_des in out varchar2,
p_11g_hash_with_des in out varchar2,
p_10g_hash in out varchar2
) is
begin
--10 and 11g.
$if dbms_db_version.ver_le_11_2 $then
select
spare4,
spare4 hash_without_des,
spare4||';'||password hash_with_des,
password
into p_12c_hash, p_11g_hash_without_des, p_11g_hash_with_des, p_10g_hash
from sys.user$
where name = 'METHOD5';
--12c.
$else
select
spare4,
regexp_substr(spare4, 'S:.{60}'),
regexp_substr(spare4, 'S:.{60}')||';'||password hash_with_des,
password
into p_12c_hash, p_11g_hash_without_des, p_11g_hash_with_des, p_10g_hash
from sys.user$
where name = 'METHOD5';
$end
end;
/
--#6: Allow the package and DBAs to call the procedure.
grant execute on sys.get_method5_hashes to method5, dba;
--#7: Create procedures that will protect important Method5 tables.
create or replace procedure sys.m5_protect_config_tables
/*
Purpose: Protect impotant Method5 configuration tables from changes.
Send an email when the table changes.
Raise an exception if the user is not a Method5 administrator.
*/
(
p_table_name varchar2
) is
v_sender_address varchar2(4000);
v_recipients varchar2(4000);
v_count number;
begin
--Get email configuration information.
execute immediate
q'[
select
min(email_address) sender_address
,listagg(email_address, ',') within group (order by email_address) recipients
from method5.m5_user
where is_m5_admin = 'Yes'
and email_address is not null
]'
into v_sender_address, v_recipients;
--Try to send an email if there is a configuration change.
begin
if v_sender_address is not null then
sys.utl_mail.send(
sender => v_sender_address,
recipients => v_recipients,
subject => 'METHOD5.'||p_table_name||' table was changed.',
message => 'The database user '||sys_context('userenv', 'session_user')||
' (OS user '||sys_context('userenv', 'os_user')||') made a change to the'||
' table METHOD5.'||p_table_name||'.'
);
end if;
--I hate to swallow exceptions but in this case it's more important to raise an exception
--about invalid privileges than about the email.
exception when others then null;
end;
--Check if the user is an admin.
execute immediate
q'[
select count(*) valid_user_count
from method5.m5_user
where is_m5_admin = 'Yes'
and trim(lower(oracle_username)) = lower(sys_context('userenv', 'session_user'))
and
(
lower(os_username) = lower(sys_context('userenv', 'os_user'))
or
os_username is null
)
]'
into v_count;
--Raise error if the user is not allowed.
if v_count = 0 then
raise_application_error(-20000, 'You do not have permission to modify the table '||p_table_name||'.'||chr(10)||
'Only Method5 administrators can modify that table.'||chr(10)||
'Contact your current administrator if you need access.');
end if;
end m5_protect_config_tables;
/
create or replace procedure sys.m5_create_triggers is
/*
Purpose: Create triggers to protect Method5 tables.
These triggers cannot be created ahead of time because the tables don't exist yet.
The triggers are added through this procedure so the installation doesn't have to
switch back and forth between SYS and DBA accounts.
*/
begin
for tables in
(
select 'M5_CONFIG' table_name from dual union all
select 'M5_DATABASE' table_name from dual union all
select 'M5_ROLE' table_name from dual union all
select 'M5_ROLE_PRIV' table_name from dual union all
select 'M5_USER' table_name from dual union all
select 'M5_USER_ROLE' table_name from dual
order by 1
) loop
execute immediate replace(q'[
create or replace trigger sys.#TABLE_NAME#_user_trg
before update or delete or insert on method5.#TABLE_NAME#
begin
sys.m5_protect_config_tables
(
p_table_name => '#TABLE_NAME#'
);
end;
]',
'#TABLE_NAME#', tables.table_name);
end loop;
end m5_create_triggers;
/
grant execute on sys.m5_create_triggers to dba;
prompt Done.