/* ***************************************************************** * * * Copyright (c) Compaq Computer Corporation, 1991, 1999 * * * * All Rights Reserved. Unpublished rights reserved under * * the copyright laws of the United States. * * * * The software contained on this media is proprietary to * * and embodies the confidential technology of Compaq * * Computer Corporation. Possession, use, duplication or * * dissemination of the software and media is authorized only * * pursuant to a valid written license from Compaq Computer * * Corporation. * * * * RESTRICTED RIGHTS LEGEND Use, duplication, or disclosure * * by the U.S. Government is subject to restrictions as set * * forth in Subparagraph (c)(1)(ii) of DFARS 252.227-7013, * * or in FAR 52.227-19, as applicable. * * * ***************************************************************** */ /* * HISTORY */ #pragma ident "@(#)$RCSfile: site-pwpolicy.c,v $ $Revision: 1.1.1.4 $ (DEC) $Date: 1999/07/03 01:09:40 $" /* * This module shows how to do the defined customer-policy callouts * for the Tru64 UNIX operating system's Enhanced Security * package (commonly, but incorrectly, referred to as "C2"). * This code was based on the development release currently planned * to be released as V5.0, but has also been tested on V4.0D. * Note that only the AUTH_PW_OKPASSWORD function is available * prior to V5.0-to-be. (While the AUTH_PW_GENPASSWORD call was * defined prior to V5.0, it was never referenced, and the number * of parameters for it was changed before it was used for V5.0. * Thus, despite appearances from reading , it really is * true that only AUTH_PW_OKPASSWORD was available.) * * To compile: * cc -std -o site-pwpolicy -O4 site-pwpolicy.c -lsecurity -lclu -levm -ldb -laud -lm * (The `-lclu -levm' is only relevant to V5.) * If cracklib is installed, and you wish to use it for testing acceptable * passcodes, then add `-DCRACKLIB_DICTPATH=\"/usr/local/lib/pw_dict\"' (or * whatever your DICTPATH was when building cracklib) before the `-O4', and * `-lcrack' to the end. If you didn't install libcrack.a in /usr/local/lib, * then you'll need the appropriate `-L/path/to/libcrack' before the `-lcrack'. * * To use: * Install it with ownership of auth:auth and permissions of * 510 in the directory of your choice, but do NOT install it as * /tcb/bin/pwpolicy - instead, once you've installed it, use * either dxaccounts or "edauth -dd default" to modify the site-callout * path to point to the program. Changing the field in the system * defaults database is something which will be preserved across * upgrade installations, but even an update installation will replace * the /tcb/bin/pwpolicy file with a Digital-supplied shell script. * * Further reading (for understanding): * See the comments in /usr/include/prot.h around AUTH_PW_funcs and * the comments in the /tcb/bin/pwpolicy script supplied by Compaq. */ #include #include #include #include #ifdef AUTH_PW_NUMCRYPTS /*{*/ typedef int Cfunc(char const *, char const *); Cfunc Cbadcrypt; /* slot 0 -- should never be called */ Cfunc Cnullcrypt; /* slot 1 -- store in plaintext (testing only) */ Cfunc Cbigcrypt; /* slot 2 -- bigcrypt() via callout for testing */ struct crypt_disp { Cfunc *func; char const * const name; int maxlen; } ; struct crypt_disp ccrypts[] = { {Cbadcrypt, "Cbadcrypt", 0}, {Cnullcrypt, "Cnullcrypt", AUTH_MAX_PASSWD_LENGTH}, {Cbigcrypt, "Cbigcrypt", AUTH_MAX_PASSWD_LENGTH}, }; #define NUM_CCRYPTS ((int)(sizeof ccrypts / sizeof *ccrypts) - 1) /* slot zero always present to be syntactically valid if no local entries */ /*ARGSUSED*/ int Cbadcrypt(char const *cleartext, char const *salt) { return 1; } /*ARGSUSED*/ int Cnullcrypt(char const *cleartext, char const *salt) { return puts(cleartext) < 0; } int Cbigcrypt(char const *cleartext, char const *salt) { return puts(bigcrypt(cleartext, salt)) < 0; } /* End of encryption codes */ #endif /* } def AUTH_PW_NUMCRYPTS */ int getline(char *ibuf, size_t lbuf) { char *cp; if (!fgets(ibuf, lbuf, stdin)) return 1; cp = strchr(ibuf, '\n'); if (!cp || cp[1]) return 1; *cp = 0; return 0; } int getnum(char const *buf, long *rval) { long val; char *ep; ep = 0; val = strtol(buf, &ep, 10); if (ep && *ep) return 1; *rval = val; return 0; } int getinum(char *ibuf, size_t lbuf, long *rval) { if (getline(ibuf, lbuf)) return 1; return getnum(ibuf, rval); } #ifdef AUTH_PW_NUMCRYPTS /*{*/ const char a64code[65] = "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" ; int gen_passcode(char const *user, int algnum, int minlen, int maxlen) { char tbuf[AUTH_MAX_PASSWD_LENGTH+5]; /* note--6 bits per char, 30+ bits per uint, so 5 chars per uint */ uint_t nbuf[(AUTH_MAX_PASSWD_LENGTH+4)/5]; #define MAXNBUF (sizeof nbuf / sizeof *nbuf) int outlen, i, j; uint_t nval; char *cp; char const *sp; long seedval; if (algnum < 0 && ccrypts[-algnum].func == Cnullcrypt) return 0; /* same `declined' testing as NSYMBOLS */ seedval = 0L; for (sp = user; *sp; sp++) { seedval = seedval * 48 + *sp; } seedval ^= getpid()*9L ^ time(NULL); srand48(seedval); /* get some pseudo-random bits */ for (i = 0; i < MAXNBUF; i++) { nbuf[i] = (uint_t) lrand48(); } /* pick an output length */ outlen = minlen + lrand48() % (maxlen - minlen + 1); /* where to start storing output characters */ cp = tbuf; for (i = 0; i < MAXNBUF; i++) { nval = nbuf[i]; for (j = 0; j < 5; j++,nval>>=6) { *cp++ = a64code[nval & 077]; } } tbuf[outlen] = 0; /* truncate it where we decided earlier */ return puts(tbuf) < 0; } #endif /* } def AUTH_PW_NUMCRYPTS */ /* * Here to do site-defined passcode acceptability tests. * Inputs: * const char *passcode -- the proposed passcode * * Outputs: * boolean -- true if acceptable, false if rejected. */ int allow_passcode_p(const char *passcode) { #ifdef CRACKLIB_DICTPATH extern char *FascistCheck(const char *, const char *); char *msg; msg = FascistCheck(passcode, CRACKLIB_DICTPATH); /* * The message output will only be useful starting with V5.0. * It's suppressed and ignored prior to V5.0. */ if (msg && *msg) { (void) fprintf(stdout, "Passkey rejected: %s\n", msg); return 0; } else if (msg) { (void) fprintf(stdout, "Passkey rejected by cracklib\n"); } else { return 1; } #else /* Just for pedagogical purposes, reject passcodes which * contain problematic characters which might not be easily * generated on all keyboards. */ if (strcspn(passcode, "#@$\033") != strlen(passcode)) return 0; return 1; /* blindly accept other passphrases for now */ #endif } int main(int argc, char **argv) { char iline[AUTH_MAX_PASSWD_LENGTH+2]; char saltbuf[AUTH_MAX_PASSWD_LENGTH+1]; char *cp, *ep; long inum; int rval; int algnum, minlen, maxlen; set_auth_parameters(argc, argv); /* see what we're supposed to do */ if (getinum(iline, sizeof iline, &inum)) return 1; /* validate the function code */ if (inum < AUTH_PW_FUNC_MIN || inum > AUTH_PW_FUNC_MAX) return 1; switch ((int)inum) { default: /* should never get here */ abort(); /*NOTREACHED*/ #ifdef AUTH_PW_NUMCRYPTS /*{*/ case AUTH_PW_NUMCRYPTS: return printf("%d\n", NUM_CCRYPTS) < 0; /*NOTREACHED*/ case AUTH_PW_ENCRYPT: /* OK, read the parameters */ if (getinum(iline, sizeof iline, &inum)) return 1; if (inum <= 0 || inum > NUM_CCRYPTS) return 1; if (getline(iline, sizeof iline)) return 1; (void) strcpy(saltbuf, iline); if (getline(iline, sizeof iline)) return 1; return (ccrypts[inum].func)(iline, saltbuf); /*NOTREACHED*/ case AUTH_PW_MAXCRYPTLEN: /* OK, read the parameters */ if (getinum(iline, sizeof iline, &inum)) return 1; if (inum <= 0 || inum > NUM_CCRYPTS) return 1; return printf("%d\n", ccrypts[inum].maxlen) < 0; /*NOTREACHED*/ case AUTH_PW_CRYPTNAME: /* OK, read the parameters */ if (getinum(iline, sizeof iline, &inum)) return 1; if (inum <= 0 || inum > NUM_CCRYPTS) return 1; return puts(ccrypts[inum].name) < 0; /*NOTREACHED*/ case AUTH_PW_NSYMBOLS: /* OK, read the parameters */ if (getline(iline, sizeof iline)) return 1; (void) strcpy(saltbuf, iline); /* save username */ if (getinum(iline, sizeof iline, &inum)) return 1; if (inum < -NUM_CCRYPTS || inum >= get_num_crypts()) return 1; /* for testing, give a way to get this result */ if (inum < 0 && ccrypts[-inum].func == Cnullcrypt) rval = 0; else rval = 64; return printf("%d\n", rval) < 0; /*NOTREACHED*/ case AUTH_PW_GENPASSWORD: /* OK, read the parameters */ if (getline(iline, sizeof iline)) return 1; (void) strcpy(saltbuf, iline); /* save username */ if (getinum(iline, sizeof iline, &inum)) return 1; if (inum < -NUM_CCRYPTS || inum >= get_num_crypts()) return 1; algnum = (int) inum; if (getinum(iline, sizeof iline, &inum)) return 1; if (inum < 0 || inum > AUTH_MAX_PASSWD_LENGTH) return 1; minlen = (int) inum; if (getinum(iline, sizeof iline, &inum)) return 1; if (inum < 0 || inum > AUTH_MAX_PASSWD_LENGTH) return 1; maxlen = (int) inum; if (minlen > maxlen) return 1; return gen_passcode(saltbuf, algnum, minlen, maxlen); /*NOTREACHED*/ #endif /* } new-to-v5.0 features */ case AUTH_PW_OKPASSWORD: /* OK, eat the parameters */ /* Username, which we're ignoring. */ if (getline(iline, sizeof iline)) return 1; /* Proposed passcode, which we'll make subject to some * trivial check as a demonstration. */ if (getline(iline, sizeof iline)) return 1; return !allow_passcode_p(iline); /*NOTREACHED*/ } abort(); /* should not be reachable */ }