Index: head/lib/libskey/put.c =================================================================== --- head/lib/libskey/put.c (revision 40660) +++ head/lib/libskey/put.c (revision 40661) @@ -1,2293 +1,2293 @@ #include #include #include #include #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, v,l, low,high; unsigned int p; 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); + insert(b,v,(int)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); } Index: head/lib/libskey/skey.h =================================================================== --- head/lib/libskey/skey.h (revision 40660) +++ head/lib/libskey/skey.h (revision 40661) @@ -1,60 +1,60 @@ #ifndef _SKEY_H_ #define _SKEY_H_ #include /* 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,const char *seed,const 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 int skeylookup __P((struct skey *mp, const char *name)); int skeyverify __P((struct skey *mp, char *response)); int skeychallenge __P((struct skey *mp, const char *name, char *challenge)); int skeyinfo __P((struct skey *mp, const char* name, char *ss)); int skeyaccess __P((char *user, const char *port, const char *host, const char *addr)); char *skey_getpass __P((const char *prompt, struct passwd * pwd, int pwok)); -char *skey_crypt __P((char *pp, char *salt, struct passwd *pwd, int pwok)); +const char *skey_crypt __P((char *pp, char *salt, struct passwd *pwd, int pwok)); #endif /* _SKEY_H_ */ Index: head/lib/libskey/skey_crypt.c =================================================================== --- head/lib/libskey/skey_crypt.c (revision 40660) +++ head/lib/libskey/skey_crypt.c (revision 40661) @@ -1,38 +1,38 @@ /* Author: Wietse Venema, Eindhoven University of Technology. */ #include #include #include +#include #include "skey.h" /* skey_crypt - return encrypted UNIX passwd if s/key or regular password ok */ -char *skey_crypt(pp, salt, pwd, pwok) +const 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 (":"); } Index: head/lib/libskey/skeyaccess.c =================================================================== --- head/lib/libskey/skeyaccess.c (revision 40660) +++ head/lib/libskey/skeyaccess.c (revision 40661) @@ -1,485 +1,487 @@ /* * 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 #include #include #include #include #include #include #include #include #include #include #include #include #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 char *first_token __P((char *, int, FILE *)); static int line_number; -static void unget_token(); -static char *get_token(); -static char *need_token(); -static char *need_internet_addr(); +static void unget_token __P((char *)); +static char *get_token __P((void)); +static char *need_token __P((void)); +static char *need_internet_addr __P((void)); /* * 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(); +struct login_info; +static int match_internet_addr __P((struct login_info *)); +static int match_group __P((struct login_info *)); +static int match_token __P((char *)); +static int is_internet_addr __P((char *)); +static struct in_addr *convert_internet_addr __P((char *)); +static struct in_addr *lookup_internet_addr __P((char *)); #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 * )); +static int _skeyaccess __P((FILE *, struct login_info *)); +int skeyaccess __P((char *, char *, char *, char *)); /* 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; u_int32_t pattern; u_int32_t 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 != INADDR_NONE && (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); + hp->h_addr_list[i], (size_t)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; + list[i].s_addr = (u_int32_t) -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; + list[i].s_addr = (u_int32_t) -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 Index: head/lib/libskey/skeylogin.c =================================================================== --- head/lib/libskey/skeylogin.c (revision 40660) +++ head/lib/libskey/skeylogin.c (revision 40661) @@ -1,342 +1,342 @@ -/* Login code for S/KEY Authentication. S/KEY is a trademark +* 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 #include #include #include #include #include #include #include #include #include #include #include "skey.h" #include "pathnames.h" -static char *skipspace(); +static char *skipspace __P((char *)); #define setpriority(x,y,z) /* nothing */ -static char *month[12] = { +static const 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; const 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; const 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; const char *name; { int found; size_t len; long recstart = 0; 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); snprintf(tbuf, sizeof(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; } Index: head/lib/libskey/skeysubr.c =================================================================== --- head/lib/libskey/skeysubr.c (revision 40660) +++ head/lib/libskey/skeysubr.c (revision 40661) @@ -1,131 +1,133 @@ #include #include #include #include #include #include #include #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 */ const char *seed; /* Seed, any length */ const 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 __P((int)); + static void interrupt(sig) int sig; { tcsetattr(0, TCSANOW, &saved_ttymode); err(1, "interrupted by signal %s", sys_siglist[sig]); } char * readpass(buf,n) char *buf; int n; { struct termios noecho_ttymode; - void (*oldsig)(); + void (*oldsig) __P((int)); /* 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++; } }