1 /****^  ******************************************************
  2         *                                                    *
  3         * Copyright, (C) Honeywell Bull Inc., 1987           *
  4         *                                                    *
  5         * Copyright (c) 1987 by Massachusetts Institute of   *
  6         * Technology and Honeywell Information Systems, Inc. *
  7         *                                                    *
  8         * Copyright (c) 1972 by Massachusetts Institute of   *
  9         * Technology and Honeywell Information Systems, Inc. *
 10         *                                                    *
 11         ****************************************************** */
 12 
 13 /* format: style2,indcomtxt */
 14 set_privileges:
 15      procedure;
 16 
 17 /* Modified 1985-03-04, EJ Sharpe: remove special_op event flags and auditing for ring-1 TCB calls */
 18 /* Modified 1985-01-21, BIM: ring 1 (admin) privilege manipulation. */
 19 /* Modified 84-12-05 by EJ Sharpe to use access_audit_ instead of protection_audit_ */
 20 /* Modified 84-11 BIM, changed to set all privs in apte */
 21 /* Modified May 1983 by E. N. Kittlitz to add communication privilege */
 22 /* Modified 760309 by L.Scheffler to fix excessive auditing calls */
 23 /* Modified by E. Stone on Sept 1975 to change kst when setting directory privileges */
 24 /* Coded 16 Oct. 1974 by D. H. Hunt */
 25 
 26 /* This ring 0 procedure is expected to be invoked only by the */
 27 /* system security administrator and by certain SysDaemon processes */
 28 /* which need to bypass the access isolation mechanism (AIM) checks */
 29 
 30 /* A process grants itself a particular privilege to bypass AIM checks */
 31 /* by calling one of the "---priv_on" entry points.  This sets the */
 32 /* corresponding privilege bit on (="1"b) */
 33 
 34 /* A process rescinds a particular privilege for bypassing AIM checks */
 35 /* by calling one of the "---priv_off" entry points.  This sets the */
 36 /* corresponding privilege bit off (="0"b) */
 37 
 38 
 39           declare access_audit_$log_general
 40                                          entry external options (variable);
 41           declare access_operations_$system_privilege_modify
 42                                          bit (36) aligned external;
 43           declare 1 pds$access_authorization
 44                                          aligned like aim_template external;
 45           declare pds$admin_privileges   bit (36) aligned external;
 46           declare pds$apt_ptr            pointer external;
 47           declare 1 event_flags          aligned like audit_event_flags;
 48           declare level$get              entry returns (fixed bin (3));
 49           declare ring_alarm$reset       entry;
 50           declare setfaults$disconnect   entry (fixed bin);
 51           declare ME                     char (14) aligned internal static initial ("set_privileges") options (constant);
 52           declare P_code                 fixed bin (35) parameter;
 53           declare P_set_privs            bit (36) aligned parameter;
 54           declare P_old_privs            bit (36) aligned parameter;
 55 
 56           declare changed                bit (1) aligned;
 57           declare set_privs              bit (36) aligned;
 58           declare old_privs              bit (36) aligned;
 59 
 60           declare (addr, bit, bool, hbound, length, null, rtrim, string, substr)
 61                                          builtin;
 62 %page;
 63 
 64 admin_set:
 65      entry (P_set_privs, P_old_privs);
 66 
 67           set_privs = P_set_privs;
 68           call set_admin_privileges (set_privs, old_privs); /* fixes the KST */
 69           P_old_privs = old_privs;
 70           return;
 71 
 72 admin_reset:
 73      entry (P_set_privs);
 74 
 75           set_privs = P_set_privs;
 76           call reset_admin_privileges (set_privs);          /* fixes the KST */
 77           P_set_privs = set_privs;
 78           return;
 79 
 80 
 81 admin_ring_alarm:                                           /* Called on a ring alarm to get rid of these */
 82      entry;
 83 
 84           set_privs = bit (string (pds$access_authorization.privileges), 36) & ^pds$admin_privileges;
 85                                                             /* construct appropriate priv set */
 86           substr (set_privs, 36, 1) = "1"b;                 /* Give it something to do */
 87           call reset_admin_privileges (set_privs);
 88           pds$admin_privileges = ""b;                       /* double sure */
 89           return;
 90 %page;
 91 
 92 /* In managing its log buffers, syserr may send a wakeup to the initializer */
 93 /* process.  Everything will work OK, since if the wakeup is sent from the */
 94 /* initializer to itself, the wakeup will be allowed regardless of the state */
 95 /* of the IPC privilege bits.  If another process sends the wakeup to the */
 96 /* initializer, it will be allowed since the initializer will have IPC privilege */
 97 /* on before other processes are allowed to log in. */
 98 
 99 ipc_priv_on:                                                /* disables the AIM check for interprocess communication */
100      entry (P_code);
101 
102           call set_one_privilege (IPC_PRIVILEGE_X, IPC_PRIVILEGE, changed);
103 
104           if changed
105           then P_code = 0;
106           else P_code = 1;
107           return;
108 
109 
110 ipc_priv_off:                                               /* enables the AIM check for interprocess communication */
111      entry (P_code);
112 
113           call clear_one_privilege (IPC_PRIVILEGE_X, ^IPC_PRIVILEGE, changed);
114 
115           if changed
116           then P_code = 0;
117           else P_code = 1;
118           return;
119 
120 dir_priv_on:                                                /* disables the AIM checks for directories */
121      entry (P_code);
122 
123           call set_one_privilege (DIR_PRIVILEGE_X, DIR_PRIVILEGE, changed);
124           if changed
125           then do;
126                     call fix_kst;                           /* cause access to directories to be recalculated */
127                     P_code = 0;
128                end;
129           else P_code = 1;
130           return;
131 
132 dir_priv_off:                                               /* enables the AIM checks for directories */
133      entry (P_code);
134 
135           call clear_one_privilege (DIR_PRIVILEGE_X, ^DIR_PRIVILEGE, changed);
136 
137           if changed
138           then do;
139                     call fix_kst;                           /* cause access to directories to be recalculated */
140                     P_code = 0;
141                end;
142           else P_code = 1;
143           return;
144 
145 seg_priv_on:                                                /* disables the AIM checks for segments */
146      entry (P_code);
147 
148           call set_one_privilege (SEG_PRIVILEGE_X, SEG_PRIVILEGE, changed);
149 
150           if changed
151           then do;
152                     P_code = 0;
153                     call fix_kst_seg;
154                end;
155           else P_code = 1;
156           return;
157 
158 seg_priv_off:                                               /* enables the AIM checks for segments */
159      entry (P_code);
160 
161           call clear_one_privilege (SEG_PRIVILEGE_X, ^SEG_PRIVILEGE, changed);
162           if changed
163           then do;
164                     P_code = 0;
165                     call fix_kst_seg;
166                end;
167           else P_code = 1;
168 
169           return;
170 
171 soos_priv_on:                                               /* prevents access to directories which have the */
172      entry (P_code);                                        /* security out of service attribute turned on */
173 
174           call set_one_privilege (SOOS_PRIVILEGE_X, SOOS_PRIVILEGE, changed);
175           if changed
176           then P_code = 0;
177           else P_code = 1;
178           return;
179 
180 soos_priv_off:                                              /* allows access to directories which have the */
181      entry (P_code);                                        /* security out of service attribute turned on */
182           call clear_one_privilege (SOOS_PRIVILEGE_X, ^SOOS_PRIVILEGE, changed);
183 
184           if changed
185           then P_code = 0;
186           else P_code = 1;
187           return;
188 
189 ring1_priv_on:                                              /* disables the interpretive AIM */
190      entry (P_code);                                        /* checks in ring one */
191           call set_one_privilege (RING1_PRIVILEGE_X, RING1_PRIVILEGE, changed);
192           if changed
193           then P_code = 0;
194           else P_code = 1;
195           return;
196 
197 ring1_priv_off:                                             /* enables the interpretive AIM */
198      entry (P_code);                                        /* checks in ring one */
199 
200           call clear_one_privilege (RING1_PRIVILEGE_X, ^RING1_PRIVILEGE, changed);
201           if changed
202           then P_code = 0;
203           else P_code = 1;
204           return;
205 
206 rcp_priv_on:                                                /* disables the interpretive AIM */
207      entry (P_code);                                        /* checks in RCP */
208 
209           call set_one_privilege (RCP_PRIVILEGE_X, RCP_PRIVILEGE, changed);
210           if changed
211           then P_code = 0;
212           else P_code = 1;
213           return;
214 
215 rcp_priv_off:                                               /* enables the interpretive AIM */
216      entry (P_code);                                        /* checks in RCP */
217           call clear_one_privilege (RCP_PRIVILEGE_X, ^RCP_PRIVILEGE, changed);
218           if changed
219           then P_code = 0;
220           else P_code = 1;
221           return;
222 
223 comm_priv_on:                                               /* disables the interpretive AIM */
224      entry (P_code);                                        /* checks in TCP and dial_ctl_ */
225 
226           call set_one_privilege (COMM_PRIVILEGE_X, COMM_PRIVILEGE, changed);
227           if changed
228           then P_code = 0;
229           else P_code = 1;
230           return;
231 
232 comm_priv_off:                                              /* enables the interpretive AIM */
233      entry (P_code);                                        /* checks in comm */
234           call clear_one_privilege (COMM_PRIVILEGE_X, ^COMM_PRIVILEGE, changed);
235           if changed
236           then P_code = 0;
237           else P_code = 1;
238           return;
239 %page;
240 
241 fix_kst:
242      procedure;
243 
244           dcl     segno                  fixed bin;
245           dcl     seg_flag               bit (1) aligned;
246           dcl     faulted_one            bit (1) aligned;
247 
248           seg_flag = "0"b;
249           go to COMMON;
250 
251 fix_kst_seg:
252      entry;
253 
254           seg_flag = "1"b;
255 
256 COMMON:
257           kstp = pds$kstp;                                  /* get pointer to kst  */
258           faulted_one = "0"b;
259           do segno = kstp -> kst.lowseg to kstp -> kst.highest_used_segno;
260                                                             /* whip thru kst looking for dirs */
261                kstep = addr (kstp -> kst.kst_entry (segno));
262                if kste.uid ^= ""b
263                then if (kste.dirsw & ^seg_flag) | (^kste.dirsw & ^kste.priv_init & seg_flag)
264                     then do;
265                               kstep -> kste.dtbm = (36)"1"b;/* set dtbm so that access will be recalculated as needed */
266                               if seg_flag
267                               then call setfaults$disconnect (segno);
268                          end;
269 
270           end;
271 
272      end fix_kst;
273 %page;
274 
275 set_one_privilege:
276      procedure (privilege_index, privilege_mask, changed);
277 
278           declare changed                bit (1) aligned;
279           declare privilege_index        fixed bin;
280           declare privilege_mask         bit (36) aligned;
281           declare new_privs              bit (18) aligned;
282           declare old_privs              bit (18) aligned;
283           declare apte_auth_ptr          pointer;
284           declare 1 apte_auth            aligned like aim_template based (apte_auth_ptr);
285           declare turn_on                bit (1) aligned;
286 
287           turn_on = "1"b;
288           go to COMMON;
289 
290 clear_one_privilege:
291      entry (privilege_index, privilege_mask, changed);
292 
293           turn_on = "0"b;
294 
295 COMMON:
296           changed = "0"b;
297           old_privs = string (pds$access_authorization.privileges);
298                                                             /* starts same as old */
299           if turn_on
300           then new_privs = old_privs | privilege_mask;
301           else new_privs = old_privs & privilege_mask;      /* caller ^'s to get ^'ed form in as text constant */
302 
303           if new_privs = old_privs
304           then return;                                      /* with changed = "0"b */
305 
306           changed = "1"b;
307           apte_auth_ptr = addr (pds$apt_ptr -> apte.access_authorization);
308           string (apte_auth.privileges), string (pds$access_authorization.privileges) = new_privs;
309           string (event_flags) = ""b;
310           event_flags.grant = "1"b;
311           event_flags.priv_op = "1"b;
312           call access_audit_$log_general (ME, level$get (), string (event_flags),
313                access_operations_$system_privilege_modify, "", 0, null (), 0, "^a turned ^[on^;off^]",
314                system_privilege_names (privilege_index).long, turn_on);
315           return;
316 
317      end set_one_privilege;
318 
319 set_admin_privileges:
320      procedure (new_privileges, old_privileges);
321 
322           declare (new_privileges, old_privileges)
323                                          bit (36) aligned;
324           declare apte_auth_ptr          pointer;
325           declare 1 apte_auth            aligned like aim_template based (apte_auth_ptr);
326           declare priv_value             bit (18);
327           declare name_string            char (100) varying;
328           declare x                      fixed bin;
329           declare privs_before_set       bit (18) aligned;
330           declare different_privs_mask   bit (18) aligned;
331 
332           old_privileges = string (pds$access_authorization.privileges);
333           substr (old_privileges, 36, 1) = "1"b;            /* Mark the setting */
334           priv_value = substr (old_privileges, 1, 18) | substr (new_privileges, 1, 18);
335                                                             /* Turn on the new ones */
336           name_string = "";
337           do x = 1 to hbound (system_privilege_names, 1);
338                if substr (new_privileges, x, 1)
339                then do;
340                          if length (name_string) > 0
341                          then name_string = name_string || ",";
342                          name_string = name_string || rtrim (system_privilege_names.short (x));
343                     end;
344           end;
345 
346           apte_auth_ptr = addr (pds$apt_ptr -> apte.access_authorization);
347           privs_before_set = string (pds$access_authorization.privileges);
348 
349           different_privs_mask = bool (privs_before_set, new_privileges, "0110"b);
350                                                             /* XOR */
351           pds$admin_privileges = pds$admin_privileges | (new_privileges & different_privs_mask);
352                                                             /* mark */
353           call ring_alarm$reset;
354 
355           string (apte_auth.privileges), string (pds$access_authorization.privileges) = priv_value;
356 
357           if ((priv_value & DIR_PRIVILEGE) ^= ""b) /* We only turn ON here */ & ((privs_before_set & DIR_PRIVILEGE) = ""b)
358           then call fix_kst;
359           if ((priv_value & SEG_PRIVILEGE) ^= ""b) & ((privs_before_set & SEG_PRIVILEGE) = ""b)
360           then call fix_kst_seg;
361 
362 /**** The following code would usually audit the event.  However, setting
363       /****  privileges temporarily is a normal function of the ring-1 TCB.
364       /****  Therefore, we elect to avoid many unnecessary audit messages.
365       /****  Besides, there's no associated object or event flag on which to decide
366       /****  upon auditing.
367       /****         string (event_flags) = ""b;
368       /****         event_flags.grant = "1"b;
369       /****         event_flags.WHAT? = "1"b;     HAVE to have an event flag here - admin_op is NOT the correct one
370       /****         call access_audit_$log_general (ME, level$get (), string (event_flags),
371       /****              access_operations_$system_privilege_modify, "", 0, null (), 0, "^a turned on", name_string);
372       / ****/
373           return;
374 
375 
376 reset_admin_privileges:
377      entry (old_privileges);
378 
379           if ^substr (old_privileges, 36, 1)
380           then return;                                      /* Not anything to reset. */
381 
382           substr (old_privileges, 36, 1) = "0"b;
383           privs_before_set = string (pds$access_authorization.privileges);
384           priv_value = substr (old_privileges, 1, 18);
385 
386           apte_auth_ptr = addr (pds$apt_ptr -> apte.access_authorization);
387 
388           different_privs_mask = bool (privs_before_set, old_privileges, "0110"b);
389                                                             /* XOR */
390           pds$admin_privileges = pds$admin_privileges & ^(^old_privileges & different_privs_mask);
391                                                             /* Zero out privs zero'd out by the reset */
392 
393           string (apte_auth.privileges), string (pds$access_authorization.privileges) = priv_value;
394           call ring_alarm$reset;
395 
396           if (priv_value & DIR_PRIVILEGE) ^= (privs_before_set & DIR_PRIVILEGE)
397           then call fix_kst;
398           if (priv_value & SEG_PRIVILEGE) ^= (privs_before_set & SEG_PRIVILEGE)
399           then call fix_kst_seg;
400 
401           name_string = "";
402           do x = 1 to hbound (system_privilege_names, 1);
403                if substr (privs_before_set, x, 1) ^= substr (priv_value, x, 1)
404                then do;
405                          if length (name_string) > 0
406                          then name_string = name_string || ",";
407                          name_string = name_string || rtrim (system_privilege_names (x).short);
408                          if substr (priv_value, x, 1)
409                          then name_string = name_string || "(set)";
410                          else name_string = name_string || "(reset)";
411                     end;
412           end;
413 
414 
415 /**** The following code would usually audit the event.  However, setting
416       /****  privileges temporarily is a normal function of the ring-1 TCB.
417       /****  Therefore, we elect to avoid many unnecessary audit messages.
418       /****  Besides, there's no associated object or event flag on which to decide
419       /****  upon auditing.
420       /****         string (event_flags) = ""b;
421       /****         event_flags.grant = "1"b;
422       /****         event_flags.WHAT? = "1"b;     HAVE to have an event flag here - admin_op is NOT the correct one
423       /****         call access_audit_$log_general (ME, level$get (), string (event_flags),
424       /****              access_operations_$system_privilege_modify, "", 0, null (), 0, "change: ^a", name_string);
425       / ****/
426           return;
427 
428      end set_admin_privileges;
429 
430 /* format: off */
431 %page; %include aim_privileges;
432 %page; %include aim_template;
433 %page; %include apte;
434 %page; %include kst;
435 %page; %include system_privileges;
436 %page; %include access_audit_eventflags;
437 /* format: on */
438 %page;
439 /* BEGIN MESSAGE DOCUMENTATION
440 
441 
442    Message:
443    AUDIT (set_privileges): GRANTED modification of system AIM privilege ADDED_INFO
444 
445    S:     $access_audit
446 
447    T:     $run
448 
449    M:     The specified user made a privileged call for modifying the
450    process AIM privileges
451 
452    A:     $ignore
453 
454 
455    END MESSAGE DOCUMENTATION */
456 
457      end set_privileges;