I have separately posted this to freebsd-security as it seemed relevant to both 
lists.

The blowfish crypt(3) mechanism supports the use of a "cost value" for password 
encryption.  The cost value is encoded into the encrypted password that is 
stored in master.passwd.  On OpenBSD, this cost value can be set in login.conf. 
 FreeBSD does not currently support the cost value.  The cost value is the 
base-2 logarithm of the number of rounds of encryption to use so 
rounds=1<<cost;  This functionality can be supported through modifications to 
/usr/bin/passwd (which actually means a change to PAM) or through modifications 
to libcrypt.

In order to patch /usr/bin/passwd, it must be modified to provide a specially 
formatted salt value for the encryption of new passwords.  Specifically, 
$2a$COST$ must be prepended to the generated salt value.  "2a" is the major and 
minor version for blowfish/bcrypt.  Again, this means changing PAM.
 
Since passwd should not have to keep up with any formatting requirements for 
any libcrypt mechanism, I modified libcrypt instead.

The diff is pasted below strictly for viewing, the uuencoded version is below 
that.  In libcrypt, I use getpwuid_r(getuid(), ...) to get a pwd structure for 
the current user.  Then, I use login_getpwclass() to return a login_cap_t 
structure and use login_getcapnum(...,"ln_rounds",...) to grab the value for 
ln_rounds in login.conf.  
 
The only drawback to this approach is that it grabs the entry for the current 
user rather than the user whose password is being changed.  Normally, root will 
have a higher cost value than normal users.  If root changes a user's password, 
the password will be encrypted with a higher cost than if the user changed it 
themselves.  This doesn't seem to be all that bad.
 
To support this patch, /etc/login.conf must include an entry of the form 
":ln_rounds=10:" and cap_mkdb must be run on /etc/login.conf to apply the 
change.  This is slightly different than the way this feature is turned on in 
OpenBSD.
 
The patch can be applied by:
 
cd /usr/src
patch < /path/to/libcrypt.patch
 
I have submitted a change request/PR for this so that it can be considered for 
commitment.  
 
At the moment, the patch is also on my website at:
 
http://www.mccd.edu/staff/alexanders/libcrypt.patch
http://www.mccd.edu/staff/alexanders/libcrypt.uu
 
My thanks to David Magda for pointing out to me the difference between the 
OpenBSD and FreeBSD implementations.
 
Enjoy.
 
Steven
 
 
 
[Details follow]
 
My system is:
 
FreeBSD kernel.wayside.com 5.3-RELEASE FreeBSD 5.3-RELEASE #6: Fri Dec 31 
19:48:24 PST 2004     [EMAIL PROTECTED]:/usr/src/sys/i386/compile/GENERIC  i386
 
 
diff -c ./secure/lib/libcrypt/crypt-blowfish.c 
./secure/lib/libcrypt-new/crypt-blowfish.c
*** ./secure/lib/libcrypt/crypt-blowfish.c Mon Jun  2 12:17:24 2003
--- ./secure/lib/libcrypt-new/crypt-blowfish.c Fri Jan  7 19:43:31 2005
***************
*** 55,60 ****
--- 55,63 ----
  #include <sys/types.h>
  #include <string.h>
  #include <pwd.h>
+ #include <libutil.h>
+ #include <login_cap.h>
+ 
  #include "blowfish.h"
  #include "crypt.h"
  
***************
*** 144,149 ****
--- 147,157 ----
   u_int8_t csalt[BCRYPT_MAXSALT];
   u_int32_t cdata[BCRYPT_BLOCKS];
   static const char     *magic = "$2a$04$";
+ 
+  struct passwd pw, *pwd;
+  char pwbuf[1024];
+ 
+  login_cap_t *lc;
                                     
    /* Defaults */
   minr = 'a';
***************
*** 193,198 ****
--- 201,238 ----
  
    /* Discard num rounds + "$" identifier */
    salt += 3;
+  }
+  else
+  {
+   /* We're crypting a new password.  We want to get the
+      ln_rounds value that is stored in login.conf
+      and use it to initialize the rounds value.  
+                    ln_rounds is the base 2 logarithm of the 
+      desired rounds value.  */
+   
+      if(getpwuid_r(getuid(), &pw, pwbuf, sizeof(pwbuf), &pwd) == 0)
+      {
+   if( (lc = login_getpwclass(pwd)) != NULL)
+     {
+              logr = (int)login_getcapnum(lc, "ln_rounds", logr, logr);
+       rounds = 1 << logr;
+       if(rounds < BCRYPT_MINROUNDS)
+       {
+    printf("ln_rounds in login.conf is too small\n");
+    return error;
+       }
+                 }
+   else
+   {
+       printf("could not look up capability\n");
+       return error;
+   }
+             }
+      else
+      {
+   printf("Could not look up current user %d\n", getuid());
+   return error;
+             }
   }
  
 
 
begin 644 libcrypt.patch
M9&EF9B`M8R`N+W-E8W5R92]L:6(O;&EB8W)Y<'0O8W)Y<'0M8FQO=V9I<[EMAIL PROTECTED]
M8R`N+W-E8W5R92]L:6(O;&EB8W)Y<'0M;F5W+V-R>7!T+6)L;W=F:7-H+F,*
M*BHJ("XO<V5C=7)E+VQI8B]L:6)C<GEP="]C<GEP="UB;&]W9FES:"YC"4UO
M;B!*=6X@(#(@,3(Z,3<Z,C0@,C`P,[EMAIL PROTECTED]<F4O;&EB+VQI8F-R
M>7!T+6YE=R]C<GEP="UB;&]W9FES:"YC"49R:2!*86X@(#<@,3DZ-#,Z,S$@
M,C`P-0HJ*BHJ*BHJ*BHJ*BHJ*BH**BHJ(#4U+#8P("HJ*BH*+2TM(#4U+#8S
M("TM+2T*("`C:6YC;'5D92`\<WES+W1Y<&[EMAIL PROTECTED]"B`@(VEN8VQU9&4@/'-T
M<FEN9RYH/@H@("-I;F-L=61E(#QP=V0N:#X**R`C:6YC;'5D92`\;&EB=71I
M;"YH/@HK("-I;F-L=61E(#QL;V=I;E]C87`N:#X**R`*("`C:6YC;'5D92`B
M8FQO=V9I<[EMAIL PROTECTED]:"(*("`C:6YC;'5D92`B8W)Y<'0N:"(*("`**BHJ*BHJ*BHJ
M*BHJ*BHJ"BHJ*B`Q-#0L,30Y("HJ*BH*+2TM(#$T-RPQ-3<@+2TM+0H@(`EU
M7VEN=#A?="!C<V%L=%M"0U)94%1?34%84T%,5%T["B`@"75?:6YT,S)?="!C
M9&%T85M"0U)94%1?0DQ/0TM373L*("`)<W1A=&EC(&-O;G-T(&-H87(@("`@
M("IM86=I8R`]("(D,F$D,#0D(CL**R`**R`)<W1R=6-T('!A<W-W9"!P=RP@
M*G!W9#L**R`)8VAA<B!P=V)U9ELQ,#(T73L**R`**R`);&]G:6Y?8V%P7W0@
M*FQC.PH@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@"B`@
M"0DO*B!$969A=6QT<R`J+PH@(`EM:6YR(#T@)V$G.PHJ*BHJ*BHJ*BHJ*BHJ
M*BH**BHJ(#$Y,RPQ.3@@[EMAIL PROTECTED]@,C`Q+#(S."`M+2TM"B`@"B`@"0DO
M*B!$:7-C87)D(&YU;2!R;W5N9',@*R`B)"(@:61E;G1I9FEE<B`J+PH@(`D)
M<V%L="`K/2`S.PHK(`E]"BL@"65L<V4**R`)>PHK(`D)[EMAIL PROTECTED]<[EMAIL 
PROTECTED])Y
M<'1I;F<@82!N97<@<&%S<W=O<F0N("!792!W86YT('1O(&=E="!T:&4**R`)
M"2`@(&QN7W)O=6YD<R!V86QU92!T:&%T(&ES('-T;W)E9"!I;B!L;V=I;BYC
M;VYF"BL@"0D@("!A;[EMAIL PROTECTED](&ET('1O(&EN:71I86QI>[EMAIL 
PROTECTED]&AE(')O=6YD
M<R!V86QU92X@(`HK("`@("`@("`@("`@("`@("`@("!L;E]R;W5N9',@:7,@
M=&AE(&)A<V4@,B!L;V=A<FET:&T@;[EMAIL PROTECTED]&AE(`HK(`D)("[EMAIL 
PROTECTED]&5S:7)E9"!R
M;W5N9',@=F%L=64N("`J+PHK(`D)"BL@"2`@("!I9BAG971P=W5I9%]R*&=E
M='5I9"@I+"`F<'<L('!W8G5F+"!S:7IE;V8H<'=B=68I+"`F<'=D*2`]/2`P
M*0HK(`D@("`@>PHK(`D):68H("AL8R`](&QO9VEN7V=E='!W8VQA<W,H<'=D
M*2D@([EMAIL PROTECTED],3"D**R`)("`)>PHK(`D@("`@("`@("`@("!L;V=R([EMAIL 
PROTECTED]&EN
M="EL;V=I;E]G971C87!N=6TH;&,L(")L;E]R;W5N9',B+"!L;V=R+"!L;V=R
M*3L**R`)"2`@("!R;W5N9',@/2`Q(#P\(&QO9W(["BL@"0D@("`@:68H<F]U
M;F1S([EMAIL PROTECTED])3E)/54Y$4RD**R`)"2`@("!["BL@"0D)<')I;G1F
M*")L;E]R;W5N9',@:6X@;&]G:6XN8V]N9B!I<R!T;V\@<VUA;&Q<;B(I.PHK
M(`D)"7)E='5R;B!E<G)O<CL**R`)"2`@("!]"BL@("`@("`@("`@("`@("`@
M('T**R`)"65L<V4**R`)"7L**R`)"2`@("!P<FEN=&8H(F-O=6QD(&YO="!L
M;V]K('5P(&-A<&%B:6QI='E<;B(I.PHK(`D)("`@(')E='5R;B!E<G)O<CL*
M*R`)"7T**R`@("`@("`@("`@("!]"BL@"2`@("!E;'-E"BL@"2`@("!["BL@
M"0EP<FEN=&8H(D-O=6QD(&YO="!L;V]K('5P(&-U<G)E;[EMAIL PROTECTED]<B`E9%QN
M([EMAIL PROTECTED]"DI.PHK(`D)<F5T=7)N(&5R<F]R.PHK("`@("`@("`@("`@
.('T*("`)?0H@(`H@(`H`
`
end

_______________________________________________
freebsd-hackers@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-hackers
To unsubscribe, send any mail to "[EMAIL PROTECTED]"

Reply via email to