From 04c9749ff0148ec8f73b150cec8bc2c094a5d31a Mon Sep 17 00:00:00 2001 From: Brian Feldman Date: Tue, 22 Aug 2000 02:15:54 +0000 Subject: [PATCH] Add working and easy crypt(3)-switching. Yes, we need a whole new API for crypt(3) by now. In any case: Add crypt_set_format(3) + documentation to -lcrypt. Add login_setcryptfmt(3) + documentation to -lutil. Support for switching crypt formats in passwd(8). Support for switching crypt formats in pw(8). The simple synopsis is: edit login.conf; add a passwd_format field set to "des" or "md5"; go nuts :) Reviewed by: peter --- include/unistd.h | 2 ++ lib/libcrypt/Makefile | 3 +- lib/libcrypt/crypt.3 | 51 ++++++++++++++++++++++++++----- lib/libcrypt/crypt.c | 57 ++++++++++++++++++++++++++++++----- lib/libcrypt/crypt.h | 1 - lib/libutil/Makefile | 6 +++- lib/libutil/login_cap.3 | 22 +++++++++++++- lib/libutil/login_cap.c | 13 ++++++++ lib/libutil/login_cap.h | 1 + secure/lib/libcrypt/Makefile | 1 + usr.bin/passwd/local_passwd.c | 21 +++++-------- usr.sbin/pw/Makefile | 4 +-- usr.sbin/pw/pw_user.c | 21 ++++++++++++- 13 files changed, 167 insertions(+), 36 deletions(-) diff --git a/include/unistd.h b/include/unistd.h index 45679e516f79..274c98d9b7d5 100644 --- a/include/unistd.h +++ b/include/unistd.h @@ -120,6 +120,8 @@ char *brk __P((const char *)); int chroot __P((const char *)); size_t confstr __P((int, char *, size_t)); char *crypt __P((const char *, const char *)); +const char *crypt_get_format __P((void)); +int crypt_set_format __P((const char *)); int des_cipher __P((const char *, char *, long, int)); int des_setkey __P((const char *key)); int encrypt __P((char *, int)); diff --git a/lib/libcrypt/Makefile b/lib/libcrypt/Makefile index 17c978ef6b70..1c54fa69caa3 100644 --- a/lib/libcrypt/Makefile +++ b/lib/libcrypt/Makefile @@ -17,9 +17,10 @@ SONAME= ${LCRYPTSO} .PATH: ${.CURDIR}/../libmd SRCS= crypt.c crypt-md5.c misc.c -STATICSRCS= md5c.c +STATICSRCS= md5c.c sha1c.c STATICOBJS= ${STATICSRCS:S/.c/.o/g} MAN3= crypt.3 +MLINKS= crypt.3 crypt_get_format.3 crypt.3 crypt_set_format.3 CFLAGS+= -I${.CURDIR}/../libmd CFLAGS+= -DLIBC_SCCS -Wall PRECIOUSLIB= yes diff --git a/lib/libcrypt/crypt.3 b/lib/libcrypt/crypt.3 index e9f98c155c35..81f626158142 100644 --- a/lib/libcrypt/crypt.3 +++ b/lib/libcrypt/crypt.3 @@ -43,6 +43,10 @@ .Fd #include .Ft char * .Fn crypt "const char *key" "const char *salt" +.Ft const char * +.Fn crypt_get_format "void" +.Ft int +.Fn crypt_set_format "const char *string" .Sh DESCRIPTION The .Fn crypt @@ -59,10 +63,12 @@ Currently these include the .Tn Data Encryption Standard (DES) , and .Tn MD5 . -The algorithm used will depend upon the format of the Salt--following -the Modular Crypt Format (MCF)--and if +The algorithm used will depend upon the format of the Salt (following +the Modular Crypt Format (MCF)), if .Tn DES -is installed or not. +is installed or not, and whether +.Fn crypt_set_format +has been called to change the default. .Pp The first argument to .Nm @@ -177,10 +183,15 @@ Other crypt formats may be easilly added. An example salt would be: .Ss "Traditional" crypt: .Pp The algorithm used will depend upon whether +.Fn crypt_set_format +has been called and whether .Tn DES -is installed or not. If it is, +is installed or not. If .Tn DES -will be used. Otherwise, the best algorithm is used, which is currently +is installed and +.Fn crypt_set_format +has not set the format to something else, it will be used. +Otherwise, the best algorithm is used, which is currently .\" .\" NOTICE: Also make sure to update this .\" @@ -188,6 +199,23 @@ MD5. .Pp How the salt is used will depend upon the algorithm for the hash. For best results, specify at least two characters of salt. +.Pp +The +.Fn crypt_get_format +function returns a constant string that represents the name of the +algorithm currently used. +Valid values are +.\" +.\" NOTICE: Also make sure to update this, too, as well +.\" +.Ql des +and +.Ql md5 . +.Pp +The +.Fn crypt_set_format +function sets the default encoding format according to the supplied +.Fa string . .Sh RETURN VALUES .Pp .Fn crypt @@ -195,6 +223,10 @@ returns a pointer to the encrypted value on success, and NULL on failure. Note: this is not a standard behaviour, AT&T .Fn crypt will always return a pointer to a string. +.Pp +.Fn crypt_set_format +will return 1 if the supplied encoding format was valid. +Otherwise, a value of 0 is returned. .Sh SEE ALSO .Xr login 1 , .Xr passwd 1 , @@ -206,7 +238,9 @@ The .Fn crypt function returns a pointer to static data, and subsequent calls to .Fn crypt -will modify the same data. +will modify the same data. Likewise, +.Fn crypt_set_format +modifies static data. .Sh HISTORY A rotor-based .Fn crypt @@ -230,6 +264,7 @@ Originally written by .An David Burren Aq davidb@werj.com.au , later additions and changes by .An Poul-henning Kamp , -.An Mark R V Murray -and +.An Mark R V Murray , .An Kris Kennaway . +and +.An Brian Feldman . diff --git a/lib/libcrypt/crypt.c b/lib/libcrypt/crypt.c index e040be1986ee..7a61b42fa284 100644 --- a/lib/libcrypt/crypt.c +++ b/lib/libcrypt/crypt.c @@ -34,14 +34,57 @@ static char rcsid[] = "$FreeBSD$"; #include #include "crypt.h" +static const struct { + const char *const name; + char *(*const func)(const char *, const char *); + const char *const magic; +} crypt_types[] = { + { + "des", + crypt_des, + NULL + }, + { + "md5", + crypt_md5, + "$1$" + }, + { + NULL, + NULL + } +}; + +static int crypt_type = 0; + +const char * +crypt_get_format(void) { + + return (crypt_types[crypt_type].name); +} + +int +crypt_set_format(char *type) { + int i; + + for (i = 0; i < sizeof(crypt_types) / sizeof(crypt_types[0]) - 1; i++) { + if (strcmp(type, crypt_types[i].name) == 0) { + crypt_type = i; + return (1); + } + } + return (0); +} + char * crypt(char *passwd, char *salt) { - if (!strncmp(salt, "$1$", 3)) - return crypt_md5(passwd, salt); -#ifdef NONEXPORTABLE_CRYPT - return crypt_des(passwd, salt); -#else - return crypt_md5(passwd, salt); -#endif + int i; + + for (i = 0; i < sizeof(crypt_types) / sizeof(crypt_types[0]) - 1; i++) { + if (crypt_types[i].magic != NULL && strncmp(salt, + crypt_types[i].magic, strlen(crypt_types[i].magic)) == 0) + return (crypt_types[i].func(passwd, salt)); + } + return (crypt_types[crypt_type].func(passwd, salt)); } diff --git a/lib/libcrypt/crypt.h b/lib/libcrypt/crypt.h index 8920986c2998..3544f896563d 100644 --- a/lib/libcrypt/crypt.h +++ b/lib/libcrypt/crypt.h @@ -29,7 +29,6 @@ /* magic sizes */ #define MD5_SIZE 16 -#define SHS_SIZE 20 char *crypt_des(const char *pw, const char *salt); char *crypt_md5(const char *pw, const char *salt); diff --git a/lib/libutil/Makefile b/lib/libutil/Makefile index 3b83b41e512c..9cc5ef531f9e 100644 --- a/lib/libutil/Makefile +++ b/lib/libutil/Makefile @@ -10,6 +10,10 @@ SRCS= login.c login_tty.c logout.c logwtmp.c pty.c setproctitle.c \ login_cap.c login_class.c login_auth.c login_times.c login_ok.c \ _secure_path.c uucplock.c property.c auth.c realhostname.c fparseln.c INCS= libutil.h login_cap.h + +LDADD+= -lcrypt +DPADD+= ${LIBCRYPT} + MAN3+= login.3 login_auth.3 login_tty.3 logout.3 logwtmp.3 pty.3 \ setproctitle.3 login_cap.3 login_class.3 login_times.3 login_ok.3 \ _secure_path.3 uucplock.3 property.3 auth.3 realhostname.3 \ @@ -25,7 +29,7 @@ MLINKS+=login_cap.3 login_getclassbyname.3 login_cap.3 login_close.3 \ login_cap.3 login_getstyle.3 login_cap.3 login_getcaptime.3 \ login_cap.3 login_getcapnum.3 login_cap.3 login_getcapsize.3 \ login_cap.3 login_getcapbool.3 login_cap.3 login_getpath.3 \ - login_cap.3 login_getpwclass.3 + login_cap.3 login_getpwclass.3 login_cap.3 login_setcryptfmt.3 MLINKS+=login_class.3 setusercontext.3 login_class.3 setclasscontext.3 \ login_class.3 setclassenvironment.3 login_class.3 setclassresources.3 MLINKS+=login_times.3 parse_lt.3 login_times.3 in_ltm.3 \ diff --git a/lib/libutil/login_cap.3 b/lib/libutil/login_cap.3 index 44ccd64941d0..4bdf54f3cd23 100644 --- a/lib/libutil/login_cap.3 +++ b/lib/libutil/login_cap.3 @@ -34,7 +34,8 @@ .Nm login_getclassbyname , .Nm login_getpwclass , .Nm login_getstyle , -.Nm login_getuserclass +.Nm login_getuserclass , +.Nm login_setcryptfmt .Nd functions for accessing the login class capabilities database. .Sh LIBRARY .Lb libutil @@ -67,6 +68,8 @@ .Fn login_getcapbool "login_cap_t *lc" "const char *cap" "int def" .Ft char * .Fn login_getstyle "login_cap_t *lc" "char *style" "const char *auth" +.Ft const char * +.Fn login_setcryptfmt "login_cap_t *lc" "const char *def" "const char *error" .Sh DESCRIPTION These functions represent a programming interface to the login classes database provided in @@ -396,8 +399,25 @@ the authentication method used for access to the system via the network, and standard methods via direct dialup or console logins, significantly reducing the risk of password discovery by "snooping" network packets. +.It Fn login_setcryptfmt +The +.Fn login_setcryptfmt +function is used to set the +.Xr crypt 3 +format using the +.Ql passwd_format +configuration entry. +If no entry is found, +.Fa def +is taken to be used as the fallback. +If calling +.Xr crypt_set_format 3 +on the specifier fails, +.Fa error +is returned to indicate this. .El .Sh SEE ALSO +.Xr crypt 3 , .Xr getcap 3 , .Xr login_class 3 , .Xr login.conf 5 , diff --git a/lib/libutil/login_cap.c b/lib/libutil/login_cap.c index b7528b99efc2..74103805f60f 100644 --- a/lib/libutil/login_cap.c +++ b/lib/libutil/login_cap.c @@ -798,3 +798,16 @@ login_getstyle(login_cap_t *lc, char *style, const char *auth) return lc->lc_style; } + +const char * +login_setcryptfmt(login_cap_t *lc, const char *def, const char *error) +{ + const char *cipher; + + cipher = login_getcapstr(lc, "passwd_format", def, NULL); + if (cipher == NULL) + return (error); + if (!crypt_set_format(cipher)) + return (error); + return (cipher); +} diff --git a/lib/libutil/login_cap.h b/lib/libutil/login_cap.h index f4b382519770..1320278e074a 100644 --- a/lib/libutil/login_cap.h +++ b/lib/libutil/login_cap.h @@ -110,6 +110,7 @@ rlim_t login_getcapnum __P((login_cap_t *, const char *, rlim_t, rlim_t)); rlim_t login_getcapsize __P((login_cap_t *, const char *, rlim_t, rlim_t)); char *login_getpath __P((login_cap_t *, const char *, char *)); int login_getcapbool __P((login_cap_t *, const char *, int)); +const char *login_setcryptfmt __P((login_cap_t *, const char *, const char *)); int setclasscontext __P((const char*, unsigned int)); int setusercontext __P((login_cap_t*, const struct passwd*, uid_t, unsigned int)); diff --git a/secure/lib/libcrypt/Makefile b/secure/lib/libcrypt/Makefile index 0721f5548cd1..b46df113346b 100644 --- a/secure/lib/libcrypt/Makefile +++ b/secure/lib/libcrypt/Makefile @@ -21,6 +21,7 @@ STATICSRCS= md5c.c STATICOBJS= ${STATICSRCS:S/.c/.o/g} SRCS+= crypt-des.c MAN3= crypt.3 +MLINKS= crypt.3 crypt_get_format.3 crypt.3 crypt_set_format.3 CFLAGS+= -I${.CURDIR}/../../../lib/libmd CFLAGS+= -I${.CURDIR}/../../../lib/libcrypt CFLAGS+= -DNONEXPORTABLE_CRYPT diff --git a/usr.bin/passwd/local_passwd.c b/usr.bin/passwd/local_passwd.c index 6508529bf253..e23968337b8b 100644 --- a/usr.bin/passwd/local_passwd.c +++ b/usr.bin/passwd/local_passwd.c @@ -172,20 +172,13 @@ getnewpasswd(pw, nis) #else /* Make a good size salt for algoritms that can use it. */ gettimeofday(&tv,0); - if (strncmp(pw->pw_passwd, "$1$", 3)) { - /* DES Salt */ - to64(&salt[0], random(), 3); - to64(&salt[3], tv.tv_usec, 3); - to64(&salt[6], tv.tv_sec, 2); - salt[8] = '\0'; - } - else { - /* MD5 Salt */ - strncpy(&salt[0], "$1$", 3); - to64(&salt[3], random(), 3); - to64(&salt[6], tv.tv_usec, 3); - salt[8] = '\0'; - } + if (login_setcryptfmt(lc, "md5", NULL) == NULL) + pw_error("cannot set password cipher", 1, 1); + /* Salt suitable for anything */ + to64(&salt[0], random(), 3); + to64(&salt[3], tv.tv_usec, 3); + to64(&salt[6], tv.tv_sec, 2); + salt[8] = '\0'; #endif return (crypt(buf, salt)); } diff --git a/usr.sbin/pw/Makefile b/usr.sbin/pw/Makefile index bee05ccd5502..bb82d3aa0fa3 100644 --- a/usr.sbin/pw/Makefile +++ b/usr.sbin/pw/Makefile @@ -11,8 +11,8 @@ MAN8= pw.8 #RND= -DUSE_MD5RAND CFLAGS+= -W -Wall $(CDB) $(RND) -LDADD= -lcrypt -DPADD= ${LIBCRYPT} +LDADD= -lcrypt -lutil +DPADD= ${LIBCRYPT} ${LIBUTIL} BINMODE=0555 diff --git a/usr.sbin/pw/pw_user.c b/usr.sbin/pw/pw_user.c index 2c491fdc8cfc..c4e66b4ec879 100644 --- a/usr.sbin/pw/pw_user.c +++ b/usr.sbin/pw/pw_user.c @@ -42,6 +42,7 @@ static const char rcsid[] = #include #include #include +#include #if defined(USE_MD5RAND) #include #endif @@ -544,11 +545,19 @@ pw_user(struct userconf * cnf, int mode, struct cargs * args) } if ((arg = getarg(args, 'w')) != NULL && getarg(args, 'h') == NULL) { + login_cap_t *lc; + + lc = login_getpwclass(pwd); + if (lc == NULL || + login_setcryptfmt(lc, "md5", NULL) == NULL) + warn("setting crypt(3) format"); + login_close(lc); pwd->pw_passwd = pw_password(cnf, args, pwd->pw_name); edited = 1; } } else { + login_cap_t *lc; /* * Add code @@ -565,13 +574,17 @@ pw_user(struct userconf * cnf, int mode, struct cargs * args) pwd = &fakeuser; pwd->pw_name = a_name->val; pwd->pw_class = cnf->default_class ? cnf->default_class : ""; - pwd->pw_passwd = pw_password(cnf, args, pwd->pw_name); pwd->pw_uid = pw_uidpolicy(cnf, args); pwd->pw_gid = pw_gidpolicy(cnf, args, pwd->pw_name, (gid_t) pwd->pw_uid); pwd->pw_change = pw_pwdpolicy(cnf, args); pwd->pw_expire = pw_exppolicy(cnf, args); pwd->pw_dir = pw_homepolicy(cnf, args, pwd->pw_name); pwd->pw_shell = pw_shellpolicy(cnf, args, NULL); + lc = login_getpwclass(pwd); + if (lc == NULL || login_setcryptfmt(lc, "md5", NULL) == NULL) + warn("setting crypt(3) format"); + login_close(lc); + pwd->pw_passwd = pw_password(cnf, args, pwd->pw_name); edited = 1; if (pwd->pw_uid == 0 && strcmp(pwd->pw_name, "root") != 0) @@ -600,6 +613,7 @@ pw_user(struct userconf * cnf, int mode, struct cargs * args) int b; int istty = isatty(fd); struct termios t; + login_cap_t *lc; if (istty) { if (tcgetattr(fd, &t) == -1) @@ -629,6 +643,11 @@ pw_user(struct userconf * cnf, int mode, struct cargs * args) *p = '\0'; if (!*line) errx(EX_DATAERR, "empty password read on file descriptor %d", fd); + lc = login_getpwclass(pwd); + if (lc == NULL || + login_setcryptfmt(lc, "md5", NULL) == NULL) + warn("setting crypt(3) format"); + login_close(lc); pwd->pw_passwd = pw_pwcrypt(line); edited = 1; }