4. System Information
4.1 How can I tell how much memory my system has?
This is another `Frequently Unanswered Question'. In most cases, you should not even attempt to find out.
If you really must, then it can usually be done, but in a highly
system-dependent fashion. For example, on Solaris, you can use
sysconf(_SC_PHYS_PAGES)
and sysconf(_SC_PAGESIZE)
; on
FreeBSD, you can use sysctl()
; on Linux you can read and parse
`/proc/meminfo' (being careful to allow any of the historically
valid formats for this file); other systems may have their own methods.
I'm not aware of any more portable methods.
For HP-UX (9 and 10), the following code has been contributed:
struct pst_static pst; if (pstat_getstatic(&pst, sizeof(pst), (size_t) 1, 0) != -1) { printf(" Page Size: %lu\n", pst.page_size); printf("Phys Pages: %lu\n", pst.physical_memory); }
4.2 How do I check a user's password?
4.2.1 How do I get a user's password?
Traditionally user passwords were kept in the `/etc/passwd' file, on most UNIX flavours. Which is usually of this format:
username:password:uid:gid:gecos field:home directory:login shell
Though this has changed with time, now user information may be kept on other hosts, or not necessarily in the `/etc/passwd' file. Modern implementations also made use of `shadow' password files which hold the password, along with sensitive information. This file would be readable only by privileged users.
The password is usually not in clear text, but encrypted due to security concerns.
POSIX defines a suite of routines which can be used to access this
database for queries. The quickest way to get an individual record for a
user is with the getpwnam()
and getpwuid()
routines. Both
return a pointer to a struct passwd, which holds the users information
in various members. getpwnam()
accepts a string holding the
user's name, getpwuid()
accepts a uid (type uid_t
as
defined by POSIX). Both return NULL if they fail.
However, as explained earlier, a shadow database exists on most modern
systems to hold sensitive information, namely the password. Some systems
only return the password if the calling uid is of the superuser, others
require you to use another suite of functions for the shadow password
database. If this is the case you need to make use of getspnam()
,
which accepts a username and returns a struct spwd. Again, in order to
successfully do this, you will need to have privileges. (On some systems,
notably HP-UX and SCO, you may need to use getprpwnam()
instead.)
4.2.2 How do I get shadow passwords by uid?
My system uses the getsp* suite of routines to get the sensitive user information. However I do not have
getspuid()
, onlygetspnam()
. How do I work around this, and get by uid?
The work around is relatively painless. The following routine should go straight into your personal utility library:
#include <stdlib.h> #include <stdio.h> #include <pwd.h> #include <shadow.h> struct spwd *getspuid(uid_t pw_uid) { struct spwd *shadow; struct passwd *ppasswd; if( ((ppasswd = getpwuid(pw_uid)) == NULL) || ((shadow = getspnam(ppasswd->pw_name)) == NULL)) return NULL; return shadow; }
The problem is, that some systems do not keep the uid, or other information in the shadow database.
4.2.3 How do I verify a user's password?
The fundamental problem here is, that various authentication systems exist, and passwords aren't always what they seem. Also with the traditional one way encryption method used by most UNIX flavours (out of the box), the encryption algorithm may differ, some systems use a one way DES encryption, others like the international release of FreeBSD use MD5.
The most popular way is to have a one way encryption algorithm, where
the password cannot be decrypted. Instead the password is taken in clear
text from input, and encrypted and checked against the encrypted
password in the database. The details of how to encrypt should really
come from your man page for crypt()
, but here's a usual version:
/* given a plaintext password and an encrypted password, check if * they match; returns 1 if they match, 0 otherwise. */ int check_pass(const char *plainpw, const char *cryptpw) { return strcmp(crypt(plainpw,cryptpw), cryptpw) == 0; }
This works because the salt used in encrypting the password is stored as an initial substring of the encrypted value.
WARNING: on some systems, password encryption is actually done
with a variant of crypt called bigcrypt()
.