Using trusted facilities

subsys.c example

The subsys.c program is similar to auths(C), but it lists a user's subsystem authorizations rather than kernel authorizations. The subsys command takes one argument, a user name. If no name is specified, subsys works on the effective user ID. It prints out the name of the account, the real name of the person assigned to the account, and the subsystem authorizations (both primary and secondary) for that account. This program can be run only by the owner of the account or the accounts administrator (in other words, a user with the auth subsystem authorization).

This program demonstrates how to:

Any program that queries the Protected Password database must be executed with the effective group ID (EUID) of auth. To install this program, make the binary setgid auth. For example, use the following commands:

chgrp auth subsys
chmod 2111 subsys

To compile this program, use the following command:

cc subsys.c -lprot -lx -o subsys

subsys.c (Part 1/2)

  1 #define SecureWare			/* enable security features		*/

2 #include <sys/types.h> /* system pseudo-types */ 3 #include <stdio.h> /* standard I/O definitions */ 4 #include <pwd.h> /* /etc/passwd definitions */ 5 #include <string.h> /* string library definitions */ 6 #include <sys/security.h> /* various security definitions */ 7 #include <sys/audit.h> /* audit definitions */ 8 #include <prot.h> /* database definitions */

9 main( 10 int argc, 11 char *argv[] 12 ) { 13 struct pr_passwd *pr; /* Protected Password entry */ 14 struct passwd *pwd; /* /etc/passwd entry */ 15 mask_t *pmask; /* subsys authorization vector */ 16 char *str; 17 int n, num; 18 int printed;

19 set_auth_parameters(argc, argv);

20 if (argc >= 2) 21 pwd = getpwnam(argv[1]); 22 else 23 pwd = getpwuid(starting_euid()); 24 if (pwd == (struct passwd *)0) { 25 (void) fprintf(stderr, "%s: No such user.\n", command_name); 26 exit(2); 27 /* NOTREACHED */ 28 }

29 if (pwd->pw_uid != starting_luid() && ! authorized_user("auth")) { 30 (void) fprintf(stderr, "%s: Not authorized.\n", command_name); 31 exit(3); 32 /* NOTREACHED */ 33 }

line 1
SecureWare must be defined in programs that use the trusted software. If it is not defined on the compile line, the #define SecureWare statement is required. This allows the security-related definitions in the header files to be interpreted correctly.

line 4
pwd.h defines the passwd structure. Trusted software uses this information to identify the user, as in line 24. This file must be included to use such routines as getpwnam(S) (line 21) and getpwuid(S) (line 23).

line 5
string.h is required for the strchr(S) call in line 35. The manual page for each routine defines which #include lines are required when calling that routine.

lines 6-8
These lines contain header files that define the trusted software.

line 19
This line initializes the authentication routines. This must be the first action in main(). The two arguments, count and vector, call the program. The identity(S) manual page describes set_auth_parameters().

lines 20-28
These lines get the /etc/passwd entry for the account named on the command line. If no name is specified, use the current EUID (Effective User Identification). If there is no entry in /etc/passwd (in other words, the account does not exist), then exit with an error message.

Note that it is not a security relevant event when the program reports that an account does not exist, because you can determine this by looking at the /etc/passwd file which can be read by all users.

lines 29-33
These lines check that the user is permitted to see the authorizations for the account. Only the account owner (the UID matches the LUID) or the accounts administrator (a user who has auth subsystem authorization) can check the authorizations for the account. An unauthorized user does not need to know the authorizations of another user.

subsys.c (Part 2/2)

34 (void) printf("User name: %s\n", pwd->pw_name); 35 if ((str = strchr(pwd->pw_gecos, ',')) != (char *)0) 36 *str = '\0'; 37 (void) printf("Real name: %s\n", pwd->pw_gecos); 38 (void) printf("Subsystems:");

39 pmask = (mask_t *)0; 40 if ((pr = getprpwnam(pwd->pw_name)) == (struct pr_passwd *)0) { 41 audit_auth_entry(pwd->pw_name, OT_PRPWD, 42 "User missing from Protected Password database" 43 ); 44 str = "UNKNOWN (no Protected Password entry)"; 45 } 46 else if (build_cmd_priv() || (num = total_auths()) < 0) { 47 audit_security_failure( 48 OT_SUBSYS, 1L, 0L, "Subsystem names", "Not listed" 49 ); 50 str = "UNKNOWN (cannot build list of subsystem names)"; 51 }

52 else if (pr->uflg.fg_cprivs) 53 pmask = pr->ufld.fd_cprivs; 54 else if (pr->sflg.fg_cprivs) 55 pmask = pr->sfld.fd_cprivs; 56 else 57 str = "NONE"; 58 printed=0;

59 if (pmask == (mask_t *)0) 60 (void) printf(" %s", str); 61 else { 62 for (n = 0; n < num; n++) 63 if (ISBITSET(pmask, cmd_priv[n].value)) { 64 printed=1; 65 (void) printf(" %s", cmd_priv[n].name); 66 } 67 } 68 if(!printed) 69 (void) printf ("NONE"); 70 putchar('\n');

71 (void) fflush(stdout); 72 exit(ferror(stdout)); 73 /* NOTREACHED */ 74 }

lines 34-38
These lines report the name of the account and the person's real name (which is assumed to be the part of the pw_gecos field in the /etc/passwd file that precedes the first comma).

lines 39-45
These lines get the subsystem authorization vector for the account. Because the account exists in the /etc/passwd file, it must have a Protected Password entry. If it does not, it is an auditable problem. (Note that this may not be true if the account is defined via client-mode NIS, but it will be hidden from the calling program.)

lines 41-43
The audit_auth_entry(S) call produces this type of an audit record. The first argument is the name of the user from the /etc/passwd file; the second argument identifies the type of problem (OT_PRPWD is the Protected Password database; see the audit.h header file for a list of valid type flags); the third argument is a literal string that is recorded in the audit database. See authaudit(S) for a list of routines that record other types of audit records.

lines 46-51
These lines obtain the names of the installed subsystems; if none are listed, audit the failure.

lines 47-49
The first argument to audit_security_failure defines the object in which the problem was detected; OT_SUBSYS indicates the Subsystem database. See the audit.h header file for a list of valid values. The second and third arguments record the expected and current values to help in diagnosing the problem; the fourth and fifth arguments identify additional information about the problem. In these sample programs, the messages are hard-coded in English. If you anticipate needing to localize your application, implement these messages (lines 47-51) using a message catalog so the messages print in the chosen language of the user.

lines 52-58
If the fg_cprivs flag is set in the pr_passwd structure, the account has a private list of subsystem authorizations. If not, the system default applies. If the system default list does not exist, there are no default authorizations; in this specific case, this is not considered an error. However, in most cases, this would be considered an error that should be audited. If there are no default authorizations, assign a restrictive value for the authorizations.

lines 59-70
These lines list the subsystem authorizations for the account.

Next topic: prwarn.c example
Previous topic: Programming examples

© 2003 Caldera International, Inc. All rights reserved.
SCO OpenServer Release 5.0.7 -- 11 February 2003