Unix Programming Frequently Asked Questions - Part IV

来源:互联网 发布:dropdownlist绑定数据 编辑:程序博客网 时间:2024/06/06 07:28

Unix Programming Frequently Asked Questions - Part IV


4. System Information

4.1 How can I tell how much memory my system has?

This is another `Frequently Unanswered Question'. In most cases, youshould not evenattempt to find out.

If you really must, then it can usually be done, but in a highlysystem-dependent fashion. For example, on Solaris, you can usesysconf(_SC_PHYS_PAGES) andsysconf(_SC_PAGESIZE); onFreeBSD, you can use sysctl(); on Linux you can read and parse`/proc/meminfo' (being careful to allow any of the historicallyvalid 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 onother hosts, or not necessarily in the`/etc/passwd' file. Modernimplementations also made use of `shadow' password files which hold thepassword, along with sensitive information. This file would be readableonly by privileged users.

The password is usually not in clear text, but encrypted due to securityconcerns.

POSIX defines a suite of routines which can be used to access thisdatabase for queries. The quickest way to get an individual record for auser is with thegetpwnam() and getpwuid() routines. Bothreturn a pointer to a struct passwd, which holds the users informationin various members.getpwnam() accepts a string holding theuser's name, getpwuid() accepts a uid (typeuid_t asdefined by POSIX). Both return NULL if they fail.

However, as explained earlier, a shadow database exists on most modernsystems to hold sensitive information, namely the password. Some systemsonly return the password if the calling uid is of the superuser, othersrequire you to use another suite of functions for the shadow passworddatabase. If this is the case you need to make use of getspnam(),which accepts a username and returns a struct spwd. Again, in order tosuccessfully do this, you will need to have privileges. (On some systems,notably HP-UX and SCO, you may need to usegetprpwnam() instead.)

4.2.2 How do I get shadow passwords by uid?

My system uses the getsp* suite of routines to get the sensitive userinformation. However I do not havegetspuid(), onlygetspnam(). How do I work around this, and get by uid?

The work around is relatively painless. The following routine should gostraight 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 otherinformation in the shadow database.

4.2.3 How do I verify a user's password?

The fundamental problem here is, that various authentication systemsexist, and passwords aren't always what they seem. Also with thetraditional one way encryption method used by most UNIX flavours (out ofthe box), the encryption algorithm may differ, some systems use a oneway DES encryption, others like the international release of FreeBSD useMD5.

The most popular way is to have a one way encryption algorithm, wherethe password cannot be decrypted. Instead the password is taken in cleartext from input, and encrypted and checked against the encryptedpassword in the database. The details of how to encrypt should reallycome 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 asan initial substring of the encrypted value.

WARNING: on some systems, password encryption is actually donewith a variant of crypt calledbigcrypt().

原创粉丝点击