This chapter covers the following topics:
Access to all QNX resources and system functions is controlled when a user attempts to login to the system. A user sitting at a terminal /dev/ser1 can gain access to the system by entering correct responses to the following command:
on -t /dev/ser1 /bin/login
When invoked without options, the login utility prompts the user for a username and password. You can automate the login process through the tinit utility. To have tinit start the login process automatically at system startup, you would add the following entry to the node's sysinit.node file:
tinit -t /dev/ser1 &
When a user starts a session, the login Shell program is started. See the login man page in Utilities Reference for information about how the Shell variables and defaults are established.
Additional settings are retrieved from the user's /home/userID/.profile file (~/.profile) if it exists. The Shell may add some of the values it requires to the user's .profile file automatically. For example, a user's .profile file may include settings for the following environment variables:
TERM= | defines the user's terminal type (e.g. qnx or qansi — for a list of the possible values, see the Setting Up Terminals chapter) |
TMPDIR= | gives the location of temporary work space that utilities and programs may use (e.g. /tmp) |
TZ= | sets the time zone (e.g. TZ=EST5EDT4) |
The set command can set (+) or unset (-) these shell options. To display a list of the variables that have been defined for your shell, you'd type set at the Shell prompt. To see the value of one variable, you'd type echo $variable_name at the Shell prompt (e.g. echo $WORKDIR). For more information about these Shell commands, see the sh utility in the Utilities Reference.
The /etc/profile file is the first file executed by the login Shell. Local conventions can be established through this file.
The user-specific startup profile file, typically $HOME/.profile, is executed next. You can add any exported environment variables you require to this file. For example, if you'd like to preserve your login Shell settings whenever a process starts a new shell on your behalf, be sure to define and export the ENV environment variable in your .profile file. For example:
export ENV=$HOME/.kshrc
This entry ensures that every time a new shell starts, the /home/.kshrc file will be executed. To display the values of all exported variables, type export -p.
You can write shell scripts that contain Shell commands and options. A Shell script can be executed as a command or in batch mode as a command-line argument to the Shell. For more information about shell scripts, see the sh utility in the Utilities Reference.
QNX provides mechanisms to control access to resources and critical system functions. These mechanisms are based on the ability of the system to identify a particular user.
When the system boots for the first time (right after the initial installation), you're automatically logged in as the superuser (root). This username allows access to every part of the system and doesn't require a password.
To prevent unauthorized users from accessing the system, you should give root a password. You can create a new user account for yourself that you can use afterwards for your daily work. The passwd utility allows a login password to be changed; you can use the utility to create new usernames for yourself and others.
The QNX access control utilities are:
The login utility should be started by tinit on all tty devices. The utility demands a username and password, and verifies them against the user database /etc/passwd before granting access to the system. If the username/password combination is incorrect, login displays a message to that effect and terminates. If the user enters the correct combination, login starts the login Shell and loads that user's environment.
The su utility lets you temporarily have the privileges of another user. If a user ID isn't entered on the command line when you start su, the utility prompts for a password that must match the superuser's password. Entering a valid access combination causes su to access the user database /etc/passwd and create a shell that has all the rights and privileges of the assumed user ID. Exiting from the shell returns you to your regular user ID.
The passwd utility can be used to change passwords or to add a new user account to the system. Anyone can change their own password, but the superuser (root) is the only user who has the right to create new user accounts. In both cases, the passwd utility locks access to the user password file /etc/passwd to prevent any other attempts to access the file while it's being modified.
Before you start creating user IDs, you might want to modify passwd's behavior. The settings in the file /etc/default/passwd determine which local policies will be enforced by passwd, such as the stringency of passwords, user ID ranges, and so on. For more information about the options you can set, see the passwd utility in the Utilities Reference.
A user invokes passwd with his or her own user ID to change the corresponding password. The passwd utility will prompt the user for the required information. When the user is the superuser, the old password isn't requested.
The superuser can add a new account by invoking passwd with a unique user ID. The utility prompts for information that will control the new user's environment, including access privileges. The account permissions to include comprise the user's group ID assignment and file permissions.
For example, to create a new account with the username carol, the superuser would enter:
passwd carol
By default, passwd will then prompt for the following information:
By convention, user accounts have a user ID >= 100. User IDs below 100 are often used by system processes. User ID ranges are set in the /etc/default/passwd file.
If the group ID doesn't exist, a reminder to update the group file /etc/group will be displayed.
The /etc/group file grants privileges to all users who are members of a defined group. For example, the “Finance” department would be allowed access to the company's financial records, but the “Customer Support” group would not. You can set up a group ID for “Finance” with the required access permissions and assign users to that group according to the privileges they require.
The /etc/group file contains a list of users by group. Each line has the following general syntax:
groupname::group_ID:user1, user2, user3, ..., userN
For example, the following entry defines the group “docs” with group ID “124”, and members “johno”, “chrish”, “eric”, “stever”, and “rachel.”
docs::124:johno, chrish, eric, stever, rachel
Initially you'd add groups that have no users, as in the following example:
docs::0: techies::1: support::2: marketing::3: finance::4:
When a user logs in, the value in the password database /etc/passwd will specify the default group ID a user has been assigned to (if any). Users who belong to a group are allowed to switch to the privileges of that group any time using the newgrp command.
The home directory, initial command, and initial password items are optional. If you don't specify a value, the following defaults are used:
home directory | /home/username is used (it's created if it doesn't exist) |
initial command | the default Shell startup command (/bin/sh) is executed immediately after the user logs in |
password | the user account is created without a password |
QNX doesn't provide a direct mechanism for deleting accounts. To delete an account, you must remove the user database entry from the /etc/passwd file, the username from the corresponding group ID assignment entry in the /etc/group file, and the corresponding encoded login password entry from /etc/shadow file.
Upon logging in, a user is assigned two pieces of information:
These are known as the user's real user ID and real group ID.
The user ID should be unique — no two users should share the same user ID. This rule can be enforced by the passwd utility, but the superuser can override the rule by editing the password file directly.
The group ID allows several users to be associated with a group. This group mechanism lets a team of users share resources without making those resources available to the rest of the world. For more information about the /etc/group file and its contents, see the newgrp utility in the Utilities Reference.
Processes have two classes of user and group IDs: real and effective. When a process is created, it automatically inherits these four IDs from its parent (which is typically the login Shell):
The effective user and group IDs are used for permission checking. A process can change its effective user or group ID, or both, so that they differ from their real counterparts. Typically, this is done to gain access to resources that aren't available to the real user and group IDs.
To modify effective group and user IDs: | You use the: |
---|---|
from within C programs | seteuid() and setegid() functions |
from within the Shell | su and newgrp utilities to set the setuid and setgid file permission bits |
while running a Shell program | su command to change to root (provided you know the superuser's password), then edit the /etc/passwd file |
For more information on setuid and setgid, see the “File permissions” section.
The newgrp utility starts a new Shell with different real and effective group IDs. When invoked without arguments, newgrp switches the group ID to the one identified in the password database for the current user. The password database controls the groups that a particular user may switch to.
In QNX, each file has an associated set of permissions called mode bits. These mode bits, in conjunction with the file's owner and group, control access to the file.
When a process creates a file, the process's effective user ID and effective group ID become the file's owner and group. A set of mode bits is also assigned to the file (this is described in the “How mode bits are assigned” section).
There are three classes of mode bits:
When a process attempts to access the file, the Filesystem Manager honors the appropriate class of mode bits. The Filesystem Manager determines which mode bits to honor by performing a few comparisons in a specific order:
The file mode bits are stored in the 16-bit st_mode field of the directory entry for the file; access is granted if a mode bit is set.
As the following table shows, permissions affect regular files and directories differently:
This bit: | Affects: | Affects directories by: |
---|---|---|
r | Reading the file | Examining the names of files in the directory (e.g. via ls) |
w | Writing to the file | Creating, removing, and renaming files within the directory, including subdirectories |
x | Executing the file | Searching the directory. This means you can change your current working directory to this directory. Also, you may include this directory within pathnames (e.g. in open(), stat(), etc.) |
You can use the ls -l (“el”) command to see a file's permissions, owner, and group. The following ls -l output for the file alpha.c shows that the owner and anyone in the techies group may read and write to the file, while other users may only read it:
-rw-rw-r-- 1 rachel techies 8475 Apr 8 1996 alpha.c
In the following example, the ls -ld output for the directory /bin shows that the owner and group members may read, write, and search the directory, while other users don't have write permissions and therefore can't add any new files to the directory:
drwxrwxr-x 2 root techies 2048 Sep 19 1990 bin
But note that other users may still list or execute files in /bin.
It's possible — though unusual — to have read permission on a directory but not search permission. For example, ls could work (depending on the options you give it), but you wouldn't be able to access any file in the directory or do a cd to the directory.
The permissions on a file are derived by combining the current umask of the creating process with that process's requested open()/creat() mode.
The umask is a permission bit mask that indicates which permission bits are to be turned off if a process specifies default permission when a file, directory, or FIFO is created (see umask in the Utilities Reference).
The mask is the logical AND of the mode and the complement of the umask. For example, if the mode requests read-write permission for everyone as follows:
Binary | Octal | Symbolic |
---|---|---|
110 110 110 | 0666 | rw- rw- rw- |
and the umask indicates write permission for group and other:
Binary | Octal | Symbolic |
---|---|---|
000 010 010 | 0022 | --- -w- -w- |
then the result is read-write permission for the owner, and read permission for everyone else:
Binary | Octal | Symbolic |
---|---|---|
110 100 100 | 0644 | rw- r-- r-- |
You can change the permissions of a file with the following commands:
To: | Use: |
---|---|
change owner and group | chown and chgrp utilities, or chown() function (C programs) |
change access permissions, and setuid and setgid mode bits | chmod utility or chmod() function (C programs) |
set the file mode creation mask | umask utility |
To perform certain functions, a user must sometimes run a command at a privilege level higher than their own. For example, a user may need to run the passwd utility to modify their own entry in the password database, even though they would normally be denied write access to that database.
Two file mode bits allow a user to run a command at a higher privilege level:
With these bits set, an executable file will run with the privileges of its owner and group rather than with the privileges of the process that invokes the file. These mode bits apply only to executable regular files.
When a file is loaded for execution and the setuid mode bit is set, the effective user ID of the new process becomes that of the file's owner. Similarly, if the setgid mode bit is set, the effective group ID becomes that of the file's group.
To close a potential security hole, the setuid and setgid bits are cleared any time the file ownership (owner or group) is changed. This prevents users from writing an executable file to disk, setting the setuid bit, and then changing the ownership of the file to root, thereby gaining unlimited system access.
The passwd, login, su, and newgrp utilities are all setuid to root; these programs therefore run with the permissions of the superuser.
By convention, root is the only user with user ID zero, which yields superuser status. With respect to access control, you must ensure that only programs that can be trusted — and absolutely need to be trusted — are setuid to root. No special privileges are bestowed on a program when it's setgid to root.
Three files collectively form the password database:
The access permissions to these files should be set as follows:
File: | Owner: | Group: | Permissions: |
---|---|---|---|
/etc/passwd | root | root | rw- r-- r-- |
/etc/group | root | root | rw- r-- r-- |
/etc/shadow | root | root | rw- --- --- |
The /etc/passwd file contains a set of lines in the following format:
username:haspw:userid:group:comment:homedir:shell
where:
username | login name of user |
haspw | if empty, user has no password; if x, user's password is in the /etc/shadow file. An empty value or a value of x are the only permitted values. |
userid | numeric user ID |
group | numeric group ID |
comment | a free-form comment field; must not contain “:” |
homedir | home directory of this user (default is /) |
shell | initial command (and arguments) to start after login (default is /bin/sh) |
The /etc/group file contains lines in the following format:
groupname::group_ID:user_ID[,user_ID]*
where:
groupname | name of the group |
group_ID | numeric ID of the group |
user_ID | one or more user IDs belonging to this group |
The /etc/shadow file contains lines in the following format:
user_ID:password:0:0:0
where:
user_ID | name of this user |
password | encrypted password of this user |
You may notice from the above permission list that /etc/passwd is readable by anyone. This is to provide standard utilities with a simple mechanism to find information about users. Since this file is readable, the encrypted password isn't stored in it.
The encrypted password is stored in the /etc/shadow file, which is readable only by the superuser. This is to inhibit unauthorized attempts to decrypt the passwords. To protect the security of your user community, you should ensure that these permissions are maintained.
QNX is shipped with a default password database that includes /etc/passwd and /etc/group. The /etc/shadow file isn't shipped, because the accounts initially don't have passwords associated with them.
The default /etc/passwd file that was shipped with your QNX system contains the following:
root::0:0::/:/bin/sh
The default /etc/group file contains the following:
root::0:root
The login utility updates system accounting information, which is logged to the /etc/acclog file. If this file doesn't exist, all accounting information will be discarded. This is the normal mode of operation after QNX has been installed.
For most realtime systems, this default of discarding accounting information is recommended. If you have a dial-up line to a computer or if you run QNX on a network of many users, you may wish to change this default by creating an empty /etc/acclog file.
To enable accounting, you create an empty /etc/acclog file. You can do this using the touch utility:
touch /etc/acclog chmod g=,o= /etc/acclog
Once this file is created, accounting information will be logged here.
Note that only the superuser (user ID root) may create and modify this file.
Each record in the /etc/acclog file is of the form:
tttttttttt cc data...
where tttttttttt is the time in seconds since 1970 (in decimal). This is always followed by a single space. The time is followed by a two-character code cc. This code is then followed by a space and data specific to each code. Each line is terminated by a Newline character. The following utilities write to the /etc/acclog file:
Utility: | Purpose: | Record: |
---|---|---|
login | user logged in | tttttttttt LO device uid gid uname |
login | login failed | tttttttttt LF device uname |
modem | modem connect | tttttttttt MO device baud |
su | switch user | tttttttttt SU device uid gid uname |
tinit | start a command | tttttttttt TS device command |
tinit | arm a device | tttttttttt TA device |
A typical accounting file might look like this:
670464500 TS //1/dev/ser1 modem -b 19200 -L 670464545 MO //1/dev/ser1 2400 670464550 LO //1/dev/ser1 100 101 steve 670465824 TS //1/dev/ser1 modem -b 19200 -L
This record shows that tinit started a modem program to wait for calls. A call was received and answered at 2400 baud, and user ID steve logged in. Note that the log doesn't show a logout. The logout is inferred, because in the final entry tinit starts another modem program.
The total connect time for the user (from successful login) can be calculated thus:
670465824 - 670464550 = 1274 seconds
On a busy system, records from many devices will be interspersed throughout the accounting file. In order to match events keyed to each device, you'll find an associated node number that lets you track accounting records for all devices throughout a network in a single logfile.
Here are several common event sequences:
Event sequence: | Meaning: |
---|---|
TS --> LO --> TS | A login and logout on a dedicated line. |
TS --> MO --> LO --> TS | A login and logout on a dial-up line. |
TA --> TS --> LO --> TA | A login and logout on a dedicated line armed by a keystroke. |
TS --> TS | An unsuccessful login on a dedicated line. |
TS --> MO --> TS | An unsuccessful login on a dial-up line. |
Once you create /etc/acclog, it will start to grow as records are appended to it. If left unmanaged, this file may grow to consume considerable disk space, so you should print or archive the information in this file on a regular basis. You may even want to automate this housekeeping job using the cron utility (see the Utilities Reference).
The following commands move the accounting file to a file named by year and month and create a new empty log:
mv /etc/acclog /etc/acclogs/9607 touch /etc/acclog chmod g=,o= /etc/acclog
Since the data in this file is very regular, you may use the freeze compression utility, which will achieve very high rates of compression on the file. This can significantly reduce disk space requirements if you keep the saved logs online or save them to a floppy.
Here's an example of the recommended compression procedure:
mv /etc/acclog /etc/logs/9607 touch /etc/acclog chmod g=,o= /etc/acclog freeze /etc/logs/9607
Note also that other utilities (possibly third-party) may add their own accounting records to the /etc/acclog file.
To have QNX start recording events in a log file, simply create an empty log file in the appropriate directory. You must use the filenames given below. QNX will start logging system events as soon as the associated log file exists.
QNX utilities log problems or unexpected events to the /etc/syslog text file.
The logger utility appends lines to the /usr/adm/syslog file. As long as a program has write access to this file, it can run logger as a setuid process owned by adm:adm.
The login utility writes information to the /usr/adm/lastlog file (provided it exists). It can be used to track where and when a user last logged in. The finger utility can display information from the lastlog file by user.
The file $HOME/.lastlogin is created by login. It keeps track of the last time the user logged in, and from which device. The contents of this file are displayed when a user logs in. If a user hasn't logged in since the message of the day (motd) was last updated, the contents of the file /etc/motd (provided it exists) are printed to the user's terminal instead.
The presence of an /etc/nologin file prevents anyone from logging in.
The /etc/wtmp file maintains a list of who is currently on the system and how these users are logged in. TCP/IP for QNX uses this information.
The /etc/utmp file is updated by login. It contains login information in binary format and maintains a history of all changes to /etc/wtmp.