Home | History | Annotate | Download | only in common_files
      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