Wednesday, August 24, 2011

Making references to the Code of Federal Regulations

Ever had to make a reference to the CFR in a word document? Want to add in the special symbol you see there (it's a section marker)? Press and hold the Alt key then type 0167. § Tada!

    Friday, July 29, 2005

    Finding social security numbers on Windows systems

    I was looking for a way of finding social security numbers in files, on Windows boxes, and couldn't get the GUI search to do it. Being a command line kind of person, I eventually came up with this gem:

    FINDSTR /m /r "...\-..\-...." .\*

    which will look in the current directory (use /s to recurse) and print out the names of the files that contain SSN format strings. It works on binary files like .xls and .doc too, not just ASCII.

    Thursday, March 17, 2005

    Staples 4 drawer filing cabinet

    If you ever need to buy a filing cabinet - go to Staples and check out their own brand. The construction quality is great compared to the others, and it's around $20 cheaper.
    The sliders are rock solid compared to the others. The test I was doing when choosing one was to pull out the top drawer all the way, then see how much up and down movement you could make. The Staples brand has virtually none.
    Another thing I noticed about the stores I visited was that none of them had filing cabinets in stock, you had to order them on the web (they don't even seem to do actual orders either!), so I went home and ordered it on the internet. Free shipping, it arrived a few days later.
    I also need a fire safe, but those things are heavy! So I'm going to order that online too. Let someone else lug it around.

    Tuesday, March 15, 2005

    Sony ICD-B16 voice recorder

    Like a lot of GTD advocates, I collect my information into "inboxes" and process it later. I initially was using a small writing pad when doing this in the car, but found that sometimes I'd start to write a note, then the light would change, or traffic would demand more attention, and the idea would be forgotten because of the interruption. I clearly needed something that only used one hand and that was fast.

    A digital voice recorder seemed the likely choice, and I chose the Sony mainly on price. It was the cheapest digital. As it turns out, it was the right choice. This unit is easy to use and small enough to carry everywhere. I leave it on the window ledge when I'm in the shower, and can reach out and make a note when I think it. No more forgotten ideas!

    The unit takes two AAA batteries, and lasts for several weeks on those batteries, even with being used 20-30 times a day.

    Recording is started by pressing a button on the top right, and stopped by pressing it again. Most people who have tried it have held the record button down, myself included, so it's a little counter-intuitive. There is no off button on the unit, so when it's in your pocket, you can record unexpectedly if it gets activated. To counter this, Sony has a "lock" slider. Why it doesn't simply have an off button if it needs to be locked doesn't make sense to me, but it works the same. Sometimes this button will go into a "double click" mode - you click to stop recording, and it immediately stops and then starts again. This happens several times in a row before it becomes controllable again.

    Occasionally, I will get loud screeching feedback instead of my audio note, but it's not often enough to be a real problem. The ability to click back and forth between notes while entering them into my computer is priceless. That's why I dismissed an analog recorder.

    Another plus compared to other voice recorders I've seen is that the recording is instantaneous - you press a single button and you're recording. It makes it easy to operate when you aren't looking at the device.

    To summarise, I only have minor problems with this device, and it has been a huge boost to my data collection processes.

    Wednesday, February 16, 2005

    Converting from a Windows PDC to a SAMBA PDC

    Converting from a Windows PDC to a SAMBA PDC



    This is simply the content of a detailed posting to the SAMBA-technical mailing list. IT IS NOT AN OFFICIAL SAMBA CONFIGURATION HOWTO DOCUMENT I have not verified it's accuracy, but it's the most comprehensive description I've seen of an NT to SAMBA migration I've seen. If you have questions, please contact the posting author Mike Brodbelt who may, or may not be aware of this copy. Better still, subscribe to the SAMBA mailing lists, for current information.

    December 23, 2002







    Message: 5
    Date: Fri, 07 Jun 2002 15:02:43 +0100
    From: Mike Brodbelt
    To: samba@lists.samba.org
    Subject: Re: [Samba] How to switch from NT to Samba transparently?

    This is a multi-part message in MIME format.
    --------------050000000402080204050008
    Content-Type: text/plain; charset=ISO-8859-2
    Content-Transfer-Encoding: 7bit



    Takacs Istvan wrote:
    > Hi,
    >
    > I want to switch from our Windows NT server
    > ( which works as our PDC ) to Linux - Samba.
    >
    > Could you advice a step-by-step guide about
    > this process, or is that possible, at all?

    I've bene working on this for a while - it is possible, with a few
    caveats. Here's a HOWTO I started putting together months ago - it
    remains unfinished due to lack of time, but it's a start.

    I was trying to get this to a "finished" state, with a docbook version,
    and then submit it to the Samba team, but at this stage I think it's
    better to throw it out there now to all interested parties - then even
    if I don't finish it, it'll hopefully be useful to people.

    > Can I use Samba as a BDC, convert the user
    > DB and than promote it to PDC?

    No. Samba does not currently have BDC support.

    To make the migration process easier, I've written a perl script which
    will take the smbpasswd created from the NT SAM, the unix passwd, group,
    and shadow file, and remap all the UID's as necessary. It also generates
    a shell script that can be used to change file ownerships to the new
    UID's. I've used it successfully, but it's provided as is, and I take no
    resposibility for anyone who hoses their system with it. Screwing around
    with UID's without fully understanding what you're doing can damage your
    system's health.

    It is my hope that these things are useful to people, and that they can
    be improved further - I'd like to see a point and shoot tranparent
    domain migration tool out there at some point.

    Mike.

    P.S. There is one notable error in my little HOWTO - newer versions of
    Samba do not pur the domain SID in MACHINE.SID. However, they will still
    *read* a MACHINE.SID file, and import it into secrets.tdb, so the
    procedure outlines still works. Thanks to Simo Sorce for pointing this
    out to me.



    --------------050000000402080204050008
    Content-Type: text/plain;
    name="PDC migration HOWTO.txt"
    Content-Transfer-Encoding: 7bit
    Content-Disposition: inline;
    filename="PDC migration HOWTO.txt"

    Samba PDC Transparent Migration HOWTO

    General Information
    ===================
    a/ Who is this document for

    This HOWTO is aimed at administrators working on a network controlled by a
    Windows NT 4 Primary Domain Controller. Readers may already be using Samba
    to provide services on their network, or may be looking to implement a Samba
    PDC to reduce costs, or to increase reliability or ease of management.

    b/ Issues to consider

    The work involved in moving an existing NT controlled infrastructure to one
    where some or all of the network services are provided by Samba is very
    different to the job of setting up a new Samba controlled network from
    scratch. Emphasis must be placed on transparency of migration - movement to
    the new system should be accomplished with the absolute minimum of
    interference to the working habits of users, and preferably without those
    users even noticing that it has happened.

    Sites that make heavy use of NT and NT features would be well advised to
    consider a gradual migration path. A Samba server should be joined to the
    existing NT domain, and networked printing and file sharing moved to this
    machine before PDC migration is even attempted. Sites that make heavy use of
    NT groups, ACL's, logon hours, and similar features will want to replicate
    these capabilities on Samba one feature at a time, rather than all at once.

    Samba will control a simple domain well at the current time. However,
    inter-domain trust relationships, BDC support, and the NT GUI user
    administration tools are not supported at this time.

    c/ Software

    The release of Samba 2.2 provides users with a stable platform that provides
    enough features to replace an existing NT Domain Controller. This HOWTO will
    focus on that software, though there are several other packages that can
    significantly ease the job of migration.

    Environment
    ===========
    This HOWTO was developed using a test environment, and in places, machines
    are referred to. They are

    VICTORIA - an NT4 server configured as a Primary Domain Controller, for the
    LONDON domain.
    MARKAB - a RedHat Linux 7.1 machine running Samba 2.2.0a
    ALNIYAT - an NT4 workstation configured as a member of the LONDON domain.

    Administrator - The LONDON domain Administrator account
    admin1 - A second domain Administrator
    user1 - A user.
    user2 - "
    user3 - "
    user4 - "


    Installing your Samba PDC
    =========================
    Start by installing a Samba 2.2 machine configured as a member server.
    Migrate file storage and printers first.


    Extracting the domain SID
    =========================
    When Samba is set up as a member server, it must be allocated a machine
    trust account in the domain. This is done by using the Server Manager
    program to create the account on the PDC, and then using the smbpasswd
    program to negotiate the initial password change for this machine account.

    This process causes three changes to occur:-

    * the machine trust account password in the NT PDC's SAM database is
    changed
    * a file called MACHINE.SID is created that contains the machine SID for
    the newly joined samba server
    * a file called secrets.tdb is created that contains the machine trust
    account password for the samba server

    The secrets.tdb file will be unneccessary when the samba server takes over
    the role of domain controller. The MACHINE.SID file will also require
    changing to the domain SID at that stage.

    At this stage, you should extract the domain SID for the domain you wish to
    take over. The domain SID for an NT domain is simply the machine SID of the
    PDC. You need to extract this from the existing NT PDC, so that the Samba
    server can be reconfigured with this SID when it takes over control of the
    NT domain.

    The domain SID can be extracted with the rpcclient
    utility, provided with Samba:-

    [root@markab filestore]# rpcclient VICTORIA -U administrator
    Enter Password:
    session setup ok
    Domain=[LONDON] OS=[Windows NT 4.0] Server=[NT LAN Manager 4.0]
    rpcclient $> lsaquery
    domain LONDON has sid S-1-5-21-1363377815-237862100-1307212239
    rpcclient $> quit


    Migrating users, passwords and machine trust accounts
    =====================================================
    To transparently migrate users, all user information must be migrated from
    the NT PDC to the Samba machine as seamlessly as possible. The information
    to be migrated is:-

    User account details - the username, real name and various flags associated
    with the user.
    User passwords - necessary for any degree of transparency in the migration
    Machine trust accounts - these must be migrated in order for the machine to
    remain a member of the domain. If they are not migrated correctly, the Samba
    server will not recognize the workstations as domain members.

    All the above information is stored in the NT SAM database, on the PDC. To
    extract this information from the SAM, and translate it into a format that
    Samba can read, use the pwdump2 utility from
    http://www.webspan.net/~tas/pwdump2/ . Running this on the PDC will dump the
    necessary information from the SAM in the correct format for use as an
    smbpasswd file. On the test system described, the output of this was the
    following file.

    admin1:1007:11d6cfe00976602e1b9643e5b4ea1793:64520100893d15a3fbc53534f627522
    d:::
    Administrator:500:05ba5dfe13b27dfa25ad3b83fa6627c7:b531ee2ba55d6e54f04e39475
    4d4f687:::
    ALNIYAT$:1004:aad3b435b51404eeaad3b435b51404ee:6829f8e013136fed4b61faf0c20a4
    a65:::
    MARKAB$:1006:aad3b435b51404eeaad3b435b51404ee:ef0cf14884d933c02f544236adac69
    95:::
    user1:1008:0f20048efc645d0a179b4d5d6690bdf3:1120acb74670c7dd46f1d3f5038a5ce8
    :::
    user2:1009:0f20048efc645d0af7b8da23b20d7ffe:4f597a08786530135e227ac1a579a54c
    :::
    user3:1010:0f20048efc645d0a468aa0df9e2394c4:4bce2b1108fbf76264778e2d20f8cbad
    :::
    user4:1011:0f20048efc645d0a95464a043990e5ec:74fe7144e2b0b349a63515159c45b1d3
    :::
    VICTORIA$:1000:240ca6d9c2b917a8b0b245f2c4d5309f:f28d473cd9d64f7c8fe683352870
    8586:::

    Particularly bored readers may enjoy cracking the passwords.

    It is worth noting that the format of the smbpasswd file has changed between
    version 2.0 of Samba and version 2.2. The file produced by pwdump2 is in the
    "old" format, but Samba 2.2 will still happily use the older format.


    Migrating Roaming Profiles
    ==========================
    Create a profiles share on Samba, where roaming profile for users will be
    stored:-

    [profiles]
    comment = Profiles Store
    path = /usr/local/filestore/profiles
    writeable = yes
    valid users = @users
    admin users = @admins
    create mask = 0755
    force create mode = 020
    directory mask = 02755
    force directory mode = 02070
    map system = yes
    map hidden = yes

    It is important to note here that simply moving the NT profile alone will
    not work. In an NT domain, each user has a RID, or relative identifier.
    These RID's are used by NT to set ACL's on system objects. The registry file
    in the roaming profile (ntuser.dat) contains ACL permissions that refer to
    the profile's user by RID, and the method which Samba uses to generate RID's
    will *not* result in the same RID. Simply copying the profile will result in
    a profile that cannot be used due to permission problems.

    Find an NT machine which has an up to date local copy of the profile for
    each and every use whose profile needs migrating. It's likely that you will
    need to arrange this by logging in as each user in turn. Having already
    dumped the password hashes from the SAM earlier, it's now safe for the
    adminstrator to reset all user passwords to a known value, and then log in
    as each user in turn.

    Larger sites may wish to automate this process - the following perl snippet
    may help, though I have made no attempt to use it, and have personally never
    even used Perl on Win32:-

    Will need Win32 perl.

    foreach $USER in Users do
    login $USER;
    GOTO 'My Computer' -> 'Properties' -> Profiles;
    cp $User_Profile $SMB_Profile_Deposits;
    'Permit use' -> user from domain users;
    done

    To migrate the profiles manually, from the NT machine you have set up, go to
    control panel -> system -> user profiles, and copy each profile to the
    appropriate subdirectory on the Samba share. In the process of copying, set
    the valid users to "Everyone".

    Configuring Samba as a PDC
    ==========================
    After the above steps have been taken, it is possible to transfer control of
    the domain over to the Samba server. Shut down Samba, and edit the smb.conf
    file, making the following changes:-

    Add

    os level = 64
    preferred master = yes
    domain master = yes
    local master = yes
    domain logons = yes
    logon path = \\%N\profiles\%u
    logon drive = M:
    logon home = \\%N\home
    logon script = logon.cmd

    Ensure that password encryption is set to "on", and that security is changed
    from "domain" to "user". The logon path, logon drive and logon home should
    be changed appropraitely for your setup.

    Add a share called "netlogon", as shown:-

    [netlogon]
    path = /usr/local/filestore/netlogon
    writeable = no
    write list = ntadmin, admin1

    Make backup copies of, and then delete the secrets.tdb file (probably in
    /usr/local/private) that was created when you joined the NT domain, and the
    MACHINE.SID file from the same directory. Replace the MACHINE.SID file with
    one containing the domain SID that was extracted from the Windows PDC. Use
    the output from pwdump as your smbpasswd file - store this in the "private"
    directory along with the MACHINE.SID.

    Ensure that all the accounts present in the smbpasswd file are present in
    /etc/passwd, both machine trust accounts (all end with a "$"), and user
    accounts. It is also important that the UID in /etc/passwd is the same as
    that in smbpasswd for each account.

    If Samba was configured with PAM support, ensure that an appropriate
    /etc/pam.d/samba file exists.

    Finally, shutdown the Windows PDC, and restart the Samba daemons from the
    new configuration file.

    You should now be able to log on to the Samba PDC from any of the Windows
    workstations that are members of the domain.

    Replacing your NT BDC
    =====================
    PDC to BDC replication is not supported in the current releases of Samba
    2.2, so setting up a BDC directly is not possible. It is, however, possible
    to provide the redundancy offered by a BDC fairly simply.

    -------
    Some documentation on using rsync to maintain SAM/account details on two
    machines, and provide failover in the event of one going down needed.
    -------


    Troubleshooting
    ===============
    -----
    need lists of what can go wrong.
    -----


    Miscellaneous
    Authentication and Single Sign on
    Using pam_smb
    Using pam_ntdom
    Using winbind


    Caveats/outstanding questions

    Machine name length - if netbios name longer than 8 characters, will the
    machine account die?
    --------------050000000402080204050008
    Content-Type: text/plain;
    name="pdc_conv.pl"
    Content-Transfer-Encoding: 7bit
    Content-Disposition: inline;
    filename="pdc_conv.pl"

    #!/usr/bin/perl
    #
    # Author: Mike Brodbelt
    # Creation date: 21/11/01
    # Last updated: 03/12/01
    #
    # Small script to read the contents of system account files, and an
    smbpasswd file, and
    # create new /etc/passwd and /etc/group files suitable for basing a Samba
    controlled
    # NT domain on. Also, generate scripts to change file ownership
    appropriately, where
    # a users UID changes.

    # Set a few global variables to influence the script's operation

    our $unix_pwd_field = "x"; # New Unix accounts will
    have their password field set to this.
    our $unix_shell = "/bin/bash"; # New Unix accounts will
    have their shell set to this.
    our $system_account_base = "105"; # Accounts in passwd file
    with UID <= this will be preserved
    our $system_group_base = "249"; # Accounts in group file
    with GID <= this will be preserved
    our $output_passwd_file = "new_passwd"; # Name of new passwd file
    for output
    our $output_group_file = "new_group"; # Name of new group file for
    output
    our $output_smbpasswd_file = "new_smbpasswd"; # Name of new smbpasswd file
    for output
    our $output_shadow_file = "new_shadow"; # Name of new shadow file
    for output
    our $shell_script = "ownership.sh"; # Name of shell script to
    change file ownerships

    (@ARGV == 4) || die "Usage: pdc_conv.pl
    \n";
    ($passwd, $group, $smbpasswd, $shadow) = @ARGV;

    # Parse the supplied passwd, group, and smbpasswd files, building
    # tables for them in memory.

    $user_hashref = hash_unix_users();
    $group_hashref = hash_unix_groups();
    $smbpasswd_hashref = hash_smbpasswd();
    $shadow_hashref = hash_shadow_file();

    # Now, we need to create a new Unix /etc/passwd file. We go through
    the existing accounts
    # that have been pulled from the passwd file, and leave any that
    fall below the base UID
    # untouched - this preserves system accounts without any changes.

    $newuser_hashref = add_reserved_accounts($user_hashref);

    # For accounts present in the smbpasswd file, we need to add a Unix
    system account. Where there is no
    # corresponding UID in the Unix passwd file, we simply create the
    account, using the appropriate
    # account information. Where there is an existing UID in the Unix
    passwd file, we store the details
    # of the account for later matching.

    add_smbpasswd_accounts($newuser_hashref, $user_hashref, $smbpasswd_hashref);

    # At this point, we have an in memory passwd file that contains the
    contents of the
    # NT SAM from the smbpasswd file, and the accounts with a UID <= the
    system base.
    # Now, we need to go through the accounts in the passwd file, and
    where we have
    # migrated an account with an identical username, we assume that
    this is the same
    # user, and bring across information from the passwd file (shell,
    home dir, gecos).

    add_finger_inf($newuser_hashref, $user_hashref, $smbpasswd_hashref);

    # Finally, we need to migrate any accounts that exist in the system
    passwd
    # file, that have no matching entry in the smbpasswd file. This will
    catch Unix
    # user logins that are not in the NT SAM. Where these collide with a
    previously
    # migrated user from the smbpasswd file, we *overwrite* the user
    from smbpasswd.
    # This is done on the principle that it's better to have a user
    account fail to
    # migrate than to trash a unix login that could be vital.

    add_nonreserved_accounts($newuser_hashref, $user_hashref,
    $smbpasswd_hashref);

    # Now we create a new Unix /etc/group file. As with the password
    file, first add all
    # the group accounts that fall below a user defined base GID.

    $newgroup_hashref = add_reserved_groups($group_hashref);

    # Now, add the other groups. Go through the group file, and add
    groups unchanged
    # unless the groupname matches the username of a user from the
    passwd file. If
    # this occurs, and the group has no member list, assume this is a
    "user private
    # group", and change the GID to match the GID we're going to write
    out in the new
    # system passwd file.

    add_all_groups($newgroup_hashref, $user_hashref, $group_hashref,
    $smbpasswd_hashref);

    # Now we need to generate new user private groups for user accounts
    with a
    # primary group that has no corresponding entry in the new group
    list.

    add_new_groups($newgroup_hashref, $newuser_hashref);

    # Write out a new Unix passwd file

    write_passwd_file($newuser_hashref);

    # Write out a shadow file that corresponds to this passwd file

    write_shadow_file($newuser_hashref, $shadow_hashref);

    # Write out a new smbpasswd file, reformatting for Samba version 2.x

    write_smbpasswd_file($smbpasswd_hashref);

    # Write out a new Unix group file

    write_group_file($newgroup_hashref);

    # Now we need to generate a shell script that will change all the
    UIDs
    # and GIDs on the filesystem as appropriate. To do this, we need to
    # build maps linking the old UIDs and GIDs to the new ones.

    $uid_map_hashref = build_uid_map($user_hashref, $newuser_hashref);
    $gid_map_hashref = build_gid_map($group_hashref, $newgroup_hashref);

    # Now, write a shell script out that'll do the changes.

    write_shell_script($uid_map_hashref, $gid_map_hashref);


    ############################################################################
    #####

    sub build_gid_map {
    my (%groups, %gid_map);
    my ($group_hashref, $newgroup_hashref) = @_;

    foreach (keys %$group_hashref) {
    $groups{ $$group_hashref{$_}->{GROUPNAME} } = $_;
    }

    foreach (sort {$a <=> $b} keys %$newgroup_hashref) {
    if (exists $groups{ $$newgroup_hashref{$_}->{GROUPNAME} }) {
    unless ($groups{ $$newgroup_hashref{$_}->{GROUPNAME}
    } == $_) {
    $gid_map{ $groups{
    $$newgroup_hashref{$_}->{GROUPNAME} } } = $_;
    }
    }
    }
    return \%gid_map;
    }

    sub build_uid_map {
    my (%users, %uid_map);
    my ($user_hashref, $newuser_hashref) = @_;

    foreach (keys %$user_hashref) {
    $users{ $$user_hashref{$_}->{USERNAME} } = $_;
    }

    foreach (sort {$a <=> $b} keys %$newuser_hashref) {
    if (exists $users{ $$newuser_hashref{$_}->{USERNAME} }) {
    unless ($users{ $$newuser_hashref{$_}->{USERNAME} }
    == $_) {
    $uid_map{ $users{
    $$newuser_hashref{$_}->{USERNAME} } } = $_;
    }
    }
    }
    return \%uid_map;
    }

    sub add_all_groups {
    my (%users);
    my ($newgroup_hashref, $user_hashref, $group_hashref,
    $smbpasswd_hashref) = @_;

    # Hash Unix usernames from passwd file against UID's

    foreach (keys %$user_hashref) {
    $users{ $$user_hashref{$_}->{USERNAME} } = $_;
    }

    foreach (keys %$group_hashref) {
    if ($_ > $system_group_base) {
    if ((exists $users{ $$group_hashref{$_}->{GROUPNAME}
    }) &&
    (!scalar @{$$group_hashref{$_}->{MEMBERS}})) {
    if (exists $$smbpasswd_hashref{
    $$group_hashref{$_}->{GROUPNAME} }) {
    # User private group with a
    corresponding smbpasswd entry
    $$newgroup_hashref{
    $$smbpasswd_hashref{$$group_hashref{$_}->{GROUPNAME}}->{UID} } = {
    GROUPNAME =>
    $$group_hashref{$_}->{GROUPNAME},
    PASSWD =>
    $$group_hashref{$_}->{PASSWD},
    GID =>
    $$smbpasswd_hashref{$$group_hashref{$_}->{GROUPNAME}}->{UID},
    MEMBERS =>
    $$group_hashref{$_}->{MEMBERS}
    };
    } else {
    # User private group with no
    corresponding smbpasswd entry
    $$newgroup_hashref{$_} = {
    GROUPNAME =>
    $$group_hashref{$_}->{GROUPNAME},
    PASSWD =>
    $$group_hashref{$_}->{PASSWD},
    GID => $_,
    MEMBERS =>
    $$group_hashref{$_}->{MEMBERS}
    };
    }
    } elsif (!scalar @{$$group_hashref{$_}->{MEMBERS}})
    {
    print "Discarding empty group
    \"$$group_hashref{$_}->{GROUPNAME}\" from new group file\n";
    } else {
    $$newgroup_hashref{$_} = {
    GROUPNAME =>
    $$group_hashref{$_}->{GROUPNAME},
    PASSWD =>
    $$group_hashref{$_}->{PASSWD},
    GID => $_,
    MEMBERS =>
    $$group_hashref{$_}->{MEMBERS}
    };
    }
    }
    }
    }

    sub add_new_groups {
    my ($newgroup_hashref, $newuser_hashref) = @_;
    foreach (sort {$a <=> $b} keys %$newuser_hashref) {
    unless (exists $$newgroup_hashref{
    $$newuser_hashref{$_}->{GID} }) {
    $$newgroup_hashref{$_} = {
    GROUPNAME =>
    $$newuser_hashref{$_}->{USERNAME},
    PASSWD => $unix_pwd_field,
    GID =>
    $$newuser_hashref{$_}->{GID},
    MEMBERS => ""
    };
    }
    }
    }

    sub add_reserved_groups {
    my (%new_unix_groups);
    my ($group_hashref) = @_;
    foreach (sort keys %$group_hashref) {
    if ($_ <= $system_group_base) {
    $new_unix_groups{$_} = $$group_hashref{$_};
    }
    }
    return \%new_unix_groups;
    }

    sub add_finger_inf {
    my ($newuser_hashref, $user_hashref, $smbpasswd_hashref) = @_;
    foreach (sort keys %$user_hashref) {
    if ($_ > $system_account_base) {
    if (exists $$smbpasswd_hashref{
    $$user_hashref{$_}->{USERNAME} }) {
    $$newuser_hashref{ $$smbpasswd_hashref{
    $$user_hashref{$_}->{USERNAME} }->{UID} }->{PASSWD} =
    $$user_hashref{$_}->{PASSWD};
    $$newuser_hashref{ $$smbpasswd_hashref{
    $$user_hashref{$_}->{USERNAME} }->{UID} }->{GECOS} =
    $$user_hashref{$_}->{GECOS};
    $$newuser_hashref{ $$smbpasswd_hashref{
    $$user_hashref{$_}->{USERNAME} }->{UID} }->{HOMEDIR} =
    $$user_hashref{$_}->{HOMEDIR};
    $$newuser_hashref{ $$smbpasswd_hashref{
    $$user_hashref{$_}->{USERNAME} }->{UID} }->{SHELL} =
    $$user_hashref{$_}->{SHELL};
    }
    }
    }
    }

    sub add_nonreserved_accounts {
    my ($newuser_hashref, $user_hashref, $smbpasswd_hashref) = @_;
    foreach (sort keys %$user_hashref) {
    if ($_ > $system_account_base) {
    # if the username matches a username in smbpasswd,
    skip it - already migrated
    if (exists $$smbpasswd_hashref{
    $$user_hashref{$_}->{USERNAME} }) {
    next;
    } else {
    # Have we already got an account in the
    newuser hash with this UID?
    if (exists $$newuser_hashref{$_}) {
    print "Warning: SMB user
    $$newuser_hashref{$_}->{USERNAME} will not be migrated, " .
    "collides with Unix user
    $$user_hashref{$_}->{USERNAME}!\n";
    }
    $$newuser_hashref{$_} = $$user_hashref{$_};
    }
    }
    }
    }

    sub add_smbpasswd_accounts {
    my ($newuser_hashref, $user_hashref, $smbpasswd_hashref) = @_;
    foreach (keys %$smbpasswd_hashref) {
    # Does the UID collide with one already in the new users
    list - i.e. a corrupted smbpasswd file or a clash between
    # an smbpasswd entry and a pre-existing Unix account with
    UID < system reserved base.

    if (exists $$newuser_hashref{ $$smbpasswd_hashref{$_}->{UID}
    }) {
    print "Account with UID
    \"$$smbpasswd_hashref{$_}->{UID}\" from smbpasswd collides with reserved
    account\n";
    print "This account
    \($$smbpasswd_hashref{$_}->{USERNAME}\) account will not be added to the new
    passwd file\n";
    } else {
    if ($$smbpasswd_hashref{$_}->{USERNAME} =~ /\$$/) {
    $record = {
    USERNAME =>
    $$smbpasswd_hashref{$_}->{USERNAME},
    PASSWD =>
    $unix_pwd_field,
    UID =>
    $$smbpasswd_hashref{$_}->{UID},
    GID =>
    $$smbpasswd_hashref{$_}->{UID},
    GECOS => "NT
    workstation trust account",
    HOMEDIR => "/dev/null",
    SHELL => "/bin/false"
    };
    } else {
    $record = {
    USERNAME =>
    $$smbpasswd_hashref{$_}->{USERNAME},
    PASSWD =>
    $unix_pwd_field,
    UID =>
    $$smbpasswd_hashref{$_}->{UID},
    GID =>
    $$smbpasswd_hashref{$_}->{UID},
    GECOS => "Account
    migrated from NT SAM database",
    HOMEDIR =>
    "/home/$$smbpasswd_hashref{$_}->{USERNAME}",
    SHELL => $unix_shell
    };
    }
    }
    $$newuser_hashref{ $record->{UID} } = $record;
    }
    }

    sub write_smbpasswd_file {
    my ($flags, $rec);
    my ($smbpasswd_hashref) = @_;
    open OUTFILE, '>', $output_smbpasswd_file || die "Unable to open
    $output_smbpasswd_file for writing\n";
    foreach (sort {uc($a) cmp uc($b)} keys %$smbpasswd_hashref) {
    if ($_ =~ /\$$/) {
    $flags = "[ W ]";
    } else {
    $flags = "[U ]";
    }
    $rec = join(':',
    $$smbpasswd_hashref{$_}->{USERNAME},
    $$smbpasswd_hashref{$_}->{UID},
    $$smbpasswd_hashref{$_}->{LMHASH},
    $$smbpasswd_hashref{$_}->{NTHASH},
    $flags,
    "LCT-363F96AD",
    ""
    );
    print OUTFILE "$rec\n";
    }
    close(OUTFILE);
    }

    sub write_group_file {
    my ($rec);
    my ($newgroup_hashref) = @_;
    open OUTFILE, '>', $output_group_file || die "Unable to open
    $output_group_file for writing\n";
    foreach (sort {$a <=> $b} keys %$newgroup_hashref) {
    $rec = join(':',
    $$newgroup_hashref{$_}->{GROUPNAME},
    $$newgroup_hashref{$_}->{PASSWD},
    $$newgroup_hashref{$_}->{GID},
    (join(',',
    @{$$newgroup_hashref{$_}->{MEMBERS}}))
    );
    print OUTFILE "$rec\n";
    }
    close(OUTFILE);
    }

    sub write_passwd_file {
    my ($rec);
    my ($newuser_hashref) = @_;
    open OUTFILE, '>', $output_passwd_file || die "Unable to open
    $output_passwd_file for writing\n";
    foreach (sort {$a <=> $b} keys %$newuser_hashref) {
    $rec = join(':',
    $$newuser_hashref{$_}->{USERNAME},
    $$newuser_hashref{$_}->{PASSWD},
    $$newuser_hashref{$_}->{UID},
    $$newuser_hashref{$_}->{GID},
    $$newuser_hashref{$_}->{GECOS},
    $$newuser_hashref{$_}->{HOMEDIR},
    $$newuser_hashref{$_}->{SHELL}
    );
    print OUTFILE "$rec\n";
    }
    close(OUTFILE);
    }

    sub write_shadow_file {
    my ($newuser_hashref, $shadow_hashref)= @_;
    open OUTFILE, '>', $output_shadow_file || die "Unable to open
    $output_shadow_file for writing\n";
    foreach (sort {$a <=> $b} keys %$newuser_hashref) {
    if (exists $$shadow_hashref{
    $$newuser_hashref{$_}->{USERNAME} }) {
    $rec = join(':',
    $$shadow_hashref{
    $$newuser_hashref{$_}->{USERNAME} }->{USERNAME},
    $$shadow_hashref{
    $$newuser_hashref{$_}->{USERNAME} }->{PASSWD},
    $$shadow_hashref{
    $$newuser_hashref{$_}->{USERNAME} }->{LASTDAY},
    $$shadow_hashref{
    $$newuser_hashref{$_}->{USERNAME} }->{MINDAY},
    $$shadow_hashref{
    $$newuser_hashref{$_}->{USERNAME} }->{MAXDAY},
    $$shadow_hashref{
    $$newuser_hashref{$_}->{USERNAME} }->{WARNDAY},
    $$shadow_hashref{
    $$newuser_hashref{$_}->{USERNAME} }->{EXPIREDATE},
    $$shadow_hashref{
    $$newuser_hashref{$_}->{USERNAME} }->{DISABLED},
    $$shadow_hashref{
    $$newuser_hashref{$_}->{USERNAME} }->{RESERVED}
    );
    } else {
    $rec = join(':',
    $$newuser_hashref{$_}->{USERNAME},
    "*",
    "10438",
    "0",
    "99999",
    "7",
    "",
    "",
    ""
    );
    }
    print OUTFILE "$rec\n";
    }
    close(OUTFILE);
    }

    sub write_shell_script {
    my ($uid_map_hashref, $gid_map_hashref) = @_;
    open OUTFILE, '>', $shell_script || die "Unable to open
    $shell_script for writing\n";
    print OUTFILE "#!/bin/sh\n";
    foreach (sort {$a <=> $b} keys %$uid_map_hashref) {
    print OUTFILE "find / -uid $_ -exec chown
    $$uid_map_hashref{$_} {} \\;\n";
    }
    foreach (sort {$a <=> $b} keys %$gid_map_hashref) {
    print OUTFILE "find / -gid $_ -exec chgrp
    $$gid_map_hashref{$_} {} \\;\n";
    }
    close(OUTFILE);
    chmod 0755,($shell_script);
    }

    sub add_reserved_accounts {
    my (%new_unix_users);
    my ($user_hashref) = @_;
    foreach (sort keys %$user_hashref) {
    if ($_ <= $system_account_base) {
    $new_unix_users{$_} = $$user_hashref{$_};
    }
    }
    return \%new_unix_users;
    }

    sub hash_smbpasswd {

    # Open the smbpasswd file, and read all entries.

    my (@fields, $record, %users);

    open SMBPASSWD, $smbpasswd || die "Unable to open $smbpasswd for
    reading\n";

    while () {
    chomp;
    (@fields) = split(/:/, $_);
    $record = {
    USERNAME => $fields[0],
    UID => $fields[1],
    LMHASH => $fields[2],
    NTHASH => $fields[3]
    };
    # Now store the record we've just created, keying the hash
    by username.
    $users{ $record->{USERNAME} } = $record;
    }
    close(SMBPASSWD);

    # Return a reference to the hash
    return \%users;
    }

    sub hash_unix_groups {

    # Open the Unix group file, and build a list of groups, and
    # their memberships. We want to isolate groups with no members,
    # which are set to the primary group of some users, so we can
    # chgrp as well as chown their files

    my (@fields, $record, %groups);

    open GROUP, $group || die "Unable to open $group for reading\n";

    while () {
    chomp;
    @fields = split(/:/, $_);
    $record = {
    GROUPNAME => $fields[0],
    PASSWD => $fields[1],
    GID => $fields[2],
    MEMBERS => [ split(/\s*,\s*/,
    $fields[3]) ]
    };

    # Now store the group record created, keying the hash by GID
    $groups{ $record->{GID} } = $record;

    }

    close(GROUP);

    # Return a reference to the hash
    return \%groups;
    }


    sub hash_unix_users {

    # Open the unix passwd file, and read a list of all users.
    # Then, store a 2 dimensional array of usernames, full names, and
    # home directories.

    my (@fields, $record, %users);

    open PASSWD, $passwd || die "Unable to open $passwd for reading\n";

    while () {
    chomp;
    (@fields) = split(/:/, $_);
    $record = {
    USERNAME => $fields[0],
    PASSWD => $fields[1],
    UID => $fields[2],
    GID => $fields[3],
    GECOS => $fields[4],
    HOMEDIR => $fields[5],
    SHELL => $fields[6],
    };

    # Now store the record we've just created, keying the hash
    by UID.
    $users{ $record->{UID} } = $record;
    }
    close(PASSWD);

    # Return a reference to the hash
    return \%users;
    }

    sub hash_shadow_file {

    my (@fields, $record, %shadow);

    open SHADOW, $shadow || die "Unable to open $shadow for reading\n";

    while () {
    chomp;
    (@fields) = split(/:/, $_);
    $record = {
    USERNAME => $fields[0],
    PASSWD => $fields[1],
    LASTDAY => $fields[2],
    MINDAY => $fields[3],
    MAXDAY => $fields[4],
    WARNDAY => $fields[5],
    EXPIREDATE => $fields[6],
    DISABLED => $fields[7],
    RESERVED => $fields[8],
    };

    # Now store the record we've just created, keying the hash
    by UID.
    $shadow{ $record->{USERNAME} } = $record;
    }
    close(SHADOW);

    # Return a reference to the hash
    return \%shadow;
    }

    Tuesday, November 30, 2004

    Canon Powershot S500

    Our latest gadget is the Canon Powershot S500. Bought for around $400 from Best Buy. It's a small, but medium weight 5.1 MegaPixel camera. It comes with a virtually useless 32Mb CF card that I've swapped out for a 256Mb CF card. So far photo results with the flash are disappointing, looking more like cheap point and shoot than anything, but I bought it mainly as a rapid way of getting images onto the computer.

    I expect sunshine shots outside to be pretty great, the resolution is excellent. The software it comes with is mediocre, I haven't yet figured out a way to automatically upload pictures and clear the card when done.

    In a tacky move, the camera comes with no case, Canon sell a separate $70 "package" of extras which include a case. So far, I've resisted.

    Tuesday, October 05, 2004

    Noise-Cancelling Headphones

    Amazon.com: Electronics: Panasonic RP-HC70 Noise-Cancelling Headphones

    I got to use my new noise cancelling earphones on a flight, and I'm pleased with them. The review said not to expect a miracle, so I didn't but I did get about a 50% noise reduction. The earphones took out the most unpleasant part of the hum, and oddly enough I could hear most of the conversations around me quite clearly. I noticed that my own voice was drowned out somewhat, and my co-work confirmed this - her voice was drowned out too. Overall though, a definite improvement in my flight.