diff options
Diffstat (limited to 'lib/libskey')
-rw-r--r-- | lib/libskey/Makefile | 18 | ||||
-rw-r--r-- | lib/libskey/mdx.h | 19 | ||||
-rw-r--r-- | lib/libskey/pathnames.h | 6 | ||||
-rw-r--r-- | lib/libskey/put.c | 2292 | ||||
-rw-r--r-- | lib/libskey/skey.1 | 59 | ||||
-rw-r--r-- | lib/libskey/skey.3 | 156 | ||||
-rw-r--r-- | lib/libskey/skey.access.5 | 125 | ||||
-rw-r--r-- | lib/libskey/skey.h | 60 | ||||
-rw-r--r-- | lib/libskey/skey_crypt.c | 38 | ||||
-rw-r--r-- | lib/libskey/skey_getpass.c | 37 | ||||
-rw-r--r-- | lib/libskey/skeyaccess.c | 485 | ||||
-rw-r--r-- | lib/libskey/skeylogin.c | 342 | ||||
-rw-r--r-- | lib/libskey/skeysubr.c | 130 |
13 files changed, 3767 insertions, 0 deletions
diff --git a/lib/libskey/Makefile b/lib/libskey/Makefile new file mode 100644 index 0000000..6e3fe92 --- /dev/null +++ b/lib/libskey/Makefile @@ -0,0 +1,18 @@ +# @(#)Makefile 5.4 (Berkeley) 5/7/91 + +LIB= skey +SRCS= skeyaccess.c put.c skey_crypt.c skey_getpass.c skeylogin.c skeysubr.c +MAN1= skey.1 +MAN3= skey.3 +MLINKS= skey.3 skeylookup.3 skey.3 skeyverify.3 skey.3 skeychallenge.3 \ + skey.3 skeyinfo.3 skey.3 skeyaccess.3 skey.3 skey_getpass.3 \ + skey.3 skey_crypt.3 +MAN5= skey.access.5 + +CFLAGS+=-DPERMIT_CONSOLE -D_SKEY_INTERNAL -I${.CURDIR} + +beforeinstall: + ${INSTALL} -C -o ${BINOWN} -g ${BINGRP} -m 444 ${.CURDIR}/skey.h \ + ${DESTDIR}/usr/include + +.include <bsd.lib.mk> diff --git a/lib/libskey/mdx.h b/lib/libskey/mdx.h new file mode 100644 index 0000000..567d541 --- /dev/null +++ b/lib/libskey/mdx.h @@ -0,0 +1,19 @@ +#ifdef MD5 +/* S/Key can use MD5 now, if defined... */ +#include <md5.h> + +#define MDXFinal MD5Final +#define MDXInit MD5Init +#define MDXUpdate MD5Update +#define MDX_CTX MD5_CTX +#else + +/* By default, use MD4 for compatibility */ +#include <md4.h> + +#define MDXFinal MD4Final +#define MDXInit MD4Init +#define MDXUpdate MD4Update +#define MDX_CTX MD4_CTX + +#endif diff --git a/lib/libskey/pathnames.h b/lib/libskey/pathnames.h new file mode 100644 index 0000000..84f0d32 --- /dev/null +++ b/lib/libskey/pathnames.h @@ -0,0 +1,6 @@ +/* $Id$ (FreeBSD) */ + +#include <paths.h> + +#define _PATH_SKEYACCESS "/etc/skey.access" +#define _PATH_SKEYFILE "/etc/skeykeys" diff --git a/lib/libskey/put.c b/lib/libskey/put.c new file mode 100644 index 0000000..5c9eaea --- /dev/null +++ b/lib/libskey/put.c @@ -0,0 +1,2292 @@ +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <ctype.h> +#include "skey.h" + +static unsigned long extract __P((char *s,int start,int length)); +static void standard __P((char *word)); +static void insert __P((char *s, int x, int start, int length)); +static int wsrch __P((char *w,int low,int high)); + +/* Dictionary for integer-word translations */ +static char Wp[2048][4] = { +"A", +"ABE", +"ACE", +"ACT", +"AD", +"ADA", +"ADD", +"AGO", +"AID", +"AIM", +"AIR", +"ALL", +"ALP", +"AM", +"AMY", +"AN", +"ANA", +"AND", +"ANN", +"ANT", +"ANY", +"APE", +"APS", +"APT", +"ARC", +"ARE", +"ARK", +"ARM", +"ART", +"AS", +"ASH", +"ASK", +"AT", +"ATE", +"AUG", +"AUK", +"AVE", +"AWE", +"AWK", +"AWL", +"AWN", +"AX", +"AYE", +"BAD", +"BAG", +"BAH", +"BAM", +"BAN", +"BAR", +"BAT", +"BAY", +"BE", +"BED", +"BEE", +"BEG", +"BEN", +"BET", +"BEY", +"BIB", +"BID", +"BIG", +"BIN", +"BIT", +"BOB", +"BOG", +"BON", +"BOO", +"BOP", +"BOW", +"BOY", +"BUB", +"BUD", +"BUG", +"BUM", +"BUN", +"BUS", +"BUT", +"BUY", +"BY", +"BYE", +"CAB", +"CAL", +"CAM", +"CAN", +"CAP", +"CAR", +"CAT", +"CAW", +"COD", +"COG", +"COL", +"CON", +"COO", +"COP", +"COT", +"COW", +"COY", +"CRY", +"CUB", +"CUE", +"CUP", +"CUR", +"CUT", +"DAB", +"DAD", +"DAM", +"DAN", +"DAR", +"DAY", +"DEE", +"DEL", +"DEN", +"DES", +"DEW", +"DID", +"DIE", +"DIG", +"DIN", +"DIP", +"DO", +"DOE", +"DOG", +"DON", +"DOT", +"DOW", +"DRY", +"DUB", +"DUD", +"DUE", +"DUG", +"DUN", +"EAR", +"EAT", +"ED", +"EEL", +"EGG", +"EGO", +"ELI", +"ELK", +"ELM", +"ELY", +"EM", +"END", +"EST", +"ETC", +"EVA", +"EVE", +"EWE", +"EYE", +"FAD", +"FAN", +"FAR", +"FAT", +"FAY", +"FED", +"FEE", +"FEW", +"FIB", +"FIG", +"FIN", +"FIR", +"FIT", +"FLO", +"FLY", +"FOE", +"FOG", +"FOR", +"FRY", +"FUM", +"FUN", +"FUR", +"GAB", +"GAD", +"GAG", +"GAL", +"GAM", +"GAP", +"GAS", +"GAY", +"GEE", +"GEL", +"GEM", +"GET", +"GIG", +"GIL", +"GIN", +"GO", +"GOT", +"GUM", +"GUN", +"GUS", +"GUT", +"GUY", +"GYM", +"GYP", +"HA", +"HAD", +"HAL", +"HAM", +"HAN", +"HAP", +"HAS", +"HAT", +"HAW", +"HAY", +"HE", +"HEM", +"HEN", +"HER", +"HEW", +"HEY", +"HI", +"HID", +"HIM", +"HIP", +"HIS", +"HIT", +"HO", +"HOB", +"HOC", +"HOE", +"HOG", +"HOP", +"HOT", +"HOW", +"HUB", +"HUE", +"HUG", +"HUH", +"HUM", +"HUT", +"I", +"ICY", +"IDA", +"IF", +"IKE", +"ILL", +"INK", +"INN", +"IO", +"ION", +"IQ", +"IRA", +"IRE", +"IRK", +"IS", +"IT", +"ITS", +"IVY", +"JAB", +"JAG", +"JAM", +"JAN", +"JAR", +"JAW", +"JAY", +"JET", +"JIG", +"JIM", +"JO", +"JOB", +"JOE", +"JOG", +"JOT", +"JOY", +"JUG", +"JUT", +"KAY", +"KEG", +"KEN", +"KEY", +"KID", +"KIM", +"KIN", +"KIT", +"LA", +"LAB", +"LAC", +"LAD", +"LAG", +"LAM", +"LAP", +"LAW", +"LAY", +"LEA", +"LED", +"LEE", +"LEG", +"LEN", +"LEO", +"LET", +"LEW", +"LID", +"LIE", +"LIN", +"LIP", +"LIT", +"LO", +"LOB", +"LOG", +"LOP", +"LOS", +"LOT", +"LOU", +"LOW", +"LOY", +"LUG", +"LYE", +"MA", +"MAC", +"MAD", +"MAE", +"MAN", +"MAO", +"MAP", +"MAT", +"MAW", +"MAY", +"ME", +"MEG", +"MEL", +"MEN", +"MET", +"MEW", +"MID", +"MIN", +"MIT", +"MOB", +"MOD", +"MOE", +"MOO", +"MOP", +"MOS", +"MOT", +"MOW", +"MUD", +"MUG", +"MUM", +"MY", +"NAB", +"NAG", +"NAN", +"NAP", +"NAT", +"NAY", +"NE", +"NED", +"NEE", +"NET", +"NEW", +"NIB", +"NIL", +"NIP", +"NIT", +"NO", +"NOB", +"NOD", +"NON", +"NOR", +"NOT", +"NOV", +"NOW", +"NU", +"NUN", +"NUT", +"O", +"OAF", +"OAK", +"OAR", +"OAT", +"ODD", +"ODE", +"OF", +"OFF", +"OFT", +"OH", +"OIL", +"OK", +"OLD", +"ON", +"ONE", +"OR", +"ORB", +"ORE", +"ORR", +"OS", +"OTT", +"OUR", +"OUT", +"OVA", +"OW", +"OWE", +"OWL", +"OWN", +"OX", +"PA", +"PAD", +"PAL", +"PAM", +"PAN", +"PAP", +"PAR", +"PAT", +"PAW", +"PAY", +"PEA", +"PEG", +"PEN", +"PEP", +"PER", +"PET", +"PEW", +"PHI", +"PI", +"PIE", +"PIN", +"PIT", +"PLY", +"PO", +"POD", +"POE", +"POP", +"POT", +"POW", +"PRO", +"PRY", +"PUB", +"PUG", +"PUN", +"PUP", +"PUT", +"QUO", +"RAG", +"RAM", +"RAN", +"RAP", +"RAT", +"RAW", +"RAY", +"REB", +"RED", +"REP", +"RET", +"RIB", +"RID", +"RIG", +"RIM", +"RIO", +"RIP", +"ROB", +"ROD", +"ROE", +"RON", +"ROT", +"ROW", +"ROY", +"RUB", +"RUE", +"RUG", +"RUM", +"RUN", +"RYE", +"SAC", +"SAD", +"SAG", +"SAL", +"SAM", +"SAN", +"SAP", +"SAT", +"SAW", +"SAY", +"SEA", +"SEC", +"SEE", +"SEN", +"SET", +"SEW", +"SHE", +"SHY", +"SIN", +"SIP", +"SIR", +"SIS", +"SIT", +"SKI", +"SKY", +"SLY", +"SO", +"SOB", +"SOD", +"SON", +"SOP", +"SOW", +"SOY", +"SPA", +"SPY", +"SUB", +"SUD", +"SUE", +"SUM", +"SUN", +"SUP", +"TAB", +"TAD", +"TAG", +"TAN", +"TAP", +"TAR", +"TEA", +"TED", +"TEE", +"TEN", +"THE", +"THY", +"TIC", +"TIE", +"TIM", +"TIN", +"TIP", +"TO", +"TOE", +"TOG", +"TOM", +"TON", +"TOO", +"TOP", +"TOW", +"TOY", +"TRY", +"TUB", +"TUG", +"TUM", +"TUN", +"TWO", +"UN", +"UP", +"US", +"USE", +"VAN", +"VAT", +"VET", +"VIE", +"WAD", +"WAG", +"WAR", +"WAS", +"WAY", +"WE", +"WEB", +"WED", +"WEE", +"WET", +"WHO", +"WHY", +"WIN", +"WIT", +"WOK", +"WON", +"WOO", +"WOW", +"WRY", +"WU", +"YAM", +"YAP", +"YAW", +"YE", +"YEA", +"YES", +"YET", +"YOU", +"ABED", +"ABEL", +"ABET", +"ABLE", +"ABUT", +"ACHE", +"ACID", +"ACME", +"ACRE", +"ACTA", +"ACTS", +"ADAM", +"ADDS", +"ADEN", +"AFAR", +"AFRO", +"AGEE", +"AHEM", +"AHOY", +"AIDA", +"AIDE", +"AIDS", +"AIRY", +"AJAR", +"AKIN", +"ALAN", +"ALEC", +"ALGA", +"ALIA", +"ALLY", +"ALMA", +"ALOE", +"ALSO", +"ALTO", +"ALUM", +"ALVA", +"AMEN", +"AMES", +"AMID", +"AMMO", +"AMOK", +"AMOS", +"AMRA", +"ANDY", +"ANEW", +"ANNA", +"ANNE", +"ANTE", +"ANTI", +"AQUA", +"ARAB", +"ARCH", +"AREA", +"ARGO", +"ARID", +"ARMY", +"ARTS", +"ARTY", +"ASIA", +"ASKS", +"ATOM", +"AUNT", +"AURA", +"AUTO", +"AVER", +"AVID", +"AVIS", +"AVON", +"AVOW", +"AWAY", +"AWRY", +"BABE", +"BABY", +"BACH", +"BACK", +"BADE", +"BAIL", +"BAIT", +"BAKE", +"BALD", +"BALE", +"BALI", +"BALK", +"BALL", +"BALM", +"BAND", +"BANE", +"BANG", +"BANK", +"BARB", +"BARD", +"BARE", +"BARK", +"BARN", +"BARR", +"BASE", +"BASH", +"BASK", +"BASS", +"BATE", +"BATH", +"BAWD", +"BAWL", +"BEAD", +"BEAK", +"BEAM", +"BEAN", +"BEAR", +"BEAT", +"BEAU", +"BECK", +"BEEF", +"BEEN", +"BEER", +"BEET", +"BELA", +"BELL", +"BELT", +"BEND", +"BENT", +"BERG", +"BERN", +"BERT", +"BESS", +"BEST", +"BETA", +"BETH", +"BHOY", +"BIAS", +"BIDE", +"BIEN", +"BILE", +"BILK", +"BILL", +"BIND", +"BING", +"BIRD", +"BITE", +"BITS", +"BLAB", +"BLAT", +"BLED", +"BLEW", +"BLOB", +"BLOC", +"BLOT", +"BLOW", +"BLUE", +"BLUM", +"BLUR", +"BOAR", +"BOAT", +"BOCA", +"BOCK", +"BODE", +"BODY", +"BOGY", +"BOHR", +"BOIL", +"BOLD", +"BOLO", +"BOLT", +"BOMB", +"BONA", +"BOND", +"BONE", +"BONG", +"BONN", +"BONY", +"BOOK", +"BOOM", +"BOON", +"BOOT", +"BORE", +"BORG", +"BORN", +"BOSE", +"BOSS", +"BOTH", +"BOUT", +"BOWL", +"BOYD", +"BRAD", +"BRAE", +"BRAG", +"BRAN", +"BRAY", +"BRED", +"BREW", +"BRIG", +"BRIM", +"BROW", +"BUCK", +"BUDD", +"BUFF", +"BULB", +"BULK", +"BULL", +"BUNK", +"BUNT", +"BUOY", +"BURG", +"BURL", +"BURN", +"BURR", +"BURT", +"BURY", +"BUSH", +"BUSS", +"BUST", +"BUSY", +"BYTE", +"CADY", +"CAFE", +"CAGE", +"CAIN", +"CAKE", +"CALF", +"CALL", +"CALM", +"CAME", +"CANE", +"CANT", +"CARD", +"CARE", +"CARL", +"CARR", +"CART", +"CASE", +"CASH", +"CASK", +"CAST", +"CAVE", +"CEIL", +"CELL", +"CENT", +"CERN", +"CHAD", +"CHAR", +"CHAT", +"CHAW", +"CHEF", +"CHEN", +"CHEW", +"CHIC", +"CHIN", +"CHOU", +"CHOW", +"CHUB", +"CHUG", +"CHUM", +"CITE", +"CITY", +"CLAD", +"CLAM", +"CLAN", +"CLAW", +"CLAY", +"CLOD", +"CLOG", +"CLOT", +"CLUB", +"CLUE", +"COAL", +"COAT", +"COCA", +"COCK", +"COCO", +"CODA", +"CODE", +"CODY", +"COED", +"COIL", +"COIN", +"COKE", +"COLA", +"COLD", +"COLT", +"COMA", +"COMB", +"COME", +"COOK", +"COOL", +"COON", +"COOT", +"CORD", +"CORE", +"CORK", +"CORN", +"COST", +"COVE", +"COWL", +"CRAB", +"CRAG", +"CRAM", +"CRAY", +"CREW", +"CRIB", +"CROW", +"CRUD", +"CUBA", +"CUBE", +"CUFF", +"CULL", +"CULT", +"CUNY", +"CURB", +"CURD", +"CURE", +"CURL", +"CURT", +"CUTS", +"DADE", +"DALE", +"DAME", +"DANA", +"DANE", +"DANG", +"DANK", +"DARE", +"DARK", +"DARN", +"DART", +"DASH", +"DATA", +"DATE", +"DAVE", +"DAVY", +"DAWN", +"DAYS", +"DEAD", +"DEAF", +"DEAL", +"DEAN", +"DEAR", +"DEBT", +"DECK", +"DEED", +"DEEM", +"DEER", +"DEFT", +"DEFY", +"DELL", +"DENT", +"DENY", +"DESK", +"DIAL", +"DICE", +"DIED", +"DIET", +"DIME", +"DINE", +"DING", +"DINT", +"DIRE", +"DIRT", +"DISC", +"DISH", +"DISK", +"DIVE", +"DOCK", +"DOES", +"DOLE", +"DOLL", +"DOLT", +"DOME", +"DONE", +"DOOM", +"DOOR", +"DORA", +"DOSE", +"DOTE", +"DOUG", +"DOUR", +"DOVE", +"DOWN", +"DRAB", +"DRAG", +"DRAM", +"DRAW", +"DREW", +"DRUB", +"DRUG", +"DRUM", +"DUAL", +"DUCK", +"DUCT", +"DUEL", +"DUET", +"DUKE", +"DULL", +"DUMB", +"DUNE", +"DUNK", +"DUSK", +"DUST", +"DUTY", +"EACH", +"EARL", +"EARN", +"EASE", +"EAST", +"EASY", +"EBEN", +"ECHO", +"EDDY", +"EDEN", +"EDGE", +"EDGY", +"EDIT", +"EDNA", +"EGAN", +"ELAN", +"ELBA", +"ELLA", +"ELSE", +"EMIL", +"EMIT", +"EMMA", +"ENDS", +"ERIC", +"EROS", +"EVEN", +"EVER", +"EVIL", +"EYED", +"FACE", +"FACT", +"FADE", +"FAIL", +"FAIN", +"FAIR", +"FAKE", +"FALL", +"FAME", +"FANG", +"FARM", +"FAST", +"FATE", +"FAWN", +"FEAR", +"FEAT", +"FEED", +"FEEL", +"FEET", +"FELL", +"FELT", +"FEND", +"FERN", +"FEST", +"FEUD", +"FIEF", +"FIGS", +"FILE", +"FILL", +"FILM", +"FIND", +"FINE", +"FINK", +"FIRE", +"FIRM", +"FISH", +"FISK", +"FIST", +"FITS", +"FIVE", +"FLAG", +"FLAK", +"FLAM", +"FLAT", +"FLAW", +"FLEA", +"FLED", +"FLEW", +"FLIT", +"FLOC", +"FLOG", +"FLOW", +"FLUB", +"FLUE", +"FOAL", +"FOAM", +"FOGY", +"FOIL", +"FOLD", +"FOLK", +"FOND", +"FONT", +"FOOD", +"FOOL", +"FOOT", +"FORD", +"FORE", +"FORK", +"FORM", +"FORT", +"FOSS", +"FOUL", +"FOUR", +"FOWL", +"FRAU", +"FRAY", +"FRED", +"FREE", +"FRET", +"FREY", +"FROG", +"FROM", +"FUEL", +"FULL", +"FUME", +"FUND", +"FUNK", +"FURY", +"FUSE", +"FUSS", +"GAFF", +"GAGE", +"GAIL", +"GAIN", +"GAIT", +"GALA", +"GALE", +"GALL", +"GALT", +"GAME", +"GANG", +"GARB", +"GARY", +"GASH", +"GATE", +"GAUL", +"GAUR", +"GAVE", +"GAWK", +"GEAR", +"GELD", +"GENE", +"GENT", +"GERM", +"GETS", +"GIBE", +"GIFT", +"GILD", +"GILL", +"GILT", +"GINA", +"GIRD", +"GIRL", +"GIST", +"GIVE", +"GLAD", +"GLEE", +"GLEN", +"GLIB", +"GLOB", +"GLOM", +"GLOW", +"GLUE", +"GLUM", +"GLUT", +"GOAD", +"GOAL", +"GOAT", +"GOER", +"GOES", +"GOLD", +"GOLF", +"GONE", +"GONG", +"GOOD", +"GOOF", +"GORE", +"GORY", +"GOSH", +"GOUT", +"GOWN", +"GRAB", +"GRAD", +"GRAY", +"GREG", +"GREW", +"GREY", +"GRID", +"GRIM", +"GRIN", +"GRIT", +"GROW", +"GRUB", +"GULF", +"GULL", +"GUNK", +"GURU", +"GUSH", +"GUST", +"GWEN", +"GWYN", +"HAAG", +"HAAS", +"HACK", +"HAIL", +"HAIR", +"HALE", +"HALF", +"HALL", +"HALO", +"HALT", +"HAND", +"HANG", +"HANK", +"HANS", +"HARD", +"HARK", +"HARM", +"HART", +"HASH", +"HAST", +"HATE", +"HATH", +"HAUL", +"HAVE", +"HAWK", +"HAYS", +"HEAD", +"HEAL", +"HEAR", +"HEAT", +"HEBE", +"HECK", +"HEED", +"HEEL", +"HEFT", +"HELD", +"HELL", +"HELM", +"HERB", +"HERD", +"HERE", +"HERO", +"HERS", +"HESS", +"HEWN", +"HICK", +"HIDE", +"HIGH", +"HIKE", +"HILL", +"HILT", +"HIND", +"HINT", +"HIRE", +"HISS", +"HIVE", +"HOBO", +"HOCK", +"HOFF", +"HOLD", +"HOLE", +"HOLM", +"HOLT", +"HOME", +"HONE", +"HONK", +"HOOD", +"HOOF", +"HOOK", +"HOOT", +"HORN", +"HOSE", +"HOST", +"HOUR", +"HOVE", +"HOWE", +"HOWL", +"HOYT", +"HUCK", +"HUED", +"HUFF", +"HUGE", +"HUGH", +"HUGO", +"HULK", +"HULL", +"HUNK", +"HUNT", +"HURD", +"HURL", +"HURT", +"HUSH", +"HYDE", +"HYMN", +"IBIS", +"ICON", +"IDEA", +"IDLE", +"IFFY", +"INCA", +"INCH", +"INTO", +"IONS", +"IOTA", +"IOWA", +"IRIS", +"IRMA", +"IRON", +"ISLE", +"ITCH", +"ITEM", +"IVAN", +"JACK", +"JADE", +"JAIL", +"JAKE", +"JANE", +"JAVA", +"JEAN", +"JEFF", +"JERK", +"JESS", +"JEST", +"JIBE", +"JILL", +"JILT", +"JIVE", +"JOAN", +"JOBS", +"JOCK", +"JOEL", +"JOEY", +"JOHN", +"JOIN", +"JOKE", +"JOLT", +"JOVE", +"JUDD", +"JUDE", +"JUDO", +"JUDY", +"JUJU", +"JUKE", +"JULY", +"JUNE", +"JUNK", +"JUNO", +"JURY", +"JUST", +"JUTE", +"KAHN", +"KALE", +"KANE", +"KANT", +"KARL", +"KATE", +"KEEL", +"KEEN", +"KENO", +"KENT", +"KERN", +"KERR", +"KEYS", +"KICK", +"KILL", +"KIND", +"KING", +"KIRK", +"KISS", +"KITE", +"KLAN", +"KNEE", +"KNEW", +"KNIT", +"KNOB", +"KNOT", +"KNOW", +"KOCH", +"KONG", +"KUDO", +"KURD", +"KURT", +"KYLE", +"LACE", +"LACK", +"LACY", +"LADY", +"LAID", +"LAIN", +"LAIR", +"LAKE", +"LAMB", +"LAME", +"LAND", +"LANE", +"LANG", +"LARD", +"LARK", +"LASS", +"LAST", +"LATE", +"LAUD", +"LAVA", +"LAWN", +"LAWS", +"LAYS", +"LEAD", +"LEAF", +"LEAK", +"LEAN", +"LEAR", +"LEEK", +"LEER", +"LEFT", +"LEND", +"LENS", +"LENT", +"LEON", +"LESK", +"LESS", +"LEST", +"LETS", +"LIAR", +"LICE", +"LICK", +"LIED", +"LIEN", +"LIES", +"LIEU", +"LIFE", +"LIFT", +"LIKE", +"LILA", +"LILT", +"LILY", +"LIMA", +"LIMB", +"LIME", +"LIND", +"LINE", +"LINK", +"LINT", +"LION", +"LISA", +"LIST", +"LIVE", +"LOAD", +"LOAF", +"LOAM", +"LOAN", +"LOCK", +"LOFT", +"LOGE", +"LOIS", +"LOLA", +"LONE", +"LONG", +"LOOK", +"LOON", +"LOOT", +"LORD", +"LORE", +"LOSE", +"LOSS", +"LOST", +"LOUD", +"LOVE", +"LOWE", +"LUCK", +"LUCY", +"LUGE", +"LUKE", +"LULU", +"LUND", +"LUNG", +"LURA", +"LURE", +"LURK", +"LUSH", +"LUST", +"LYLE", +"LYNN", +"LYON", +"LYRA", +"MACE", +"MADE", +"MAGI", +"MAID", +"MAIL", +"MAIN", +"MAKE", +"MALE", +"MALI", +"MALL", +"MALT", +"MANA", +"MANN", +"MANY", +"MARC", +"MARE", +"MARK", +"MARS", +"MART", +"MARY", +"MASH", +"MASK", +"MASS", +"MAST", +"MATE", +"MATH", +"MAUL", +"MAYO", +"MEAD", +"MEAL", +"MEAN", +"MEAT", +"MEEK", +"MEET", +"MELD", +"MELT", +"MEMO", +"MEND", +"MENU", +"MERT", +"MESH", +"MESS", +"MICE", +"MIKE", +"MILD", +"MILE", +"MILK", +"MILL", +"MILT", +"MIMI", +"MIND", +"MINE", +"MINI", +"MINK", +"MINT", +"MIRE", +"MISS", +"MIST", +"MITE", +"MITT", +"MOAN", +"MOAT", +"MOCK", +"MODE", +"MOLD", +"MOLE", +"MOLL", +"MOLT", +"MONA", +"MONK", +"MONT", +"MOOD", +"MOON", +"MOOR", +"MOOT", +"MORE", +"MORN", +"MORT", +"MOSS", +"MOST", +"MOTH", +"MOVE", +"MUCH", +"MUCK", +"MUDD", +"MUFF", +"MULE", +"MULL", +"MURK", +"MUSH", +"MUST", +"MUTE", +"MUTT", +"MYRA", +"MYTH", +"NAGY", +"NAIL", +"NAIR", +"NAME", +"NARY", +"NASH", +"NAVE", +"NAVY", +"NEAL", +"NEAR", +"NEAT", +"NECK", +"NEED", +"NEIL", +"NELL", +"NEON", +"NERO", +"NESS", +"NEST", +"NEWS", +"NEWT", +"NIBS", +"NICE", +"NICK", +"NILE", +"NINA", +"NINE", +"NOAH", +"NODE", +"NOEL", +"NOLL", +"NONE", +"NOOK", +"NOON", +"NORM", +"NOSE", +"NOTE", +"NOUN", +"NOVA", +"NUDE", +"NULL", +"NUMB", +"OATH", +"OBEY", +"OBOE", +"ODIN", +"OHIO", +"OILY", +"OINT", +"OKAY", +"OLAF", +"OLDY", +"OLGA", +"OLIN", +"OMAN", +"OMEN", +"OMIT", +"ONCE", +"ONES", +"ONLY", +"ONTO", +"ONUS", +"ORAL", +"ORGY", +"OSLO", +"OTIS", +"OTTO", +"OUCH", +"OUST", +"OUTS", +"OVAL", +"OVEN", +"OVER", +"OWLY", +"OWNS", +"QUAD", +"QUIT", +"QUOD", +"RACE", +"RACK", +"RACY", +"RAFT", +"RAGE", +"RAID", +"RAIL", +"RAIN", +"RAKE", +"RANK", +"RANT", +"RARE", +"RASH", +"RATE", +"RAVE", +"RAYS", +"READ", +"REAL", +"REAM", +"REAR", +"RECK", +"REED", +"REEF", +"REEK", +"REEL", +"REID", +"REIN", +"RENA", +"REND", +"RENT", +"REST", +"RICE", +"RICH", +"RICK", +"RIDE", +"RIFT", +"RILL", +"RIME", +"RING", +"RINK", +"RISE", +"RISK", +"RITE", +"ROAD", +"ROAM", +"ROAR", +"ROBE", +"ROCK", +"RODE", +"ROIL", +"ROLL", +"ROME", +"ROOD", +"ROOF", +"ROOK", +"ROOM", +"ROOT", +"ROSA", +"ROSE", +"ROSS", +"ROSY", +"ROTH", +"ROUT", +"ROVE", +"ROWE", +"ROWS", +"RUBE", +"RUBY", +"RUDE", +"RUDY", +"RUIN", +"RULE", +"RUNG", +"RUNS", +"RUNT", +"RUSE", +"RUSH", +"RUSK", +"RUSS", +"RUST", +"RUTH", +"SACK", +"SAFE", +"SAGE", +"SAID", +"SAIL", +"SALE", +"SALK", +"SALT", +"SAME", +"SAND", +"SANE", +"SANG", +"SANK", +"SARA", +"SAUL", +"SAVE", +"SAYS", +"SCAN", +"SCAR", +"SCAT", +"SCOT", +"SEAL", +"SEAM", +"SEAR", +"SEAT", +"SEED", +"SEEK", +"SEEM", +"SEEN", +"SEES", +"SELF", +"SELL", +"SEND", +"SENT", +"SETS", +"SEWN", +"SHAG", +"SHAM", +"SHAW", +"SHAY", +"SHED", +"SHIM", +"SHIN", +"SHOD", +"SHOE", +"SHOT", +"SHOW", +"SHUN", +"SHUT", +"SICK", +"SIDE", +"SIFT", +"SIGH", +"SIGN", +"SILK", +"SILL", +"SILO", +"SILT", +"SINE", +"SING", +"SINK", +"SIRE", +"SITE", +"SITS", +"SITU", +"SKAT", +"SKEW", +"SKID", +"SKIM", +"SKIN", +"SKIT", +"SLAB", +"SLAM", +"SLAT", +"SLAY", +"SLED", +"SLEW", +"SLID", +"SLIM", +"SLIT", +"SLOB", +"SLOG", +"SLOT", +"SLOW", +"SLUG", +"SLUM", +"SLUR", +"SMOG", +"SMUG", +"SNAG", +"SNOB", +"SNOW", +"SNUB", +"SNUG", +"SOAK", +"SOAR", +"SOCK", +"SODA", +"SOFA", +"SOFT", +"SOIL", +"SOLD", +"SOME", +"SONG", +"SOON", +"SOOT", +"SORE", +"SORT", +"SOUL", +"SOUR", +"SOWN", +"STAB", +"STAG", +"STAN", +"STAR", +"STAY", +"STEM", +"STEW", +"STIR", +"STOW", +"STUB", +"STUN", +"SUCH", +"SUDS", +"SUIT", +"SULK", +"SUMS", +"SUNG", +"SUNK", +"SURE", +"SURF", +"SWAB", +"SWAG", +"SWAM", +"SWAN", +"SWAT", +"SWAY", +"SWIM", +"SWUM", +"TACK", +"TACT", +"TAIL", +"TAKE", +"TALE", +"TALK", +"TALL", +"TANK", +"TASK", +"TATE", +"TAUT", +"TEAL", +"TEAM", +"TEAR", +"TECH", +"TEEM", +"TEEN", +"TEET", +"TELL", +"TEND", +"TENT", +"TERM", +"TERN", +"TESS", +"TEST", +"THAN", +"THAT", +"THEE", +"THEM", +"THEN", +"THEY", +"THIN", +"THIS", +"THUD", +"THUG", +"TICK", +"TIDE", +"TIDY", +"TIED", +"TIER", +"TILE", +"TILL", +"TILT", +"TIME", +"TINA", +"TINE", +"TINT", +"TINY", +"TIRE", +"TOAD", +"TOGO", +"TOIL", +"TOLD", +"TOLL", +"TONE", +"TONG", +"TONY", +"TOOK", +"TOOL", +"TOOT", +"TORE", +"TORN", +"TOTE", +"TOUR", +"TOUT", +"TOWN", +"TRAG", +"TRAM", +"TRAY", +"TREE", +"TREK", +"TRIG", +"TRIM", +"TRIO", +"TROD", +"TROT", +"TROY", +"TRUE", +"TUBA", +"TUBE", +"TUCK", +"TUFT", +"TUNA", +"TUNE", +"TUNG", +"TURF", +"TURN", +"TUSK", +"TWIG", +"TWIN", +"TWIT", +"ULAN", +"UNIT", +"URGE", +"USED", +"USER", +"USES", +"UTAH", +"VAIL", +"VAIN", +"VALE", +"VARY", +"VASE", +"VAST", +"VEAL", +"VEDA", +"VEIL", +"VEIN", +"VEND", +"VENT", +"VERB", +"VERY", +"VETO", +"VICE", +"VIEW", +"VINE", +"VISE", +"VOID", +"VOLT", +"VOTE", +"WACK", +"WADE", +"WAGE", +"WAIL", +"WAIT", +"WAKE", +"WALE", +"WALK", +"WALL", +"WALT", +"WAND", +"WANE", +"WANG", +"WANT", +"WARD", +"WARM", +"WARN", +"WART", +"WASH", +"WAST", +"WATS", +"WATT", +"WAVE", +"WAVY", +"WAYS", +"WEAK", +"WEAL", +"WEAN", +"WEAR", +"WEED", +"WEEK", +"WEIR", +"WELD", +"WELL", +"WELT", +"WENT", +"WERE", +"WERT", +"WEST", +"WHAM", +"WHAT", +"WHEE", +"WHEN", +"WHET", +"WHOA", +"WHOM", +"WICK", +"WIFE", +"WILD", +"WILL", +"WIND", +"WINE", +"WING", +"WINK", +"WINO", +"WIRE", +"WISE", +"WISH", +"WITH", +"WOLF", +"WONT", +"WOOD", +"WOOL", +"WORD", +"WORE", +"WORK", +"WORM", +"WORN", +"WOVE", +"WRIT", +"WYNN", +"YALE", +"YANG", +"YANK", +"YARD", +"YARN", +"YAWL", +"YAWN", +"YEAH", +"YEAR", +"YELL", +"YOGA", +"YOKE" +}; + +/* Encode 8 bytes in 'c' as a string of English words. + * Returns a pointer to a static buffer + */ +char * +btoe(engout,c) +char *c, *engout; +{ + char cp[9]; /* add in room for the parity 2 bits*/ + int p,i ; + + engout[0] = '\0'; + memcpy(cp, c,8); + /* compute parity */ + for(p = 0,i = 0; i < 64;i += 2) + p += extract(cp,i,2); + + cp[8] = (char)p << 6; + strncat(engout,&Wp[extract(cp, 0,11)][0],4); + strcat(engout," "); + strncat(engout,&Wp[extract(cp,11,11)][0],4); + strcat(engout," "); + strncat(engout,&Wp[extract(cp,22,11)][0],4); + strcat(engout," "); + strncat(engout,&Wp[extract(cp,33,11)][0],4); + strcat(engout," "); + strncat(engout,&Wp[extract(cp,44,11)][0],4); + strcat(engout," "); + strncat(engout,&Wp[extract(cp,55,11)][0],4); +#ifdef notdef + printf("engout is %s\n\r",engout); +#endif + return(engout); +} + +/* convert English to binary + * returns 1 OK - all good words and parity is OK + * 0 word not in data base + * -1 badly formed in put ie > 4 char word + * -2 words OK but parity is wrong + */ +int +etob(out, e) +char *out; +char *e; +{ + char *word, *cp; + int i, p, v,l, low,high; + char b[9]; + char input[36]; + + if(e == NULL) + return -1; + + strncpy(input,e,sizeof(input)); + cp = input; + memset(b, 0, sizeof(b)); + memset(out, 0, 8); + for(i=0,p=0;i<6;i++,p+=11){ + while ((word = strsep(&cp, " ")) != NULL && *word == '\0') + ; + if (word == NULL) + return -1; + l = strlen(word); + if(l > 4 || l < 1){ + return -1; + } else if(l < 4){ + low = 0; + high = 570; + } else { + low = 571; + high = 2047; + } + standard(word); + if( (v = wsrch(word,low,high)) < 0 ) + return 0; + insert(b,v,p,11); + } + + /* now check the parity of what we got */ + for(p = 0, i = 0; i < 64; i +=2) + p += extract(b, i, 2); + + if( (p & 3) != extract(b, 64,2) ) + return -2; + + memcpy(out,b,8); + + return 1; +} +/* Display 8 bytes as a series of 16-bit hex digits */ +char * +put8(out,s) +char *out; +char *s; +{ + sprintf(out,"%02X%02X %02X%02X %02X%02X %02X%02X", + s[0] & 0xff,s[1] & 0xff,s[2] & 0xff, + s[3] & 0xff,s[4] & 0xff,s[5] & 0xff, + s[6] & 0xff,s[7] & 0xff); + return out; +} +#ifdef notdef +/* Encode 8 bytes in 'cp' as stream of ascii letters. + * Provided as a possible alternative to btoe() + */ +char * +btoc(cp) +char *cp; +{ + int i; + static char out[31]; + + /* code out put by characters 6 bits each added to 0x21 (!)*/ + for(i=0;i <= 10;i++){ + /* last one is only 4 bits not 6*/ + out[i] = '!'+ extract(cp,6*i,i >= 10 ? 4:6); + } + out[i] = '\0'; + return(out); +} +#endif + +/* Internal subroutines for word encoding/decoding */ + +/* Dictionary binary search */ +static int +wsrch(w,low,high) +char *w; +int low, high; +{ + int i,j; + + for(;;){ + i = (low + high)/2; + if((j = strncmp(w,Wp[i],4)) == 0) + return i; /* Found it */ + if(high == low+1){ + /* Avoid effects of integer truncation in /2 */ + if(strncmp(w,Wp[high],4) == 0) + return high; + else + return -1; + } + if(low >= high) + return -1; /* I don't *think* this can happen...*/ + if(j < 0) + high = i; /* Search lower half */ + else + low = i; /* Search upper half */ + } +} +static void +insert(s, x, start, length) +char *s; +int x; +int start, length; +{ + unsigned char cl; + unsigned char cc; + unsigned char cr; + unsigned long y; + int shift; + + assert(length <= 11); + assert(start >= 0); + assert(length >= 0); + assert(start +length <= 66); + + shift = ((8 -(( start + length) % 8))%8); + y = (long) x << shift; + cl = (y >> 16) & 0xff; + cc = (y >> 8) & 0xff; + cr = y & 0xff; + if(shift + length > 16){ + s[start /8] |= cl; + s[start/8 +1] |= cc; + s[start/8 +2] |= cr; + } else if(shift +length > 8){ + s[start/8] |= cc; + s[start/8 + 1] |= cr; + } else { + s[start/8] |= cr; + } +} + +static void +standard(word) +register char *word; +{ + while(*word){ + if(!isascii(*word)) + break; + if(islower(*word)) + *word = toupper(*word); + if(*word == '1') + *word = 'L'; + if(*word == '0') + *word = 'O'; + if(*word == '5') + *word = 'S'; + word++; + } +} + +/* Extract 'length' bits from the char array 's' starting with bit 'start' */ +static unsigned long +extract(s, start, length) +char *s; +int start, length; +{ + unsigned char cl; + unsigned char cc; + unsigned char cr; + unsigned long x; + + assert(length <= 11); + assert(start >= 0); + assert(length >= 0); + assert(start +length <= 66); + + cl = s[start/8]; + cc = s[start/8 +1]; + cr = s[start/8 +2]; + x = ((long)(cl<<8 | cc) <<8 | cr) ; + x = x >> (24 - (length + (start %8))); + x =( x & (0xffff >> (16-length) ) ); + return(x); +} + diff --git a/lib/libskey/skey.1 b/lib/libskey/skey.1 new file mode 100644 index 0000000..b4e0455 --- /dev/null +++ b/lib/libskey/skey.1 @@ -0,0 +1,59 @@ +.ll 6i +.pl 10.5i +.\" @(#)skey.1 1.1 10/28/93 +.\" +.lt 6.0i +.TH KEY 1 "28 October 1993" +.AT 3 +.SH NAME +S/key \- A procedure to use one time passwords for accessing computer systems. +.SH DESCRIPTION +.I S/key +is a procedure for using one time password to authenticate access to +computer systems. It uses 64 bits of information transformed by the +MD4 algorithm. The user supplies the 64 bits in the form of 6 English +words that are generated by a secure computer. +Example use of the S/key program +.I key +.sp + Usage example: +.sp 0 + >key 99 th91334 +.sp 0 + Enter password: <your secret password is entered here> +.sp 0 + OMEN US HORN OMIT BACK AHOY +.sp 0 + > +.sp +The programs that are part of the S/Key system are keyinit, key, and +keyinfo. Keyinit is used to get your ID set up, key is +used to get the one time password each time, +keyinfo is used to extract information from the S/Key database. +.sp +When you run "keyinit" you inform the system of your +secret password. Running "key" then generates the +one-time passwords, and also requires your secret +password. If however, you misspell your password +while running "key", you will get a list of passwords +that will not work, and no indication about the problem. +.sp +Password sequence numbers count backward from 99. If you +don't know this, the syntax for "key" will be confusing. +.sp +You can enter the passwords using small letters, even +though the "key" program gives them in caps. +.sp +Macintosh and a general purpose PC use +are available. +.sp +Under FreeBSD, you can control, with /etc/skey.access, from which +hosts and/or networks the use of S/Key passwords is obligated. +.LP +.SH SEE ALSO +.BR keyinit(1), +.BR key(1), +.BR keyinfo(1) +.BR skey.access(5) +.SH AUTHOR +Phil Karn, Neil M. Haller, John S. Walden, Scott Chasin diff --git a/lib/libskey/skey.3 b/lib/libskey/skey.3 new file mode 100644 index 0000000..e8660d9 --- /dev/null +++ b/lib/libskey/skey.3 @@ -0,0 +1,156 @@ +.\" Copyright (c) 1996 +.\" David L. Nugent. All Rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY DAVID L. NUGENT AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL DAVID L. NUGENT OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $Id$ +.\" +.Dd December 22, 1996 +.Dt SKEY 3 +.Os +.Sh NAME +.Nm skeylookup , +.Nm skeyverify , +.Nm skeychallenge , +.Nm skeyinfo , +.Nm skeyaccess , +.Nm skey_getpass , +.Nm skey_crypt +.Nd Library routines for S/Key password control table access +.Sh SYNOPSIS +.Fd #include <skey.h> +.Ft int +.Fn skeylookup "struct skey *mp" "char *name" +.Ft int +.Fn skeyverify "struct skey *mp" "char *response" +.Ft int +.Fn skeychallenge "struct skey *mp" "char *name" "char *challenge" +.Ft int +.Fn skeyinfo "struct skey *mp" "char* name" "char *ss" +.Ft int +.Fn skeyaccess "char *user" "char *port" "char *host" "char *addr" +.Ft char * +.Fn skey_getpass "char *prompt" "struct passwd *pwd" "int pwok" +.Ft char * +.Fn skey_crypt "char *pp" "char *salt" "struct passwd *pwd" "int pwok" +.Sh DESCRIPTION +These routes support the S/Key one time password system used for +accessing computer systems. +See +.Xr skey 1 +for more information about the S/Key system itself. +.Pp +.Pp +.Fn skeylookup +finds an entry in the one-time password database. +On success (an entry is found corresponding to the given name), +they skey structure passed by the caller is filled and 0 is +returned, with the file read/write pointer positioned at the +beginning of the record found. +If no entry is found corresponding to the given name, the file +read/write pointer is positioned at end of file and the routine +returns 1. +If the database cannot be opened or an access error occurs, +.Fn skeylookup +returns -1. +.Pp +The +.Fn skeyinfo +function looks up skey info for user 'name'. +If successful, the caller's skey structure is filled and +.Fn skeyinfo +returns 0. +If an optional challenge string buffer is given, it is updated. +If unsuccessful (e.g. if the name is unknown, or the database +cannot be accessed) -1 is returned. +.Pp +.Fn skeychallenge +returns an skey challenge string for 'name'. +If successful, the caller's skey structure is filled, and +the function returns 0, with the file read/write pointer +left at the start of the record. +If unsuccessful (ie. the name was not found), the function +returns -1 and the database is closed. +.Pp +.Fn skeyverify +verifies a response to an s/key challenge. +If this function returns 0, the verify was successful and +the database was updated. +If 1 is returned, the verify failed and the database remains +unchanged. +If -1 is returned, some sort of error occurred with the database, +and the database is left unchanged. +The s/key database is always closed by this call. +.Pp +The +.Fn skey_getpass +function may be used to read regular or s/key passwords. +The prompt to use is passed to the function, along with the +full (secure) struct passwd for the user to be verified. +.Fn skey_getpass +uses the standard library getpass on the first attempt at +retrieving the user's password, and if that is blank, turns +echo back on and retrieves the S/Key password. +In either case, the entered string is returned back to the +caller. +.Pp +The +.Fn skey_crypt +is a wrapper function for the standard library +.Xr crypt 3 , +which returns the encrypted UNIX password if either the given +s/key or regular passwords are ok. +.Fn skey_crypt +first attempts verification of the given password via the skey +method, and will return the encrypted password from the +passwd structure if it can be verified, as though the user had +actually entered the correct UNIX password. +If s/key password verification does not work, then the password +is encrypted in the usual way and the result passed back to the +caller. +If the passwd structure pointer is NULL, +.Fn skey_crypt +returns a non-NULL string which could not possibly be a valid +UNIX password (namely, a string containing ":"). +.Pp +The +.Fn skeyaccess +function determines whether s/key passwords are permitted for any +combination of user name, group member, terminal port, host name or +network. +See +.Xr skey.access 5 +for more information on the layout and structure of the +skey.access configuration file which this function uses. +.Sh RETURN VALUES +See above. +.Sh SEE ALSO +.Xr skey 1 , +.Xr skey.access 5 +.Sh BUGS +No advisory locking is done on the s/key database to guard against +simultaneous access from multiple processes. +This is not normally a problem when keys are added to or updated +in the file, but may be problematic when keys are removed. +.Sh AUTHOR +Phil Karn, Neil M. Haller, John S. Walden, Scott Chasin + diff --git a/lib/libskey/skey.access.5 b/lib/libskey/skey.access.5 new file mode 100644 index 0000000..2e12ad1 --- /dev/null +++ b/lib/libskey/skey.access.5 @@ -0,0 +1,125 @@ +.TH SKEY.ACCESS 5 +.SH NAME +skey.access \- S/Key password control table +.SH DESCRIPTION +The S/Key password control table (\fI/etc/skey.access\fR) is used by +\fIlogin\fR-like programs to determine when UNIX passwords may be used +to access the system. +.IP \(bu +When the table does not exist, there are no password restrictions. The +user may enter the UNIX password or the S/Key one. +.IP \(bu +When the table does exist, UNIX passwords are permitted only when +explicitly specified. +.IP \(bu +For the sake of sanity, UNIX passwords are always permitted on the +systems console. +.SH "TABLE FORMAT" +The format of the table is one rule per line. Rules are matched in +order. The search terminates when the first matching rule is found, or +when the end of the table is reached. +.PP +Rules have the form: +.sp +.in +5 +permit condition condition... +.br +deny condition condition... +.in +.PP +where +.I permit +and +.I deny +may be followed by zero or more conditions. Comments begin with a `#\' +character, and extend through the end of the line. Empty lines or +lines with only comments are ignored. +.PP +A rule is matched when all conditions are satisfied. A rule without +conditions is always satisfied. For example, the last entry could +be a line with just the word +.I deny +on it. +.SH CONDITIONS +.IP "hostname wzv.win.tue.nl" +True when the login comes from host wzv.win.tue.nl. +See the WARNINGS section below. +.IP "internet 131.155.210.0 255.255.255.0" +True when the remote host has an internet address in network +131.155.210. The general form of a net/mask rule is: +.sp +.ti +5 +internet net mask +.sp +The expression is true when the host has an internet address for which +the bitwise and of +.I address +and +.I mask +equals +.IR net. +See the WARNINGS section below. +.IP "port ttya" +True when the login terminal is equal to +.IR /dev/ttya . +Remember that UNIX passwords are always permitted with logins on the +system console. +.IP "user uucp" +True when the user attempts to log in as +.IR uucp . +.IP "group wheel" +True when the user attempts to log in as a member of the +.I wheel +group. +.SH COMPATIBILITY +For the sake of backwards compatibility, the +.I internet +keyword may be omitted from net/mask patterns. +.SH WARNINGS +Several rule types depend on host name or address information obtained +through the network. What follows is a list of conceivable attacks to +force the system to permit UNIX passwords. +.IP "Host address spoofing (source routing)" +An intruder configures a local interface to an address in a trusted +network and connects to the victim using that source address. Given +the wrong client address, the victim draws the wrong conclusion from +rules based on host addresses or from rules based on host names derived +from addresses. +.sp +Remedies: (1) do not permit UNIX passwords with network logins; (2) +use network software that discards source routing information (e.g. +a tcp wrapper). +.PP +Almost every network server must look up the client host name using the +client network address. The next obvious attack therefore is: +.IP "Host name spoofing (bad PTR record)" +An intruder manipulates the name server system so that the client +network address resolves to the name of a trusted host. Given the +wrong host name, the victim draws the wrong conclusion from rules based +on host names, or from rules based on addresses derived from host +names. +.sp +Remedies: (1) do not permit UNIX passwords with network logins; (2) use +network software that verifies that the hostname resolves to the client +network address (e.g. a tcp wrapper). +.PP +Some applications, such as the UNIX login program, must look up the +client network address using the client host name. In addition to the +previous two attacks, this opens up yet another possibility: +.IP "Host address spoofing (extra A record)" +An intruder manipulates the name server system so that the client host +name (also) resolves to a trusted address. +.sp +Remedies: (1) do not permit UNIX passwords with network logins; (2) +the skeyaccess() routines ignore network addresses that appear to +belong to someone else. +.SH DIAGNOSTICS +Syntax errors are reported to the syslogd. When an error is found +the rule is skipped. +.SH FILES +/etc/skey.access, password control table +.SH AUTHOR +.nf +Wietse Venema +Eindhoven University of Technology +The Netherlands diff --git a/lib/libskey/skey.h b/lib/libskey/skey.h new file mode 100644 index 0000000..208d14d --- /dev/null +++ b/lib/libskey/skey.h @@ -0,0 +1,60 @@ +#ifndef _SKEY_H_ +#define _SKEY_H_ + +#include <sys/cdefs.h> + +/* Server-side data structure for reading keys file during login */ +struct skey { + FILE *keyfile; + char buf[256]; + char *logname; + int n; + char *seed; + char *val; + long recstart; /*needed so reread of buffer is efficient*/ +}; + +#ifdef _SKEY_INTERNAL +/* Client-side structure for scanning data stream for challenge */ +struct mc { + char buf[256]; + int skip; + int cnt; +}; + +#define atob8 _sk_atob8 +#define btoa8 _sk_btoa8 +#define btoe _sk_btoe +#define etob _sk_etob +#define f _sk_f +#define htoi _sk_htoi +#define keycrunch _sk_keycrunch +#define put8 _sk_put8 +#define readpass _sk_readpass +#define rip _sk_rip +#define sevenbit _sk_sevenbit + +void f __P((char *x)); +int keycrunch __P((char *result,char *seed,char *passwd)); +char *btoe __P((char *engout,char *c)); +char *put8 __P((char *out,char *s)); +int atob8 __P((char *out, char *in)); +int btoa8 __P((char *out, char *in)); +int htoi __P((char c)); +int etob __P((char *out,char *e)); +void sevenbit __P((char *s)); +char *readpass __P((char *buf, int n)); +void rip __P((char *buf)); +#endif /* _SKEY_INTERNAL */ + +/* Simplified application programming interface. */ +#include <pwd.h> +int skeylookup __P((struct skey *mp,char *name)); +int skeyverify __P((struct skey *mp,char *response)); +int skeychallenge __P((struct skey *mp,char *name, char *challenge)); +int skeyinfo __P((struct skey *mp, char* name, char *ss)); +int skeyaccess __P((char *user, char *port, char *host, char *addr)); +char *skey_getpass __P((char *prompt, struct passwd *pwd, int pwok)); +char *skey_crypt __P((char *pp, char *salt, struct passwd *pwd, int pwok)); + +#endif /* _SKEY_H_ */ diff --git a/lib/libskey/skey_crypt.c b/lib/libskey/skey_crypt.c new file mode 100644 index 0000000..79e5635 --- /dev/null +++ b/lib/libskey/skey_crypt.c @@ -0,0 +1,38 @@ +/* Author: Wietse Venema, Eindhoven University of Technology. */ + +#include <string.h> +#include <stdio.h> +#include <pwd.h> + +#include "skey.h" + +/* skey_crypt - return encrypted UNIX passwd if s/key or regular password ok */ + +char *skey_crypt(pp, salt, pwd, pwok) +char *pp; +char *salt; +struct passwd *pwd; +int pwok; +{ + struct skey skey; + char *p; + char *crypt(); + + /* Try s/key authentication even when the UNIX password is permitted. */ + + if (pwd != 0 && skeyinfo(&skey, pwd->pw_name, (char *) 0) == 0 + && skeyverify(&skey, pp) == 0) { + /* s/key authentication succeeded */ + return (pwd->pw_passwd); + } + + /* When s/key authentication does not work, always invoke crypt(). */ + + p = crypt(pp, salt); + if (pwok && pwd != 0 && strcmp(p, pwd->pw_passwd) == 0) + return (pwd->pw_passwd); + + /* The user does not exist or entered bad input. */ + + return (":"); +} diff --git a/lib/libskey/skey_getpass.c b/lib/libskey/skey_getpass.c new file mode 100644 index 0000000..9878a5e --- /dev/null +++ b/lib/libskey/skey_getpass.c @@ -0,0 +1,37 @@ +#include <unistd.h> +#include <stdio.h> +#include <skey.h> + +/* skey_getpass - read regular or s/key password */ + +char *skey_getpass(prompt, pwd, pwok) +char *prompt; +struct passwd *pwd; +int pwok; +{ + static char buf[128]; + struct skey skey; + char *pass; + int sflag; + + /* Attempt an s/key challenge. */ + sflag = (pwd == NULL || skeyinfo(&skey, pwd->pw_name, buf)); + if (!sflag) { + printf("%s\n", buf); + if (!pwok) + printf("(s/key required)\n"); + } + + pass = getpass(prompt); + + /* Give S/Key users a chance to do it with echo on. */ + if (!sflag && !feof(stdin) && *pass == '\0') { + fputs(" (turning echo on)\n", stdout); + fputs(prompt, stdout); + fflush(stdout); + fgets(buf, sizeof(buf), stdin); + rip(buf); + return (buf); + } else + return (pass); +} diff --git a/lib/libskey/skeyaccess.c b/lib/libskey/skeyaccess.c new file mode 100644 index 0000000..0d52caf --- /dev/null +++ b/lib/libskey/skeyaccess.c @@ -0,0 +1,485 @@ + /* + * Figure out if UNIX passwords are permitted for any combination of user + * name, group member, terminal port, host_name or network: + * + * Programmatic interface: skeyaccess(user, port, host, addr) + * + * All arguments are null-terminated strings. Specify a null character pointer + * where information is not available. + * + * When no address information is given this code performs the host (internet) + * address lookup itself. It rejects addresses that appear to belong to + * someone else. + * + * When compiled with -DPERMIT_CONSOLE always permits UNIX passwords with + * console logins, no matter what the configuration file says. + * + * To build a stand-alone test version, compile with -DTEST and run it off an + * skey.access file in the current directory: + * + * Command-line interface: ./skeyaccess user port [host_or_ip_addr] + * + * Errors are reported via syslogd. + * + * Author: Wietse Venema, Eindhoven University of Technology. + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <string.h> +#include <netdb.h> +#include <arpa/inet.h> +#include <stdio.h> +#include <grp.h> +#include <ctype.h> +#include <syslog.h> +#include <unistd.h> +#include <stdlib.h> +#include <sys/param.h> + +#include "pathnames.h" + + /* + * Token input with one-deep pushback. + */ +static char *prev_token = 0; /* push-back buffer */ +static char *line_pointer = NULL; +static char *first_token(); +static int line_number; +static void unget_token(); +static char *get_token(); +static char *need_token(); +static char *need_internet_addr(); + + /* + * Various forms of token matching. + */ +#define match_host_name(l) match_token((l)->host_name) +#define match_port(l) match_token((l)->port) +#define match_user(l) match_token((l)->user) +static int match_internet_addr(); +static int match_group(); +static int match_token(); +static int is_internet_addr(); +static struct in_addr *convert_internet_addr(); +static struct in_addr *lookup_internet_addr(); + +#define MAX_ADDR 32 +#define PERMIT 1 +#define DENY 0 + +#ifndef CONSOLE +#define CONSOLE "console" +#endif +#ifndef VTY_PREFIX +#define VTY_PREFIX "ttyv" +#endif + +struct login_info { + char *host_name; /* host name */ + struct in_addr *internet_addr; /* null terminated list */ + char *user; /* user name */ + char *port; /* login port */ +}; + +static int _skeyaccess __P(( FILE *, struct login_info * )); + +/* skeyaccess - find out if UNIX passwords are permitted */ + +int skeyaccess(user, port, host, addr) +char *user; +char *port; +char *host; +char *addr; +{ + FILE *fp; + struct login_info login_info; + int result; + + /* + * Assume no restriction on the use of UNIX passwords when the s/key + * acces table does not exist. + */ + if ((fp = fopen(_PATH_SKEYACCESS, "r")) == 0) { +#ifdef TEST + fprintf(stderr, "No file %s, thus no access control\n", _PATH_SKEYACCESS); +#endif + return (PERMIT); + } + + /* + * Bundle up the arguments in a structure so we won't have to drag around + * boring long argument lists. + * + * Look up the host address when only the name is given. We try to reject + * addresses that belong to someone else. + */ + login_info.user = user; + login_info.port = port; + + if (host != 0 && !is_internet_addr(host)) { + login_info.host_name = host; + } else { + login_info.host_name = 0; + } + + if (addr != 0 && is_internet_addr(addr)) { + login_info.internet_addr = convert_internet_addr(addr); + } else if (host != 0) { + if (is_internet_addr(host)) { + login_info.internet_addr = convert_internet_addr(host); + } else { + login_info.internet_addr = lookup_internet_addr(host); + } + } else { + login_info.internet_addr = 0; + } + + /* + * Print what we think the user wants us to do. + */ +#ifdef TEST + printf("port: %s\n", login_info.port); + printf("user: %s\n", login_info.user); + printf("host: %s\n", login_info.host_name ? login_info.host_name : "none"); + printf("addr: "); + if (login_info.internet_addr == 0) { + printf("none\n"); + } else { + int i; + + for (i = 0; login_info.internet_addr[i].s_addr; i++) + printf("%s%s", login_info.internet_addr[i].s_addr == -1 ? + "(see error log)" : inet_ntoa(login_info.internet_addr[i]), + login_info.internet_addr[i + 1].s_addr ? " " : "\n"); + } +#endif + result = _skeyaccess(fp, &login_info); + fclose(fp); + return (result); +} + +/* _skeyaccess - find out if UNIX passwords are permitted */ + +static int _skeyaccess(fp, login_info) +FILE *fp; +struct login_info *login_info; +{ + char buf[BUFSIZ]; + char *tok; + int match; + int permission=DENY; + +#ifdef PERMIT_CONSOLE + if (login_info->port != 0 && + (strcmp(login_info->port, CONSOLE) == 0 || + strncmp(login_info->port, VTY_PREFIX, sizeof(VTY_PREFIX) - 1) == 0 + ) + ) + return (1); +#endif + + /* + * Scan the s/key access table until we find an entry that matches. If no + * match is found, assume that UNIX passwords are disallowed. + */ + match = 0; + while (match == 0 && (tok = first_token(buf, sizeof(buf), fp))) { + if (strncasecmp(tok, "permit", 4) == 0) { + permission = PERMIT; + } else if (strncasecmp(tok, "deny", 4) == 0) { + permission = DENY; + } else { + syslog(LOG_ERR, "%s: line %d: bad permission: %s", + _PATH_SKEYACCESS, line_number, tok); + continue; /* error */ + } + + /* + * Process all conditions in this entry until we find one that fails. + */ + match = 1; + while (match != 0 && (tok = get_token())) { + if (strcasecmp(tok, "hostname") == 0) { + match = match_host_name(login_info); + } else if (strcasecmp(tok, "port") == 0) { + match = match_port(login_info); + } else if (strcasecmp(tok, "user") == 0) { + match = match_user(login_info); + } else if (strcasecmp(tok, "group") == 0) { + match = match_group(login_info); + } else if (strcasecmp(tok, "internet") == 0) { + match = match_internet_addr(login_info); + } else if (is_internet_addr(tok)) { + unget_token(tok); + match = match_internet_addr(login_info); + } else { + syslog(LOG_ERR, "%s: line %d: bad condition: %s", + _PATH_SKEYACCESS, line_number, tok); + match = 0; + } + } + } + return (match ? permission : DENY); +} + +/* match_internet_addr - match internet network address */ + +static int match_internet_addr(login_info) +struct login_info *login_info; +{ + char *tok; + long pattern; + long mask; + struct in_addr *addrp; + + if (login_info->internet_addr == 0) + return (0); + if ((tok = need_internet_addr()) == 0) + return (0); + pattern = inet_addr(tok); + if ((tok = need_internet_addr()) == 0) + return (0); + mask = inet_addr(tok); + + /* + * See if any of the addresses matches a pattern in the control file. We + * have already tried to drop addresses that belong to someone else. + */ + + for (addrp = login_info->internet_addr; addrp->s_addr; addrp++) + if (addrp->s_addr != -1 && (addrp->s_addr & mask) == pattern) + return (1); + return (0); +} + +/* match_group - match username against group */ + +static int match_group(login_info) +struct login_info *login_info; +{ + struct group *group; + char *tok; + char **memp; + + if ((tok = need_token()) && (group = getgrnam(tok))) { + for (memp = group->gr_mem; *memp; memp++) + if (strcmp(login_info->user, *memp) == 0) + return (1); + } + return (0); /* XXX endgrent() */ +} + +/* match_token - get and match token */ + +static int match_token(str) +char *str; +{ + char *tok; + + return (str && (tok = need_token()) && strcasecmp(str, tok) == 0); +} + +/* first_token - read line and return first token */ + +static char *first_token(buf, len, fp) +char *buf; +int len; +FILE *fp; +{ + char *cp; + + prev_token = 0; + for (;;) { + if (fgets(buf, len, fp) == 0) + return (0); + line_number++; + buf[strcspn(buf, "\r\n#")] = 0; +#ifdef TEST + if (buf[0]) + printf("rule: %s\n", buf); +#endif + line_pointer = buf; + while ((cp = strsep(&line_pointer, " \t")) != NULL && *cp == '\0') + ; + if (cp != NULL) + return (cp); + } +} + +/* unget_token - push back last token */ + +static void unget_token(cp) +char *cp; +{ + prev_token = cp; +} + +/* get_token - retrieve next token from buffer */ + +static char *get_token() +{ + char *cp; + + if ( (cp = prev_token) ) { + prev_token = 0; + } else { + while ((cp = strsep(&line_pointer, " \t")) != NULL && *cp == '\0') + ; + } + return (cp); +} + +/* need_token - complain if next token is not available */ + +static char *need_token() +{ + char *cp; + + if ((cp = get_token()) == 0) + syslog(LOG_ERR, "%s: line %d: premature end of rule", + _PATH_SKEYACCESS, line_number); + return (cp); +} + +/* need_internet_addr - complain if next token is not an internet address */ + +static char *need_internet_addr() +{ + char *cp; + + if ((cp = get_token()) == 0) { + syslog(LOG_ERR, "%s: line %d: internet address expected", + _PATH_SKEYACCESS, line_number); + return (0); + } else if (!is_internet_addr(cp)) { + syslog(LOG_ERR, "%s: line %d: bad internet address: %s", + _PATH_SKEYACCESS, line_number, cp); + return (0); + } else { + return (cp); + } +} + +/* is_internet_addr - determine if string is a dotted quad decimal address */ + +static int is_internet_addr(str) +char *str; +{ + int in_run = 0; + int runs = 0; + + /* Count the number of runs of characters between the dots. */ + + while (*str) { + if (*str == '.') { + in_run = 0; + } else { + if (!isdigit(*str)) + return (0); + if (in_run == 0) { + in_run = 1; + runs++; + } + } + str++; + } + return (runs == 4); +} + +/* lookup_internet_addr - look up internet addresses with extreme prejudice */ + +static struct in_addr *lookup_internet_addr(host) +char *host; +{ + struct hostent *hp; + static struct in_addr list[MAX_ADDR + 1]; + char buf[MAXHOSTNAMELEN + 1]; + int length; + int i; + + if ((hp = gethostbyname(host)) == 0 || hp->h_addrtype != AF_INET) + return (0); + + /* + * Save a copy of the results before gethostbyaddr() clobbers them. + */ + + for (i = 0; i < MAX_ADDR && hp->h_addr_list[i]; i++) + memcpy((char *) &list[i], + hp->h_addr_list[i], hp->h_length); + list[i].s_addr = 0; + + strncpy(buf, hp->h_name, MAXHOSTNAMELEN); + buf[MAXHOSTNAMELEN] = 0; + length = hp->h_length; + + /* + * Wipe addresses that appear to belong to someone else. We will get + * false alarms when when the hostname comes from DNS, while its + * addresses are listed under different names in local databases. + */ +#define NEQ(x,y) (strcasecmp((x),(y)) != 0) +#define NEQ3(x,y,n) (strncasecmp((x),(y), (n)) != 0) + + while (--i >= 0) { + if ((hp = gethostbyaddr((char *) &list[i], length, AF_INET)) == 0) { + syslog(LOG_ERR, "address %s not registered for host %s", + inet_ntoa(list[i]), buf); + list[i].s_addr = -1; + } + if (NEQ(buf, hp->h_name) && NEQ3(buf, "localhost.", 10)) { + syslog(LOG_ERR, "address %s registered for host %s and %s", + inet_ntoa(list[i]), hp->h_name, buf); + list[i].s_addr = -1; + } + } + return (list); +} + +/* convert_internet_addr - convert string to internet address */ + +static struct in_addr *convert_internet_addr(string) +char *string; +{ + static struct in_addr list[2]; + + list[0].s_addr = inet_addr(string); + list[1].s_addr = 0; + return (list); +} + +#ifdef TEST + +main(argc, argv) +int argc; +char **argv; +{ + struct hostent *hp; + char host[MAXHOSTNAMELEN + 1]; + int verdict; + char *user; + char *port; + + if (argc != 3 && argc != 4) { + fprintf(stderr, "usage: %s user port [host_or_ip_address]\n", argv[0]); + exit(0); + } + if (_PATH_SKEYACCESS[0] != '/') + printf("Warning: this program uses control file: %s\n", KEYACCESS); + openlog("login", LOG_PID, LOG_AUTH); + + user = argv[1]; + port = argv[2]; + if (argv[3]) { + strncpy(host, (hp = gethostbyname(argv[3])) ? + hp->h_name : argv[3], MAXHOSTNAMELEN); + host[MAXHOSTNAMELEN] = 0; + } + verdict = skeyaccess(user, port, argv[3] ? host : (char *) 0, (char *) 0); + printf("UNIX passwords %spermitted\n", verdict ? "" : "NOT "); + return (0); +} + +#endif diff --git a/lib/libskey/skeylogin.c b/lib/libskey/skeylogin.c new file mode 100644 index 0000000..a90fac1 --- /dev/null +++ b/lib/libskey/skeylogin.c @@ -0,0 +1,342 @@ +/* Login code for S/KEY Authentication. S/KEY is a trademark + * of Bellcore. + * + * Mink is the former name of the S/KEY authentication system. + * Many references for mink may still be found in this program. + */ + +#include <sys/param.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/resource.h> + + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <time.h> +#include <errno.h> + +#include "skey.h" +#include "pathnames.h" + +static char *skipspace(); + +#define setpriority(x,y,z) /* nothing */ + +static char *month[12] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" +}; + +/* Look up skey info for user 'name'. If successful, fill in the caller's + * skey structure and return 0. If unsuccessful (e.g., if name is unknown) + * return -1. If an optional challenge string buffer is given, update it. + * + * The file read/write pointer is left at the start of the + * record. + */ +int +skeyinfo(mp,name,ss) +struct skey *mp; +char *name; +char *ss; +{ + int rval; + + rval = skeylookup(mp,name); + switch(rval){ + case -1: /* File error */ + return -1; + case 0: /* Lookup succeeded */ + if (ss != 0) { + sprintf(ss, "s/key %d %s",mp->n - 1,mp->seed); + fclose(mp->keyfile); + } + return 0; + case 1: /* User not found */ + fclose(mp->keyfile); + return -1; + } + return -1; /* Can't happen */ +} + +/* Return a skey challenge string for user 'name'. If successful, + * fill in the caller's skey structure and return 0. If unsuccessful + * (e.g., if name is unknown) return -1. + * + * The file read/write pointer is left at the start of the + * record. + */ +int +skeychallenge(mp,name, ss) +struct skey *mp; +char *name; +char *ss; +{ + int rval; + + rval = skeylookup(mp,name); + switch(rval){ + case -1: /* File error */ + return -1; + case 0: /* Lookup succeeded, issue challenge */ + sprintf(ss, "s/key %d %s",mp->n - 1,mp->seed); + return 0; + case 1: /* User not found */ + fclose(mp->keyfile); + return -1; + } + return -1; /* Can't happen */ +} + +/* Find an entry in the One-time Password database. + * Return codes: + * -1: error in opening database + * 0: entry found, file R/W pointer positioned at beginning of record + * 1: entry not found, file R/W pointer positioned at EOF + */ +int +skeylookup(mp,name) +struct skey *mp; +char *name; +{ + int found; + int len; + long recstart; + char *cp, *p; + struct stat statbuf; + mode_t oldmask; + + /* See if the _PATH_SKEYFILE exists, and create it if not */ + if(stat(_PATH_SKEYFILE,&statbuf) == -1 && errno == ENOENT){ + oldmask = umask(S_IRWXG|S_IRWXO); + mp->keyfile = fopen(_PATH_SKEYFILE,"w+"); + (void)umask(oldmask); + } else { + /* Otherwise open normally for update */ + mp->keyfile = fopen(_PATH_SKEYFILE,"r+"); + } + if(mp->keyfile == NULL) + return -1; + + /* Look up user name in database */ + len = strlen(name); + if( len > 8 ) len = 8; /* Added 8/2/91 - nmh */ + found = 0; + while(!feof(mp->keyfile)){ + recstart = ftell(mp->keyfile); + mp->recstart = recstart; + if(fgets(mp->buf,sizeof(mp->buf),mp->keyfile) != mp->buf){ + break; + } + rip(mp->buf); + if(mp->buf[0] == '#') + continue; /* Comment */ + p = mp->buf; + while ((cp = strsep(&p, " \t")) != NULL && *cp == '\0') + ; + if((mp->logname = cp) == NULL) + continue; + while ((cp = strsep(&p, " \t")) != NULL && *cp == '\0') + ; + if(cp == NULL) + continue; + mp->n = atoi(cp); + while ((cp = strsep(&p, " \t")) != NULL && *cp == '\0') + ; + if((mp->seed = cp) == NULL) + continue; + while ((cp = strsep(&p, " \t")) != NULL && *cp == '\0') + ; + if((mp->val = cp) == NULL) + continue; + if(strlen(mp->logname) == len + && strncmp(mp->logname,name,len) == 0){ + found = 1; + break; + } + } + if(found){ + fseek(mp->keyfile,recstart,0); + return 0; + } else + return 1; +} +/* Verify response to a s/key challenge. + * + * Return codes: + * -1: Error of some sort; database unchanged + * 0: Verify successful, database updated + * 1: Verify failed, database unchanged + * + * The database file is always closed by this call. + */ +int +skeyverify(mp,response) +struct skey *mp; +char *response; +{ + char key[8]; + char fkey[8]; + char filekey[8]; + time_t now; + struct tm *tm; + char tbuf[27], fbuf[20]; + char *cp, *p; + + time(&now); + tm = localtime(&now); +/* can't use %b here, because it can be in national form */ + strftime(fbuf, sizeof(fbuf), "%d,%Y %T", tm); + sprintf(tbuf, " %s %s", month[tm->tm_mon], fbuf); + + if(response == NULL){ + fclose(mp->keyfile); + return -1; + } + rip(response); + + /* Convert response to binary */ + if(etob(key,response) != 1 && atob8(key,response) != 0){ + /* Neither english words or ascii hex */ + fclose(mp->keyfile); + return -1; + } + + /* Compute fkey = f(key) */ + memcpy(fkey,key,sizeof(key)); + f(fkey); + /* in order to make the window of update as short as possible + we must do the comparison here and if OK write it back + other wise the same password can be used twice to get in + to the system + */ + + setpriority(PRIO_PROCESS, 0, -4); + + /* reread the file record NOW*/ + + fseek(mp->keyfile,mp->recstart,0); + if(fgets(mp->buf,sizeof(mp->buf),mp->keyfile) != mp->buf){ + setpriority(PRIO_PROCESS, 0, 0); + fclose(mp->keyfile); + return -1; + } + rip(mp->buf); + p = mp->buf; + while ((cp = strsep(&p, " \t")) != NULL && *cp == '\0') + ; + mp->logname = cp; + while ((cp = strsep(&p, " \t")) != NULL && *cp == '\0') + ; + while ((cp = strsep(&p, " \t")) != NULL && *cp == '\0') + ; + mp->seed = cp; + while ((cp = strsep(&p, " \t")) != NULL && *cp == '\0') + ; + mp->val = cp; + /* And convert file value to hex for comparison */ + atob8(filekey,mp->val); + + /* Do actual comparison */ + if(memcmp(filekey,fkey,8) != 0){ + /* Wrong response */ + setpriority(PRIO_PROCESS, 0, 0); + fclose(mp->keyfile); + return 1; + } + + /* Update key in database by overwriting entire record. Note + * that we must write exactly the same number of bytes as in + * the original record (note fixed width field for N) + */ + btoa8(mp->val,key); + mp->n--; + fseek(mp->keyfile,mp->recstart,0); + fprintf(mp->keyfile,"%s %04d %-16s %s %-21s\n",mp->logname,mp->n,mp->seed, + mp->val, tbuf); + + fclose(mp->keyfile); + + setpriority(PRIO_PROCESS, 0, 0); + return 0; +} + + +/* Convert 8-byte hex-ascii string to binary array + * Returns 0 on success, -1 on error + */ +int +atob8(out,in) +register char *out,*in; +{ + register int i; + register int val; + + if(in == NULL || out == NULL) + return -1; + + for(i=0;i<8;i++){ + if((in = skipspace(in)) == NULL) + return -1; + if((val = htoi(*in++)) == -1) + return -1; + *out = val << 4; + + if((in = skipspace(in)) == NULL) + return -1; + if((val = htoi(*in++)) == -1) + return -1; + *out++ |= val; + } + return 0; +} + +static +char * +skipspace(cp) +register char *cp; +{ + while(*cp == ' ' || *cp == '\t') + cp++; + + if(*cp == '\0') + return NULL; + else + return cp; +} + +/* Convert 8-byte binary array to hex-ascii string */ +int +btoa8(out,in) +register char *out,*in; +{ + register int i; + + if(in == NULL || out == NULL) + return -1; + + for(i=0;i<8;i++){ + sprintf(out,"%02x",*in++ & 0xff); + out += 2; + } + return 0; +} + + +/* Convert hex digit to binary integer */ +int +htoi(c) +register char c; +{ + if('0' <= c && c <= '9') + return c - '0'; + if('a' <= c && c <= 'f') + return 10 + c - 'a'; + if('A' <= c && c <= 'F') + return 10 + c - 'A'; + return -1; +} diff --git a/lib/libskey/skeysubr.c b/lib/libskey/skeysubr.c new file mode 100644 index 0000000..2bd344f --- /dev/null +++ b/lib/libskey/skeysubr.c @@ -0,0 +1,130 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <termios.h> +#include <signal.h> + +#include "skey.h" +#include "mdx.h" + +/* Crunch a key: + * concatenate the seed and the password, run through MDX and + * collapse to 64 bits. This is defined as the user's starting key. + */ +int +keycrunch(result,seed,passwd) +char *result; /* 8-byte result */ +char *seed; /* Seed, any length */ +char *passwd; /* Password, any length */ +{ + char *buf; + MDX_CTX md; + u_long results[4]; + unsigned int buflen; + + buflen = strlen(seed) + strlen(passwd); + if((buf = malloc(buflen+1)) == NULL) + return -1; + strcpy(buf,seed); + strcat(buf,passwd); + + /* Crunch the key through MD[45] */ + sevenbit(buf); + MDXInit(&md); + MDXUpdate(&md,(unsigned char *)buf,buflen); + MDXFinal((unsigned char *)results,&md); + free(buf); + + results[0] ^= results[2]; + results[1] ^= results[3]; + + memcpy(result,(char *)results,8); + + return 0; +} + +/* The one-way function f(). Takes 8 bytes and returns 8 bytes in place */ +void +f(x) +char *x; +{ + MDX_CTX md; + u_long results[4]; + + MDXInit(&md); + MDXUpdate(&md,(unsigned char *)x,8); + MDXFinal((unsigned char *)results,&md); + /* Fold 128 to 64 bits */ + results[0] ^= results[2]; + results[1] ^= results[3]; + + memcpy(x,(char *)results,8); +} + +/* Strip trailing cr/lf from a line of text */ +void +rip(buf) +char *buf; +{ + buf[strcspn(buf, "\r\n")] = 0; +} + +static struct termios saved_ttymode; + +static void interrupt(sig) +int sig; +{ + tcsetattr(0, TCSANOW, &saved_ttymode); + exit(1); +} + +char * +readpass(buf,n) +char *buf; +int n; +{ + struct termios noecho_ttymode; + void (*oldsig)(); + + /* Save normal line editing modes */ + tcgetattr(0, &saved_ttymode); + if ((oldsig = signal(SIGINT, SIG_IGN)) != SIG_IGN) + signal(SIGINT, interrupt); + + /* Turn off echoing */ + tcgetattr(0, &noecho_ttymode); + noecho_ttymode.c_lflag &= ~ECHO; + tcsetattr(0, TCSANOW, &noecho_ttymode); + fgets(buf,n,stdin); + rip(buf); + + /* Restore previous tty modes */ + tcsetattr(0, TCSANOW, &saved_ttymode); + if (oldsig != SIG_IGN) + signal(SIGINT, oldsig); + + /* + after the secret key is taken from the keyboard, the line feed is + written to standard error instead of standard output. That means that + anyone using the program from a terminal won't notice, but capturing + standard output will get the key words without a newline in front of + them. + */ + fprintf(stderr, "\n"); + fflush(stderr); + sevenbit(buf); + + return buf; +} + +void +sevenbit(s) +char *s; +{ + /* make sure there are only 7 bit code in the line*/ + while(*s){ + *s &= 0x7f; + s++; + } +} |