1 #!/bin/sh 2 # 3 # CDDL HEADER START 4 # 5 # The contents of this file are subject to the terms of the 6 # Common Development and Distribution License (the "License"). 7 # You may not use this file except in compliance with the License. 8 # 9 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 # or http://www.opensolaris.org/os/licensing. 11 # See the License for the specific language governing permissions 12 # and limitations under the License. 13 # 14 # When distributing Covered Code, include this CDDL HEADER in each 15 # file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 # If applicable, add the following below this CDDL HEADER, with the 17 # fields enclosed by brackets "[]" replaced with your own identifying 18 # information: Portions Copyright [yyyy] [name of copyright owner] 19 # 20 # CDDL HEADER END 21 # 22 # 23 #ident "%Z%%M% %I% %E% SMI" 24 # 25 # i.rbac 26 # 27 # Copyright 2008 Sun Microsystems, Inc. All rights reserved. 28 # Use is subject to license terms. 29 # 30 # class action script for "rbac" class files 31 # installed by pkgadd 32 # 33 # Files in "rbac" class: 34 # 35 # /etc/security{prof_attr,exec_attr,auth_attr} 36 # /etc/user_attr 37 # 38 # Allowable exit codes 39 # 40 # 0 - success 41 # 2 - warning or possible error condition. Installation continues. A warning 42 # message is displayed at the time of completion. 43 # 44 45 tmp_dir=${TMPDIR:-/tmp} 46 47 PATH="/usr/bin:/usr/sbin:${PATH}" 48 export PATH 49 50 basename_cmd=basename 51 cp_cmd=cp 52 egrep_cmd=egrep 53 mv_cmd=mv 54 nawk_cmd=nawk 55 rm_cmd=rm 56 sed_cmd=sed 57 sort_cmd=sort 58 59 # $1 is the type 60 # $2 is the "old/existing file" 61 # $3 is the "new (to be merged)" file 62 # $4 is the output file 63 # returns 0 on success 64 # returns 2 on failure if nawk fails with non-zero exit status 65 # 66 dbmerge() { 67 # 68 # If the new file has a Sun copyright, remove the Sun copyright from the old 69 # file. 70 # 71 newcr=`${egrep_cmd} '^# Copyright.*Sun Microsystems, Inc.' $3 \ 72 2>/dev/null` 73 if [ -n "${newcr}" ]; then 74 $sed_cmd -e '/^# Copyright.*Sun Microsystems, Inc./d' \ 75 -e '/^# All rights reserved./d' \ 76 -e '/^# Use is subject to license terms./d' \ 77 $2 > $4.old 78 else 79 $cp_cmd $2 $4.old 80 fi 81 # 82 # If the new file has the CDDL, remove it from the old file. 83 # 84 newcr=`${egrep_cmd} '^# CDDL HEADER START' $3 2>/dev/null` 85 if [ -n "${newcr}" ]; then 86 $sed_cmd -e '/^# CDDL HEADER START/,/^# CDDL HEADER END/d' \ 87 $4.old > $4.$$ 2>/dev/null 88 $mv_cmd $4.$$ $4.old 89 fi 90 # 91 # Remove empty lines and multiple instances of these comments: 92 # 93 $sed_cmd -e '/^# \/etc\/security\/exec_attr/d' -e '/^#$/d' \ 94 -e '/^# execution attributes for profiles./d' \ 95 -e '/^# See exec_attr(4)/d' \ 96 -e '/^# \/etc\/user_attr/d' \ 97 -e '/^# user attributes. see user_attr(4)/d' \ 98 -e '/^# \/etc\/security\/prof_attr/d' \ 99 -e '/^# profiles attributes. see prof_attr(4)/d' \ 100 -e '/^# See prof_attr(4)/d' \ 101 -e '/^# \/etc\/security\/auth_attr/d' \ 102 -e '/^# authorizations. see auth_attr(4)/d' \ 103 -e '/^# authorization attributes. see auth_attr(4)/d' \ 104 $4.old > $4.$$ 105 $mv_cmd $4.$$ $4.old 106 # 107 # Retain old and new header comments. 108 # 109 $sed_cmd -n -e '/^[^#]/,$d' -e '/^##/,$d' -e p $4.old > $4 110 $rm_cmd $4.old 111 $sed_cmd -n -e '/^[^#]/,$d' -e '/^##/,$d' -e p $3 >> $4 112 # 113 # Handle line continuations (trailing \) 114 # 115 $sed_cmd \ 116 -e '/\\$/{N;s/\\\n//;}' -e '/\\$/{N;s/\\\n//;}' \ 117 -e '/\\$/{N;s/\\\n//;}' -e '/\\$/{N;s/\\\n//;}' \ 118 -e '/\\$/{N;s/\\\n//;}' -e '/\\$/{N;s/\\\n//;}' \ 119 $2 > $4.old 120 $sed_cmd \ 121 -e '/\\$/{N;s/\\\n//;}' -e '/\\$/{N;s/\\\n//;}' \ 122 -e '/\\$/{N;s/\\\n//;}' -e '/\\$/{N;s/\\\n//;}' \ 123 -e '/\\$/{N;s/\\\n//;}' -e '/\\$/{N;s/\\\n//;}' \ 124 $3 > $4.new 125 # 126 #!/usr/bin/nawk -f 127 # 128 # dbmerge type=[auth|prof|user|exec] old-file new-file 129 # 130 # Merge two versions of an RBAC database file. The output 131 # consists of the lines from the new-file, while preserving 132 # user customizations in the old-file. Specifically, the 133 # keyword/value section of each record contains the union 134 # of the entries found in both files. The value for each 135 # keyword is the value from the new-file, except for three 136 # keywords ("auths", "profiles", "roles") where the values 137 # from the old and new files are merged. 138 # 139 # The output is run through sort except for the comments 140 # which will appear first in the output. 141 # 142 # 143 $nawk_cmd ' 144 145 BEGIN { 146 FS=":" 147 } 148 149 /^#/ || /^$/ { 150 continue; 151 } 152 153 type == "auth" { 154 key = $1 ":" $2 ":" $3 ; 155 if (NR == FNR) { 156 short_comment[key] = $4 ; 157 long_comment[key] = $5; 158 record[key] = $6; 159 } 160 else { 161 if ( $4 != "" ) { 162 short_comment[key] = $4 ; 163 } 164 if ( $5 != "" ) { 165 long_comment[key] = $5 ; 166 } 167 print key ":" short_comment[key] ":" long_comment[key] ":" \ 168 merge_attrs(record[key], $6); 169 delete record[key]; 170 } 171 } 172 173 type == "prof" { 174 key = $1 ":" $2 ":" $3 ; 175 if (NR == FNR) { 176 comment[key] = $4; 177 record[key] = $5; 178 } 179 else { 180 if ( $4 != "" ) { 181 comment[key] = $4 ; 182 } 183 if (key != "::") { 184 print key ":" comment[key] ":" \ 185 merge_attrs(record[key], $5); 186 } 187 delete record[key]; 188 } 189 } 190 191 type == "exec" { 192 key = $1 ":" $2 ":" $3 ":" $4 ":" $5 ":" $6 ; 193 # Substitute new entries, do not merge. 194 record[key] = $7; 195 } 196 197 type == "user" { 198 key = $1 ":" $2 ":" $3 ":" $4 ; 199 if (NR == FNR) 200 record[key] = $5; 201 else { 202 print key ":" merge_attrs(record[key], $5); 203 delete record[key]; 204 } 205 } 206 207 END { 208 for (key in record) { 209 if (type == "prof") { 210 if (key != "::") { 211 print key ":" comment[key] ":" record[key]; 212 } 213 } else 214 if (type == "auth") { 215 print key ":" short_comment[key] ":" \ 216 long_comment[key] ":" record[key]; 217 } else 218 print key ":" record[key]; 219 } 220 } 221 222 function merge_attrs(old, new, cnt, new_cnt, i, j, list, new_list, keyword) 223 { 224 cnt = split(old, list, ";"); 225 new_cnt = split(new, new_list, ";"); 226 for (i = 1; i <= new_cnt; i++) { 227 keyword = substr(new_list[i], 1, index(new_list[i], "=")-1); 228 for (j = 1; j <= cnt; j++) { 229 if (match(list[j], "^" keyword "=")) { 230 list[j] = merge_values(keyword, list[j], 231 new_list[i]); 232 break; 233 } 234 } 235 if (j > cnt) 236 list[++cnt] = new_list[i]; 237 } 238 239 return unsplit(list, cnt, ";"); \ 240 } 241 242 function merge_values(keyword, old, new, cnt, new_cnt, i, j, list, new_list, d) 243 { 244 if (keyword != "auths" && keyword != "profiles") 245 return new; 246 247 cnt = split(substr(old, length(keyword)+2), list, ","); 248 new_cnt = split(substr(new, length(keyword)+2), new_list, ","); 249 250 # If the existing list contains "All", remove it and add it 251 # to the new list; that way "All" will appear at the only valid 252 # location, the end of the list. 253 if (keyword == "profiles") { 254 d = 0; 255 for (i = 1; i <= cnt; i++) { 256 if (list[i] != "All") 257 list[++d] = list[i]; 258 } 259 if (cnt != d) { 260 new_list[++new_cnt] = "All"; 261 cnt = d; 262 } 263 } 264 for (i = 1; i <= new_cnt; i++) { 265 for (j = 1; j <= cnt; j++) { 266 if (list[j] == new_list[i]) 267 break; 268 } 269 if (j > cnt) 270 list[++cnt] = new_list[i]; 271 } 272 273 return keyword "=" unsplit(list, cnt, ","); 274 } 275 276 function unsplit(list, cnt, delim, str) 277 { 278 str = list[1]; 279 for (i = 2; i <= cnt; i++) 280 str = str delim list[i]; 281 return str; 282 }' \ 283 type=$1 $4.old $4.new > $4.unsorted 284 rc=$? 285 $sort_cmd < $4.unsorted >> $4 286 return $rc 287 } 288 289 # $1 is the merged file 290 # $2 is the target file 291 # 292 commit() { 293 $mv_cmd $1 $2 294 return $? 295 } 296 297 outfile="" 298 type="" 299 set_type_and_outfile() { 300 # 301 # Assumes basename $1 returns one of 302 # prof_attr, exec_attr, auth_attr, or user_attr 303 # 304 fname=`$basename_cmd $1` 305 type=`echo $fname | $sed_cmd -e s'/^\([a-z][a-z]*\)_attr$/\1/' ` 306 case "$type" in 307 "prof"|"exec"|"user"|"auth") ;; 308 *) return 2 ;; 309 esac 310 311 outfile=$tmp_dir/rbac_${PKGINST}_${fname}_merge.$$ 312 313 return 0 314 } 315 316 cleanup() { 317 $rm_cmd -f $outfile $outfile.old $outfile.new $outfile.unsorted 318 319 return 0 320 } 321 322 exit_status=0 323 324 # main 325 326 while read newfile oldfile ; do 327 if [ ! -f $oldfile ]; then 328 cp $newfile $oldfile 329 else 330 set_type_and_outfile $newfile 331 if [ $? -ne 0 ]; then 332 echo "$0 : $newfile not one of" \ 333 " prof_attr, exec_attr, auth_attr, user_attr" 334 exit_status=2 335 continue 336 fi 337 338 dbmerge $type $oldfile $newfile $outfile 339 if [ $? -ne 0 ]; then 340 echo "$0 : failed to merge $newfile with $oldfile" 341 cleanup 342 exit_status=2 343 continue 344 fi 345 346 commit $outfile $oldfile 347 if [ $? -ne 0 ]; then 348 echo "$0 : failed to mv $outfile to $2" 349 cleanup 350 exit_status=2 351 continue 352 fi 353 354 cleanup 355 fi 356 done 357 358 if [ "$1" = "ENDOFCLASS" ]; then 359 exit 0 360 fi 361 362 exit $exit_status 363