1
0
Files
irix-657m-src/eoe/cmd/chlabel/chlabel.c
2022-09-29 17:59:04 +03:00

390 lines
9.6 KiB
C

/*
* COPYRIGHT NOTICE
* Copyright 1990, Silicon Graphics, Inc. All Rights Reserved.
* This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
* the contents of this file may not be disclosed to third parties, copied or
* duplicated in any form, in whole or in part, without the prior written
* permission of Silicon Graphics, Inc.
*
* RESTRICTED RIGHTS LEGEND:
* Use, duplication or disclosure by the Government is subject to restrictions
* as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
* and Computer Software clause at DFARS 252.227-7013, and/or in similar or
* successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
* rights reserved under the Copyright Laws of the United States.
*
*/
#ident "$Revision: 1.9 $"
/*
*
* chlabel - change file label
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mac.h>
#include <sys/mac_label.h>
#include <sys/capability.h>
#include <errno.h>
#include <getopt.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <pwd.h>
#include <clearance.h>
static cap_value_t lstat_caps[] =
{
CAP_DAC_EXECUTE,
CAP_NOT_A_CID, /* really: CAP_DAC_READ_SEARCH */
CAP_NOT_A_CID, /* really: CAP_MAC_READ */
};
static cap_value_t caps_for_mac_set_file[] =
{
CAP_NOT_A_CID, /* really: CAP_DAC_READ_SEARCH */
CAP_NOT_A_CID, /* really: CAP_MAC_READ */
CAP_DAC_EXECUTE,
CAP_FOWNER,
CAP_MAC_DOWNGRADE,
CAP_MAC_UPGRADE,
CAP_MAC_WRITE,
CAP_DEVICE_MGT,
CAP_DAC_WRITE,
CAP_MAC_RELABEL_OPEN,
};
static cap_value_t caps_for_mac_set_proc[] =
{
CAP_MAC_MLD,
CAP_MAC_RELABEL_SUBJ,
};
static void
print_usage_and_die (char *program)
{
fprintf (stderr, "%s: usage:\n", program);
fprintf (stderr, "\t%s [-f] -m pathname\n", program);
fprintf (stderr, "\t%s [-f] label pathname ...\n", program);
exit (EXIT_FAILURE);
}
static int
cap_inheritable (cap_t pcap, cap_value_t cap)
{
cap_flag_value_t flag;
return (cap_get_flag (pcap, cap, CAP_INHERITABLE, &flag) == 0 &&
flag == CAP_SET);
}
static int
cap_permitted (cap_t pcap, cap_value_t cap)
{
cap_flag_value_t flag;
return (cap_get_flag (pcap, cap, CAP_PERMITTED, &flag) == 0 &&
flag == CAP_SET);
}
static mac_t pmac; /* current process label */
static mac_t pmold; /* current process label, moldy */
static void
free_pmac (void)
{
if (pmac);
mac_free (pmac);
if (pmold)
mac_free (pmold);
}
int
main (int argc, char *argv[])
{
mac_t file_mac; /* existing file label */
mac_t new_mac; /* new file label */
cap_t ocap; /* saved process capabilities */
char *program; /* Program name saved */
int c; /* For use by getopt(3) */
int force = 0; /* relabel even if open */
int mflag = 0; /* set moldy bit */
int lstat_ncap = 1;
int msf_ncap = 2;
/* find program name */
program = strrchr (argv[0], '/');
program = (program != NULL ? program + 1 : argv[0]);
/* only work if MAC is enabled */
if (sysconf (_SC_MAC) <= 0)
{
fprintf (stderr, "%s: MAC not enabled.\n", program);
return (EXIT_FAILURE);
}
/*
* get current process label and
* create moldy version of current process label and
* register label destroy function
*/
if ((pmac = mac_get_proc ()) == NULL ||
(pmold = mac_set_moldy (pmac)) == NULL ||
atexit (free_pmac))
{
fprintf (stderr, "%s: fatal error at %s(%d).\n",
program, __FILE__, __LINE__);
return (EXIT_FAILURE);
}
/* only work if CAP is enabled */
if (sysconf (_SC_CAP) <= 0)
{
fprintf (stderr, "%s: capabilities not enabled.\n", program);
return (EXIT_FAILURE);
}
/*
* Verify that the required capabilities are available.
* CAP_DAC_READ_SEARCH is required by sgi_getclearancebyname
* CAP_MAC_READ is required by sgi_getclearancebyname
* CAP_PRIV_PORT is required by sgi_getclearancebyname
*
* CAP_MAC_MLD is required by chlabel itself
* CAP_MAC_RELABEL_SUBJ is required by chlabel itself
*
* If CAP_DAC_READ_SEARCH or CAP_MAC_READ were inherited, then
* it's ok to acquire them. If not, then the
* invoking user isn't cleared for these capabilities,
* so we must not acquire them.
*/
if ((ocap = cap_get_proc ()) == NULL)
{
fprintf (stderr, "%s: fatal error at %s(%d).\n",
program, __FILE__, __LINE__);
return (EXIT_FAILURE);
}
if (!cap_permitted (ocap, CAP_DAC_READ_SEARCH) ||
!cap_permitted (ocap, CAP_MAC_READ) ||
!cap_permitted (ocap, CAP_PRIV_PORT) ||
!cap_permitted (ocap, CAP_MAC_MLD) ||
!cap_permitted (ocap, CAP_MAC_RELABEL_SUBJ) ||
!cap_permitted (ocap, CAP_DAC_WRITE))
{
cap_free (ocap);
fprintf (stderr, "%s: insufficient privilege\n",
program);
return (EXIT_FAILURE);
}
if (cap_inheritable (ocap, CAP_DAC_READ_SEARCH))
{
lstat_caps[lstat_ncap++] = CAP_DAC_READ_SEARCH;
caps_for_mac_set_file[--msf_ncap] = CAP_DAC_READ_SEARCH;
}
if (cap_inheritable (ocap, CAP_MAC_READ))
{
lstat_caps[lstat_ncap++] = CAP_MAC_READ;
caps_for_mac_set_file[--msf_ncap] = CAP_MAC_READ;
}
cap_free (ocap);
/* parse option arguments */
while ((c = getopt (argc, argv, "fm")) != -1)
{
switch (c)
{
case 'f':
force = 1;
break;
case 'm':
mflag = 1;
break;
default:
print_usage_and_die (program);
break;
}
}
/*
* Unless the -m flag was set the first parameter is the label.
*/
if (!mflag)
{
struct clearance *clp; /* user clearance information */
struct passwd *pw; /* user name information */
if (optind >= argc)
print_usage_and_die (program);
/* convert human-readable label to internal form */
if ((new_mac = mac_from_text (argv[optind])) == NULL)
{
fprintf (stderr, "%s: invalid label: \"%s\"\n",
program, argv[optind]);
return (EXIT_FAILURE);
}
/* get /etc/passwd info */
if ((pw = getpwuid (getuid ())) == NULL)
{
fprintf (stderr, "%s cannot find user's name.\n",
program);
return (EXIT_FAILURE);
}
/* get the user's label clearance range */
if ((clp = sgi_getclearancebyname (pw->pw_name)) == NULL)
{
fprintf (stderr, "%s cannot find user %s's clearance.\n",
program, pw->pw_name);
return (EXIT_FAILURE);
}
/* check the label against the user's clearance range */
if ((c = mac_cleared_fl (clp, new_mac)) != MAC_CLEARED)
{
mac_free (new_mac);
fprintf (stderr, "%s: denied because %s.\n",
program, mac_clearance_error (c));
return (EXIT_FAILURE);
}
optind++;
}
/*
* There needs to be at least one path.
* If -m is given, there can be only one path.
*/
if (optind >= argc || (mflag && (optind + 1) != argc))
print_usage_and_die (program);
/*
* Do everything with a moldy label. The case this has trouble
* with is:
* chlabel A/B
* where A is a moldy directory. The argument is that one
* oughtn't be changing the label on a file in a moldy directory
* without first moving it to where it belongs.
*/
for (; optind < argc; optind++)
{
struct stat plain_st; /* attribute of file, normal label */
struct stat moldy_st; /* attribute of file, moldy label */
c = 0;
/* give ourselves a moldy label */
ocap = cap_acquire (2, caps_for_mac_set_proc);
if (mac_set_proc (pmold) == -1)
{
cap_surrender (ocap);
fprintf (stderr, "%s: fatal error at %s(%d).\n",
program, __FILE__, __LINE__);
return (EXIT_FAILURE);
}
cap_surrender (ocap);
/* get moldy file attributes */
ocap = cap_acquire (lstat_ncap, lstat_caps);
c += (lstat (argv[optind], &moldy_st) == -1) ? 1 : 0;
cap_surrender (ocap);
/* go back to our normal label */
ocap = cap_acquire (2, caps_for_mac_set_proc);
if (mac_set_proc (pmac) == -1)
{
cap_surrender (ocap);
fprintf (stderr, "%s: fatal error at %s(%d).\n",
program, __FILE__, __LINE__);
return (EXIT_FAILURE);
}
cap_surrender (ocap);
/* get non-moldy file attributes */
ocap = cap_acquire (lstat_ncap, lstat_caps);
c += (lstat (argv[optind], &plain_st) == -1) ? 1 : 0;
file_mac = mac_get_file (argv[optind]);
cap_surrender (ocap);
/* go to next file on error */
if (file_mac == NULL || c)
{
perror (argv[optind]);
mac_free (file_mac);
continue;
}
/*
* Verify that using a moldy label doesn't result
* in changing the wrong file's label. In other words,
* avoid changing the label of a file through a path
* which does moldy redirection.
*/
if (plain_st.st_ino != moldy_st.st_ino ||
plain_st.st_dev != moldy_st.st_dev)
{
fprintf (stderr, "%s: %s, %s.\n",
program, argv[optind],
"Multilevel directory redirection confusion.");
mac_free (file_mac);
continue;
}
/* create moldy new_mac as appropriate */
if (mflag)
new_mac = mac_set_moldy (file_mac);
/*
* Only directories can be moldy.
*/
if (!S_ISDIR (plain_st.st_mode) && mac_is_moldy (new_mac))
{
fprintf (stderr,
"%s: Only directories can be moldy.\n",
argv[optind]);
mac_free (file_mac);
if (mflag)
mac_free (new_mac);
continue;
}
/*
* Shortcut out if the old and new labels are the same.
* Moldy and normal labels compare the same with
* mac_equal(), so we must also check the label types
* here e.g. it should be possible to set a
* msenlow/minthigh file to msenmldlow/minthigh.
*/
if (new_mac->ml_msen_type == file_mac->ml_msen_type &&
new_mac->ml_mint_type == file_mac->ml_mint_type &&
mac_equal (new_mac, file_mac))
{
mac_free (file_mac);
if (mflag)
mac_free (new_mac);
continue;
}
/*
* Do the deed, if at all possible.
*/
ocap = cap_acquire (9 - msf_ncap + (force ? 1 : 0),
&caps_for_mac_set_file[msf_ncap]);
if (mac_set_file (argv[optind], new_mac) == -1)
perror (argv[optind]);
cap_surrender (ocap);
mac_free (file_mac);
if (mflag)
mac_free (new_mac);
}
if (!mflag)
mac_free (new_mac);
return (EXIT_SUCCESS);
}