Coming soon: OpenBSD images

So after having to (yet again) go to a secondary machine to install OpenBSD on a flash drive so I can install OpenBSD on a primary machine that lacks a disk drive(and floppy drive), I figured "you know, they should provide thumb drive images"

Well, THEY (the OpenBSD developers) don't believe it's necessary.. and don't recommend using third party generated USB images.. but here we are.

Soon to come will be a few OpenBSD images for various flash drive sizes. I plan on these sizes: (Note, these are still OpenBSD and not in any way branched or whatever. The Micro/Mini thing is just what I make the host name at install)

  1. MicroBSD. 500M. sets: bsd, bsd.rd, bsd.mp, base, etc, man
  2. MiniBSD. 1G. sets: bsd, bsd.rd, bsd.mp, base, etc, man, comp, games and a few packages preinstalled
  3. MiniBSDX. 1G. sets: all, no packages
  4. InstallBSD. 500M. sets: bsd, bsd.rd, base, etc. Includes install sets off of install_XX.iso

I plan on trying to build images for i386 and amd64 each official release and snapshot(but not more than once a month). If you want more then I suggest building your own USB image. It really isn't that hard.

My main goal of these images is

  1. Easy way to get dmesgs off of computers
  2. As a "rescue" disk. The ramdisk kernel is extremely limited. Having a full BSD installation is invaluable whenever you accidentally update fstab to use sd1a instead of sd0a... Sure there is always ed to fix it with the ramdisk kernel.. but ed is not trivial to use
  3. As a quick way to see if OpenBSD will work on your computer(especially at retail locations)
  4. As an easy way to test snapshots

These images are very simplisticly made. They are basically a default install with one-big / and a mfs /tmp. The only modifications I make are to the fstab and I add a reminder to change the root password. All private keys are generated on first boot, so no worries there.

The main annoying thing about doing these images is just uploading them. About 130M uploaded at 60kb/s on stupid DSL is awful.

Posted: 08/19/2011 05:02:09

New FSCAuth Licensing

Because of lack of demand for my beta testing of FSCAuth I've decided that I probably need to go a different approach. No one wants to blindly trust an authentication library, so I'm going to dual license it under GPL and commercial. This way everyone can see the source code and know that it's trust worthy, but also can pay for a (pretty cheap) commercial license to prevent people from having to open source their entire project.

I'll have source code uploaded in the next few days with the GPL license attached, so be on the look out for it.

Posted: 07/29/2011 04:11:55

FSCAuth Beta is now open!

I uploaded the doxygen documentation for FSCAuth 1.1-beta and now I'm saying I'm open for beta testing. The new documentation is here.

If you are interested in beta testing a new and intuitive authentication library for ASP.Net, please fill out this form detailing your beta request. The beta will end sometime in September 2011 (updated). All beta assemblies will work until December 1st, 2011. If you do get selected to beta test, then there are benefits in it for you! All beta testers that give me back feedback will receive a free 2 server license of the released version of FSCAuth. Note that all paid licenses include source code.

For more information about FSCAuth, please see these links:

Posted: 07/25/2011 02:48:37

BCrypt Support in FSCAuth

I've had to revamp quite a few things in this next release of FSCAuth to accommodate BCrypt, but overall, I think it makes things cleaner and flexible anyway.

So if you want to use BCrypt, it's pretty easy to do now. First off, a new change is that HasherInvoker is now a delegate used for computing hashes and it is now capable of "keeping track" of salts, such as is required for BCrypt. You could do it probably without converting BCrypt to a HashAlgorithm, but it's how I did it... so..

First, get the HashAlogrithm interface for BCrypt.Net: GalacticJello at StackOverflow kindly provided it for me.

Next, you just need a new HasherInvoker function for FSCAuth:

    static HashWithSalt BCryptHashHander(string plain, string salt)
    {
        var v=new HashWithSalt();
        BCryptHasher hash=new BCryptHasher();
        if(salt==null){
            v.Text=HashHelper.FromBytes(hash.ComputeHash(HashHelper.ToBytes(plain)));
            v.Salt=hash.Salt;
        }else{
            hash.Salt=salt;
            v.Text=HashHelper.FromBytes(hash.ComputeHash(HashHelper.ToBytes(plain)));
        }
        return v;
    }

Fairly simple at least. And then just assign it to Authentication:

Authentication.HasherInvoker = BCryptHashHander;

You could extend on this to put in a WorkFactor and other such things pretty easily as well. The only possible thing in FSCAuth to break it might be HashIterations being more than one. But for BCrypt, you should really only have this at 1 and increase the WorkFactor if you need it slower

BSD Licensed code :)

Copyright (c) 2011 Jordan "Earlz/hckr83" Earls http://lastyearswishes.com 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.
  3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED ``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 THE AUTHOR 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.

Posted: 07/24/2011 19:50:53

Abort, Retry or Ignore?

So I have long since known about Abort, Retry, Ignore, but I have never known why it is so wide spread in assorted Windows programs. I figured this out today while looking in some .Net code(which I'm assuming carries over from Win32)

The Debug.Assert method will cause this error, as does Trace.Assert. As you can see from the documentation there, Abort Retry Ignore comes from these methods. Abort ends the program, Retry will open a debugger if available, and Ignore will ignore the assertion.

So next time you see an Abort Retry Ignore message, just remember that the programmer probably didn't intend for you to see that, and right next to that line of code was //this won't ever happen... but just in case

Posted: 07/06/2011 20:02:08

New Look

Well, I got a new look thanks to Nate Ernst over at Varloo Design

I rather like the new look he gave. I got it by submitting a small little project to Weekend Hacker. I suggest everyone try it. It's pretty nifty.

Posted: 07/04/2011 22:04:26

New Computer

So I finally got my computer built. Basically, it's a beast. The OpenBSD dmesg is here. I prefer OpenBSD dmesgs to Linux dmesgs.

But anyway, it's running Arch Linux and utilizes a software RAID0 and RAID1 array across two harddrives. I put the RAID0 array mostly there for my virtual machines so that they'll be as fast as possible and Wow. I can boot Windows XP from a virtual machine and start Visual Studio in about 15 seconds. Booting just Windows XP takes 5 seconds. It's insanely fast. I didn't think a virtual machine could actually go so quick.

But yea, Project: Earlz-Zeta is definitely a success. Best $600 bucks I've ever spent.

Posted: 06/27/2011 04:42:10

Sup 86.122.189.166

So I've been recently attempted to be brute forced by the IP 86.122.189.166. The little fellow tried to login to root a good number of times. He has SSH enabled on his machine, so I've considered trying to do the same to him.. but instead, I'll just add an entry to hosts.deny and get on with my life

Posted: 06/23/2011 22:20:04

New Computer. Woot!

So I'm building my own computer.. and it's basically going to be hardcore.

All this awesome hardware goodness for a total of only $600, of which $11 is shipping. Of course, I do save quite a bit of money though for other reasons. I don't have to buy a license of Windows because I use Arch Linux and I don't have to buy a graphics card because I have an extra one. Of course, I'm a programmer, not a gamer though.

Except pictures soon! I'm hoping it comes in tomorrow, otherwise it won't be til Monday

Posted: 06/16/2011 17:57:46

SQL Server User Store for FSCAuth

Well, I finally got around to writing a UserStore utilizing SQL Server. I did it without an ORM.. which is annoying at best, but regardless, I'd say it gets the job done and is sorta easy to extend for your own UserData class. SQL doesn't play well with inheritance though. It's quite difficult to write an easy to extend data class without using an ORM

Anyway, here is the code:

namespace Earlz.FSCAuth.Extensions
{
    public class SqlServerUserStore : IUserStore
    {
        private static SqlServerUserStore instance;
        private SqlServerUserStore() {}

        public static SqlServerUserStore Instance
        {
          get 
          {
             if (instance == null)
             {
                instance = new SqlServerUserStore();
             }
             return instance;
          }
        }
        /// <summary>
        /// Will get a user by username or email address
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        virtual public UserData GetUserByName(string name)
        {
            using (var con=GetConnection())
            {
                con.Open();
                var cmd = new SqlCommand();
                cmd.CommandText="select * from users left join Groups on"+
                    " groups.UserID=users.ID where username=@name or "+
                    " emailaddress=@name";
                cmd.Connection = con;
                cmd.Parameters.Add(new SqlParameter("@name", name));
                return ReaderToUserData(cmd.ExecuteReader());
            }
        }

        virtual public bool UpdateUserByID(UserData user)
        {
            var old = GetUserByName(user.Username);
            if (old == null)
            {
                return false;
            }
            using (var con = GetConnection())
            {
                con.Open();
                var cmd = new SqlCommand();
                cmd.Connection = con;
                cmd.CommandText="";
                if (old.Groups.TrueForAll(x => user.Groups.Contains(x)))
                {
                    //update groups as well.
                    //we're just going to do it messy and drop all groups
                    //and add them back in.
                    cmd.CommandText = "delete from groups where userid=@userid;";
                    foreach (var g in user.Groups)
                    {
                        cmd.CommandText += "insert into groups (name,userid)"+
                        " values('" + g.Replace("'", "''") + "',@userid);";
                    }
                }
                cmd.CommandText += "update users set emailaddress=@email, username=@username,"+
                " salt=@salt, passwordhash=@password ";
                cmd.CommandText += "where id=@userid;";
                cmd.Parameters.Add(new SqlParameter("@userid", user.UniqueID));
                cmd.Parameters.Add(new SqlParameter("@email",user.EmailAddress ?? ""));
                cmd.Parameters.Add(new SqlParameter("@username",user.Username));
                cmd.Parameters.Add(new SqlParameter("@salt",user.Salt));
                cmd.Parameters.Add(new SqlParameter("@password",user.PasswordHash));
                if (cmd.ExecuteNonQuery() > 0)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }

        }

        virtual public bool AddUser(UserData user)
        {
            using(var con=GetConnection())
            {
                con.Open();
                var cmd = new SqlCommand();
                cmd.Connection = con;
                cmd.CommandText = "declare @userid as integer;";
                cmd.CommandText += "insert into users (username,emailaddress,passwordhash,salt)"+
                " values (@username,@email,@password,@salt);";
                cmd.CommandText += "set @userid=scope_identity();";
                foreach (var g in user.Groups)
                {
                    cmd.CommandText += "insert into groups (name,userid) values "+
                    "('" + g.Replace("'", "''") + "',@userid);";
                }
                cmd.CommandText += "select @userid;";
                cmd.Parameters.Add(new SqlParameter("@email",user.EmailAddress ?? ""));
                cmd.Parameters.Add(new SqlParameter("@username",user.Username));
                cmd.Parameters.Add(new SqlParameter("@salt",user.Salt ?? ""));
                cmd.Parameters.Add(new SqlParameter("@password", user.PasswordHash ?? ""));
                try
                {
                    user.UniqueID = ((int)cmd.ExecuteScalar()).ToString();
                    return true;
                }
                catch
                {
                    return false;
                }
            }
        }

        virtual public bool DeleteUserByID(UserData user)
        {
            using (var con = GetConnection())
            {
                con.Open();
                var cmd = new SqlCommand();
                cmd.CommandText = "delete from groups where userid=@userid; delete from users where id=@userid";
                cmd.Connection = con;
                cmd.Parameters.Add(new SqlParameter("@userid", int.Parse(user.UniqueID)));
                if (cmd.ExecuteNonQuery() > 0)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
        }
        virtual protected UserData ReaderToUserData(IDataReader rdr)
        {
            if (!rdr.Read())
            {
                return null;
            }
            var u = new UserData();
            u.EmailAddress = rdr["EmailAddress"] as string;
            u.PasswordHash = rdr["PasswordHash"] as string;
            u.Salt = rdr["Salt"] as string;
            u.UniqueID = ((int)rdr[0]).ToString(); //user.id
            u.Username = rdr["Username"] as string;
            u.Groups=new List<string>();
            if (rdr["Name"] != null && !(rdr["Name"] is DBNull))
            {
                u.Groups.Add(rdr["Name"] as string);
                while(rdr.Read()){
                    u.Groups.Add(rdr["Name"] as string);
                }
            }
            rdr.Close();
            return u;

        }
        protected virtual SqlConnection GetConnection()
        {
            string s=ConfigurationManager.ConnectionStrings["fscauth"].ConnectionString;
            var con = new SqlConnection(s);
            return con;
        }
    }
}

Also, BSD licensed again:

Copyright (c) 2011 Jordan "Earlz/hckr83" Earls http://lastyearswishes.com 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.
  3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED ``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 THE AUTHOR 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.

Posted: 06/12/2011 21:57:37