Team LiB
Previous Section Next Section

Hack 29. Remotely Manage User Configurations

Make sure all users in an enterprise have a uniform set of configured preferences.

This hack shows how to take configuration control away from the Firefox user. Firefox provides a little support for locking preference files. It provides no support for other parts of the profile. This means that most parts of the profile must be managed with filesystem access controls, such as ownership and read/write permissions. This is something of a problem if you require extensive configuration control.

On the plus side, the two configuration features described later in this hack, ReadConfig and AutoConfig, apply to Netscape 4.x-7.x and all these Mozilla-based products: Mozilla Application Suite, Firefox, Thunderbird, Camino, and probably a few others as well. They can be used to manage all these products from one central point. The two features are sometimes collectively called autoconfig.

3.9.1. Locking Files Using the Operating System

Many of the files in the profile that you would want to lock (for example, cookies.txt, mimeTypes.rdf, and the Chrome subdirectory) are located directly underneath the profile's salted directory name. It is not enough to make these files read-only. The user can remove them if write permission remains on the parent directory (permission models differ in detail between Unix and Windows). Default versions will then be regenerated the next time Firefox starts up, with read/write permissions restored. So making files read-only isn't enough.

If write permission is taken off the salted directory, extensions or other oddities that are installed at a later date will not be able to add their files to that directory. The salted directory is a common place for such oddities. Currently, the only solution to this extension problem is to assess each extension for impact using an unlocked test system before approving it for use.

You might also want to lock files in the install area. If Firefox runs over a network from a central application server, you can lock all the default (or modified) preference files and other default configuration in the install area.

It is also important to lock the registry.dat file. Users can change their profile entirely if they can modify or replace this file, so remove that possibility.

3.9.2. Surviving Special Preference Configuration Rules

The rest of this hack describes use of special configuration files. Keep these points in mind. First, .js, .cfg, and .jsc files are all JavaScript scripts; there is no special meaning behind these filename extensions.

There are four special syntax arrangements for .cfg scripts:

  • The first line of such files should be invalid JavaScript, so that the file cannot be run by accident as an ordinary script.

  • Such files are very weakly encrypted (shrouded), making them unreadable by eye.

  • All these files have full support for the core JavaScript language, but only a limited range of functions are available. There are no alert()or user-friendly error messages.

  • The lock_pref() and unlock_pref() functionsnot pref( )should be used in these scripts. This is also true for .jsc files.

The first line invalid rule is quite confusing, because it means that Firefox ignores that first line completely. Recommended practice is to make sure files look like this:

#Mozilla Example Security Header Line
lock_pref("example.pref.enabled",true);
lock_pref("example.pref2.enabled",true);
...

Do not use #!, which can cause a program to run under Unix. If this line uses correct JavaScript comment syntax (either // for whole lines, or /* */ pairs) instead of #, then:

  • The file is now valid JavaScript, a minor security hole.

  • The special behavior is less obvious and so is easy to forget.

This example shows that ill-advised use:

// Mozilla Example Security Header Line
lock_pref("example.pref.enabled",true);
lock_pref("example.pref2.enabled",true);
...

If you forget this feature entirely, you could lose the first line of your file accidentally, which might wreck the script if it's no longer a whole JavaScript, or at least cause a statement to be missed:

lock_pref("example.pref.enabled",true);  // line 1 - ignored and lost 
lock_pref("example.pref2.enabled",true); // line 2 - recognized
...

Finally, if there is a JavaScript syntax error anywhere in the file, the remainder of the file's contents is silently ignored. Always make a line like this the last line of your file:

lock_pref("check.config.enabled",true);  // my check

This preference has no special meaning; it is a made-up flag. If it appears in about:config, your file has been read successfully. Don't forget to delete it using about:config before testing changes to your files.

3.9.3. Locking Preferences Using ReadConfig

ReadConfig is a small enhancement to the preferences system [Hack #23] designed to lock down preferences using a local file. It doesn't appear anywhere in the Firefox GUI or in the files supplied at install time. Two files must be modified for ReadConfig to work. First, Firefox must be told that ReadConfig is enabled. This is done with normal preferences:

lock_pref("general.config.vendor","acme");
lock_pref("general.config.filename","acme.cfg");

Those preferences should be set in the install area, either as part of a custom Firefox installation or hacked into place afterward. They are not set by default. acme is an opaque string that names the organization (vendor) providing the custom install of Firefox (you). These preferences must be put in a file called all.js, and nowhere else. This file must be put in the install area here:

defaults/pref/all.js

The other file, acme.cfg, is a new file that must be placed at the top of the install area in the same directory as the Firefox binary (e.g., C:\Program Files\Firefox). The following preference controls the shrouding (trivial encryption) of this acme.cfg file. The normal case is encryption using a simple ROT-13 algorithm:

lock_pref("general.config.obscure_value",13);

Set this preference to 0 (zero) to ease testing of ReadConfig. It allows an unshrouded acme.cfg file to be read.

Summarizing all that, a minimal all.js file designed to enable ReadConfig with a standard, shrouded file looks like this:

lock_pref("general.config.vendor","acme");
lock_pref("general.config.filename","acme.cfg");
lock_pref("general.config.obscure_value",13);
lock_pref("check.alljs.enabled",true);          // my syntax OK flag

On startup, Firefox will see these preferences. It will load, unshroud, and first-line-strip the acme.cfg file, and then interpret its contents.

The script inside acme.cfg file is not interpreted the same way as a straightforward JavaScript script. Two extra things happen when it runs:

  1. Before it is interpreted, the content of these two other files are exposed to its use:

    defaults/autoconfig/platform.js
    defaults/autoconfig/prefcalls.js

  2. After it is interpreted, these preferences are reapplied (if they are present) and overwrite any previous values:

    general.config.vendor
    general.config.filename
    autoadmin.global_config_url

    The first point simply provides the configuration script with some extra functions that it can call. A highly customized Firefox install might extend that set by providing a bigger prefcalls.js file. The second point is a security feature. The user should not be able to reset the names of configuration files after they are read.

    A sample acme.cfg file, without AutoConfig support (see the next section) and without shrouding, looks like this:

    #Mozilla ReadConfig Security Header Line
    lock_pref("general.config.vendor","acme");
    lock_pref("general.config.filename","acme.cfg");
    
    lock_pref("browser.chrome.toolbar_tips",false);  // whatever's needed
    
    lock_pref("check.readconfig.enabled",true);      // syntax ok flag

    To shroud the acme.cfg file, use Alain Knaff's script (Perl 5.8 required):

    http://www.alain.knaff.lu/howto/MozillaCustomization/moz-byteshift.pl

    ReadConfig offers little remote control by itself. The most you get is a customized install and a trivial hurdle for the user. You must use filesystem security to protect the ReadConfig information, but since it's in the install area, not in the profile, this is an easy task, especially if the Firefox install is on a central server. ReadConfig serves as a jumping off point for AutoConfig, discussed next.

3.9.4. Updating Preferences Using AutoConfig

AutoConfig is also a small enhancement to the preference system. It doesn't appear in the Firefox GUI anywhere, or in the default install files. It allows preferences to be set from a file delivered by a web server. It facilitates centralized control; preferences can be modified in one place and automatically reapplied to all users the next time that Firefox starts up. In that respect, it is similar to the AutoProxy feature [Hack #15], but the similarity ends quickly.

AutoConfig preference scripts are specified by a URL. Any http: or ftp: URL is fine, as long as the HTTP Content-Type sent is correct [Hack #27] . If the file is static, the convention is to name it autoconfig.jsc (jsc stands for JavaScript Configuration). This preference causes the server-based file to be downloaded at Firefox startup time:

autoadmin.global_config_url    /* set to a http: or ftp: URL */

This preference can be put in any preference file. The only sensible place to put it is inside a ReadConfig .cfg file, where the user can't change it. The only place that uses this preference for its fundamental purpose is the internal bit of Mozilla that reads the .cfg files.

AutoConfig writes a file to the Firefox profile failover.jsc., which is a copy of the web-delivered configuration script grabbed automatically by Firefox. The configuration script is downloaded each time the profile is switched. Firefox 1.0 doesn't yet support live profile switching (unless you add an extension), so the download occurs only when Firefox starts up. It also occurs if there's no profile at all (but that is an abnormal state of affairs).

No AutoConfig file contains JavaScript-unfriendly header lines. No such file is shrouded with ROT-13. They are plain and correct JavaScript syntax.

Several preferences control the way AutoConfig behaves. They should also be set somewhere that's away from the user's grubby hands.

The following preference indicates whether to tell the server who the user is, using dodgy HTTP GET syntax to send the user's email address to the server:

autoadmin.append_emailaddr /* default = false, set to true */

Firefox will do its best to find in the preference system a Thunderbird, Mozilla Email & News, or Netscape Email email address to use. The sent URL will look like this:

http://www.example.com/example-config.jsc?foo@bar.org

A sample server-supplied AutoConfig file looks like this:

lock_pref("browser.chrome.toolbar_tips",false);  // whatever's needed

lock_pref("check.autoconfig.enabled",true);      // my syntax OK flag

3.9.5. Handling Failover Scenarios

AutoConfig does not rely on or use the general-purpose Firefox Cache. This preference determines what AutoConfig must do if Firefox is set to offline mode by the user:

autoadmin.offline_failover  /* default = false, set to true */

If this preference is set to true, Firefox will read the locally stored failover.jsc file instead of reaching out over the network.

This further preference indicates what AutoConfig must do if Firefox fails to retrieve the configuration script from a web server:

autoadmin.failover_to_cached  /* default = false, set to true */

If this preference is set to TRue, Firefox will read the failover.jsc file if retrieval or parsing of the autoconfig.jsc file fails for any reason. If that happens, Firefox will also lock this preference, which prevents any online activity until the browser restarts.

Finally, this preference is a security measure designed to stop clients from being flooded with bad configuration data:

network.online   /* set to true or false */

Set to false, Firefox will not seek out the AutoConfig file. Firefox will set this preference to false if it detects problems retrieving the config file.

    Team LiB
    Previous Section Next Section