summaryrefslogtreecommitdiffstats
path: root/lib/libskey
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libskey')
-rw-r--r--lib/libskey/Makefile18
-rw-r--r--lib/libskey/mdx.h19
-rw-r--r--lib/libskey/pathnames.h6
-rw-r--r--lib/libskey/put.c2292
-rw-r--r--lib/libskey/skey.159
-rw-r--r--lib/libskey/skey.3156
-rw-r--r--lib/libskey/skey.access.5125
-rw-r--r--lib/libskey/skey.h60
-rw-r--r--lib/libskey/skey_crypt.c38
-rw-r--r--lib/libskey/skey_getpass.c37
-rw-r--r--lib/libskey/skeyaccess.c485
-rw-r--r--lib/libskey/skeylogin.c342
-rw-r--r--lib/libskey/skeysubr.c130
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++;
+ }
+}
OpenPOWER on IntegriCloud