Sharing Files with Samba

   

Samba, used by Apple to implement Windows-compatible file sharing, is another complex server product, approaching Apache in terms of options. Although we'll do our best to cover the basic settings and security directives you need to run an effective server, it would be worth your while to buy a dedicated text for advanced file sharing environments. Sams Teach Yourself in 24 Hours (ISBN: 0672316099) and the Samba Web site are great sources for information (http://www.samba.org).

NOTE

Apple has done an admirable job of keeping Samba up to date, but if you need to update Samba, it compiles easily, without any tweaks. Download the latest Samba source from http://www.samba.org/, and configure , make , then make install .

Samba Security History

As you can imagine, a project that required Microsoft's proprietary protocols to be reverse-engineered has experienced a few rocky points during its development. At the time of this writing, Apple was shipping version 2.2.3a, which is several versions behind the latest release. Luckily, Samba compiles and installs cleanly on Mac OS X, so if you'd like to build the latest version, you can download the source from http://us1.samba.org/samba/ftp/. The 2.2.3a version suffers from one (known) potential exploit:

  • DoS and Root Exploit (CVE: CAN-2002-1318) . The 2.2.3a-2.2.6 releases contain a buffer overflow that can be exploited to cause a denial of service attack and potentially execute arbitrary code on the server. There are no known exploits of this condition, but it is corrected in the 2.2.7 release.

Previous exploits include the following:

  • SymLink Attack (CVE: CAN-2001-0406) . Versions of Samba prior to 2.2.0 suffered from a bug that allowed local users to overwrite arbitrary files by querying the printer queue or using smbclient . This error was corrected in the 2.2.0 release.

  • SWAT DoS (CVE: CAN-2000-0939) . SWAT suffered from a potential denial of service attack that would force the process to be restarted when requested with a URL formatted as localhost:901?somethingthatdoesntexist . This is recognized as an inetd problem that is simply made easier to exploit via SWAT.

  • Remote File Overwrite (CVE: CVE-2001-1162) . In versions of Samba prior to 2.2.0a, remote attackers could overwrite local files by providing Unix path characters within a NETBIOS name , such as ... These were subsequently substituted for %m anywhere it occurred in the smb.conf file.

Activating Samba

To turn on Samba, open the Sharing System Preferences panel, highlight the Services tab, then either click the check box in front of the Windows File Serving line or highlight it and click the Start button. The sharing panel updates and shows the path that can be used to map the drive on a Windows-based computer, as demonstrated in Figure 16.4.

Figure 16.4. Start the Samba daemon by using the Sharing preference panel.

graphics/16fig04.jpg

Like AppleShare file sharing in OS X, the built-in Samba configuration is limited to sharing each user's home directory ”and, by default, none of the user accounts are enabled for login. Enable login from Windows by opening the Accounts System Preferences panel, selecting the user to have Samba access, then clicking the Edit User button. Your screen will look similar to Figure 16.5.

Figure 16.5. Edit the user accounts that should be able to access your computer from Windows.

graphics/16fig05.jpg

If necessary, enter the current user password, press Enter, then click the Allow User to Log In from Windows check box. The configured user should now be able to access his or her home directory with the SMB/CIFS path format:

  \<hostname or IP address>\<username>  

NOTE

Windows login is enabled and disabled by adding ;LocalWindowsHash; to the NetInfo key authentication_authority in each user's NetInfo directory.

The first time Windows access is enabled through the Accounts panel, a Windows password hash file is created in the directory /private/var/db/samba/hash . Subsequent checking and unchecking of the Allow User to Log In from Windows check box will simply toggle the NetInfo authentication settings.

Apple has included a GUI means of setting one's workgroup and WINS server by using the Directory Access utility (Path: /Applications/Utilities/Directory Access ). Open the utility, then authenticate by using the lock button in the lower right corner.

Next, highlight the SMB service and click the Configure button. Mac OS X prompts for a workgroup name and WINS server, which are subsequently added to the /etc/smb.conf file.

Activating SWAT

Although Samba can be activated and used with Apple's default configuration, you'll be missing 99% of the functionality. Samba offers many advanced features that can only be accessed when you manually edit the setup. The Samba setup is contained in the very readable file /etc/smb.conf . Configuration is handled entirely through a Web-based GUI called SWAT.

CAUTION

Samba is intended to be configured with SWAT. Although you can manually edit /etc/smb.conf , it is not recommended and can quickly lead to an invalid setup.

If the file does become corrupted, return to the original Mac OS X Samba configuration by copying the file /etc/smb.conf.template over /etc/smb.conf .

SWAT is included with your system, but is not ready for use. SWAT requires additional setup that enables it to activate when a Web browser accesses port 901 on your computer. To start, be sure that you have the 10.2 Developer Tools installed.

CAUTION

If you attempt to use SWAT without the Developer Tools, it will almost run, but will generate seemingly unintelligible error messages.

Open your /etc/services file and add the following line:

 swat         901/tcp # SWAT 

Assuming you're running xinetd , create a new file /etc/xinetd.d/swat with the following contents:

 service swat {         disable         = no         socket_type     = stream         wait            = no         user            = root         server          = /usr/sbin/swat         groups          = yes         flags           = REUSE } 

If you're using inetd , add the following line to the end of /etc/inetd.conf :

 swat stream tcp nowait root /usr/libexec/tcpd /usr/sbin/swat 

This tells the inetd (Internet Daemon) to start /usr/sbin/swat when it gets a request for the SWAT service. It also employs TCP Wrappers to protect against unauthorized incoming requests .

SWAT is ready to run. Either reboot Mac OS X to enable SWAT access on port 901, or use kill -HUP to reload settings for the inetd or xinetd processes. (You'll need to use sudo to do this.)

To configure Samba, start a Web browser and point it at port 901 of the Samba server ( http://localhost:901 ). SWAT will prompt for an administrative username and password; use the root account to have access to all features.

The top of the SWAT display, shown in Figure 16.6, includes seven buttons to control the server's operation:

  • Home . Provides links to Samba documentation and supplemental material.

  • Globals . Settings that affect the entire server, such as its name and security model.

  • Shares . Shared file resources. If you used the sample configuration file that came with the Apache distribution, there should be a single home directory share already configured.

  • Printers . Shared printers. To share a printer, it must first be set up so that it can be accessed from the lpr command in Unix.

  • Status . Monitor and view the status of the server. If logged in as root , you can restart or stop the server process.

  • View . View a copy of the text configuration file.

  • Password . Set and edit Samba user passwords.

Figure 16.6. SWAT opens with a page providing easy access to Samba documentation.

graphics/16fig06.jpg

Security configuration is scattered throughout these seven pages, so we'll cover what is appropriate for basic setup and security as well as the configuration directives contained in the default /etc/smb.conf file.

TIP

You can also handle security through the Mac OS X firewall by restricting access to TCP/UDP ports 137-139 (Samba), and TCP 901 (SWAT). Since SWAT runs as root and controls file sharing for your whole system, you should, at the very least, limit access through xinet / TCP Wrappers .

Globals

The Globals Variables page is the starting point for setting up your Samba server. Many people jump the gun and immediately start setting up file shares. Failure to properly configure the global options might make it impossible to mount or browse shared resources.

Three buttons can save server settings (Commit Changes), reset changes (Reset Values), or access advanced options (Advanced View). Choosing Advanced View shows additional options, a number of which are listed in Table 16.3. If you don't see the setting you're looking for in default view, move to the Advanced mode.

Table 16.3. Globals Options and Their Purpose

Option

Purpose

coding_system

Defines the how Japanese characters from the client computer are mapped to the Unix file system. It is unlikely that you will ever need to change the default Mac OS X setting.

client_code_page

Specifies the code page that Samba clients will use to access the server. It is unlikely that you will ever need to change the default Mac OS X setting.

workgroup

Sets the workgroup or domain to which the server belongs. Set this to the same value as the workgroup/domain of local Windows clients; otherwise , they will not be able to browse the server.

netbios_name

The Windows (NetBIOS) name of the server.

netbios_aliases

A list of additional NetBIOS names to which the Samba server will respond. (Advanced)

password_level

The number of case changes that will be checked between the client login and the server password. Because client operating systems might transmit passwords in uppercase, they have to be altered to authenticate with the server. (Advanced)

username_level

The same as the password level, but alters the username in a similar manner. For example, if I have a Mac OS X username of jray and a Windows login of JRAY , I have to set this value to 4 for it to be successfully permuted into the lowercase version. (Advanced)

server_string

The text used to identify the server.

interfaces

The network interfaces that Samba will broadcast over. For example, Mac OS X's primary interface is en0 . By default, all active interfaces will be used. To limit the interfaces, enter the interface names to use, or the network address followed by a subnet mask (that is, 192.168.0.0/255.255.255.0 ).

security

The type of security model to use. User security bases access upon a user login. Share password protects individual shared resources. Domain and server security passes authentication duties to other NT or Samba servers, respectively. You'll probably want user or share-level security.

encrypt_passwords

Sets encrypted password negotiation with the client. If you are using Windows 98 or later, set this to Yes . Encrypted passwords also require the use of the smbpasswd file, which is configured through the SWAT Password page. The Mac OS X default is Yes .

update_encrypted

Used when migrating from an unencrypted password on an existing server to a local encrypted smbpasswd file. This shouldn't be needed unless you are using an advanced configuration.

guest_account

The local user that should be used for guest access and resource browsing. Mac OS X should use unknown .

hosts_allow

A list of hostnames, IP addresses, IP addresses and subnet masks ( 192.168.0.0/255.255.255.0 ), or partial addresses ( 192.168.0. ) that can access the server. The except keyword can create an exception to a rule. For example, 192.168.0.0/255.255.255.0 except 192.168.0.5 would allow any host in the 192.168.0.0 subnet, except 192.168.0.5 , to access the server. If left blank, all remote hosts can access the server.

hosts_deny

Like hosts allow , but used to list servers that should not have access to the server. Configured by the same method as allow .

log_file

The logfile in which to store server accesses. The %m in the default path appends the name of the remote machine to the logfile name.

max_log_size

The maximum size in kilobytes that a logfile should be allowed to reach before rolling over.

os_level

A number used to determine the ranking of Samba when a master browser is being elected on a Windows network. If Samba is the only server on the network, use the default 20 . If NT 4.0 or 2000 machines are on the network, and you'd like Samba to be the master browser, set this to a value greater than 32 .

domain_logon

Accept domain logins. This allows Windows clients to recognize the Samba server as a PDC (Primary Domain Controller). (Advanced)

preferred_master

If set to yes , the Samba server will attempt to force an election for master browser. Do not use on networks with multiple servers that want to be masters.

local_master

Enables Samba to try to become the master browser for the local area network. If set to no , it will not attempt to assume this role.

domain_master

Enables Samba's nmbd component to become a domain master browser that collects browse lists from remote subnets.

dns_proxy

Attempts to resolve WINS queries through DNS if they cannot be resolved from locally registered machines.

wins_server

A remote WINS server that Samba should query to service NetBIOS name requests.

wins_support

Enables Samba's WINS service. Only a single machine should act as a WINS server on a given subnet.

The default settings should be sufficient for most small networks, with the exception of the base and security options.

Samba security is set both globally for the server and for each individual share. What follows are the global settings you may want to consider changing to either alter the type or improve the quality of security on your machine.

Security Levels

Before creating a share, you need to decide what security model to use for the server ”set with the security directive. By default, Mac OS X's Samba implementation uses the user security level.

  • User level . The easiest security model to manage is user level, which requires Windows users to log in to their computers with the same username and password that they set up on the Mac OS X machine. When using user-level access, Windows users are mapped directly to Samba users. The Mac OS X file permissions apply directly to the permissions of the connected user. Assume, for example, the Mac OS X user jray has read/write permissions to the folder /Stuff , which is also set to be a Samba share. If jray logs in to a Windows computer using the same username as on Mac OS X, he will be able to access the Stuff share and have read/write access. The SWAT Password page or smbpasswd utility (covered shortly) can be used to map Unix users to the passwords that they will use on the remote Windows client if it doesn't match their default OS X password.

  • Share level . In the case of share security, a single password is needed to access the share for all users. The Mac OS X user that is used to access the data depends on the share configuration and the password that is given when mounting the share. This can be a bit confusing because unlike Windows, where you can set a password for a share, Samba still requires a password and username for share security, but the username is determined dynamically based on the share configuration. If a share is set with a username directive, whichever username whose password matches what the client supplies when connecting is then used to access the data. If a username is not supplied, then the guest_account password is used as the share password.

    To simplify share-level security, create a new Mac OS X user with Allow User to Log In from Windows permissions. Then set the username option for the share equal to the Mac OS X username.

  • Server/Domain level . Server-level security can be used if you need to integrate with an existing Windows server. When using server or domain security, the Samba process attempts to authenticate usernames and passwords against an existing SMB server or an NT Domain, respectively. The password_server directive is used to set the queried server. The encrypt_passwords must be set to yes .

NOTE

Samba has rudimentary support for acting as a PDC. It does not support operating as a BDC. For a simple tutorial on setting up Samba as a PDC, visit http://hr.uoregon.edu/davidrl/samba/.

Limiting Access

The hosts_allow and hosts_deny directives should be used, if possible, to limit Samba access to only the client or client subnet that will be accessing your server. If you have multiple network connections, be sure that the interfaces setting is applied to only the interfaces that should provide SMB service. If, for example, you're using the Mac OS X Internet sharing feature, you may not want to enable Samba on the broadband interface.

Encrypted Passwords

To negotiate encrypted password transmission with the connecting client, set encrypt_passwords to yes . Clients earlier than Windows 98 do not support encrypted passwords, so if you have any early Windows machines connecting, this should be set to no . The Mac OS X default is yes .

Password and Username Mangling

The username _ level and password_level directives control the number of case permutations between a true password/username and the user-supplied information that can take place and still be considered a match. A username_level of 1, for example, would allow one permutation ”matching " Jray " to " jray " ” while 2 could match " JrAy" to " jray" , and so on. Setting these to zero forces an exact password match and is recommended. Higher values increase the possibility of an attacker being able to access your system with what would normally be an incorrect password.

Shares

The Share Parameters page sets up file shares that can be mounted on networked Windows-based computers. To create a new share, type a share name in the Create Share field, and then click the Create Share button. To edit an existing share, choose its name from the pop-up list, and then click Choose Share ”or click Delete Share to remove it completely. With the default Mac OS X Samba configuration file, there should be a single homes share already available. The homes share is unique because it is equivalent to each user sharing his home directory with himself.

Like the Globals Variables page, there is an Advanced button to show all possible configuration features for file sharing. Table 16.4 lists the sharing- and security- related options.

Table 16.4. File-Sharing Options and Values

Option

Purpose

comment

A comment to help identify the shared resource.

path

The pathname of the directory to share. Be aware that in user-level security, you must make sure that the corresponding Mac OS X user accounts have access to this directory. When using share-level security, a single-user account is used ”usually either the guest_account or an account specified with username .

guest_account

The account used to access the share if the remote client is logged in as a guest. The default is nobody , but, if set to another username, the guest user will have the read/write permissions of that local user account. If you want to use share-level access control, you can set this value to the account whose permissions should be used when accessing the share.

force_user

If entered, the force_user username will be used for all accesses (read/write) to the file share, regardless of the username used to log in. (Advanced)

force_group

Similar to force_user but forces a group rather than a user. (Advanced)

read_only

When set to Yes , users cannot write to the share, regardless of the Mac OS X file permissions.

create_mask

A set of permissions that newly created files will have. By default, the mask is set to 0744. (Advanced)

inherit_permissions

When set to yes , new directories will inherit the Unix permission bits from the parent (enclosing) directory.

guest_ok

If set to yes , guests can log in to the server without a password.

hosts_allow

A list of hostnames, IP addresses, IP addresses and subnet masks ( 192.168.0.0/255.255.255.0 ), or partial addresses ( 192.168.0. ) that can access the share. The except keyword can create an exception to a rule. For example, 192.168.0.0/255.255.255.0 except 192.168.0.5 would allow any host in the 192.168.0.0 subnet, except 192.168.0.5 , to access the server. If left blank, all remote hosts can access the server.

hosts_deny

Like hosts_allow , but used to list servers that should not have access to the server. Configure using the same method as allow .

max_connections

Restricts the number of simultaneous users who can access the share. (Advanced)

browseable

When set to yes , the share shows up in the Windows network browser. If No , the share still exists, but remote users cannot see its name.

available

If set to yes , the share is made available over the network. Setting to no disables access to the share.

username

A comma-separated list of usernames whose passwords are to be used for login validation. If a username is prefixed with a + , the username is interpreted as a group name and is expanded to all the users within the group. (Advanced)

valid_users

A list of usernames that will be allowed to access the share. If a username is prefixed with + , it will be processed as a group name.

veto_files

A / -separated list of file/directory names that will be invisible and inaccessible via a mounted share. The wildcards * (any character string) and ? (any single character) can be used as within the names. For example, /*.html/*.tmp/tmp????.txt . This feature can be used to stop the spread of viruses by denying access to certain types of Windows files, such as .eml , .vbs , .dll and other files commonly created by virus-infected clients. (Advanced)

hide_files

Like veto_files , but files are only hidden; they still remain accessible to the client. (Advanced)

hide_unreadable

When set to yes , files that are unreadable to a given user are hidden. (Advanced)

invalid_users

The opposite of the valid_users directive, useful within the homes share. (Advanced)

Users and Permissions

As with the global settings, share access can be limited by IP with the hosts_allow and hosts_deny directives. Restricting a volume to a specific user is performed with the valid_users and invalid_users options, both of which can also accept a group name prefixed with a + to simplify user management.

Users who are sharing directories that need to maintain file ownership different from the logged-in Samba user may find the force_user and force_group directives useful. These can be employed to force all file accesses to be from a named user and group (such as www ). In cases where overlapping file sharing is taking place, such as via WebDAV and Samba, this can greatly ease the difficulty of maintaining compatible permissions.

To alter the umask for files that are created via Samba, use the create_mask directive with a standard Mac OS X umask setting. If you want to provide read (no write) access to files regardless of the actual file permissions, set the read_only attribute equal to yes .

Disabling and Hiding Shares and Files

To temporarily disable an active share, set the available directory to no . You can hide active shares from direct Network Neighborhood browsing by setting browseable to no . This does not keep users from accessing the share, but they need to know the share name to connect.

CAUTION

Disabling browseability is not an acceptable form of security. The browseable attribute is useful for setting up temporary administrative shares or other shares that don't necessarily need to be advertised to your general user base.

You can hide the files contained within a share based on simple name patterns with DOS-style * and ? wildcards that you set by using the hide_files directive. Hidden files remain accessible by name, but appear (to Windows) as if they have the hidden attribute set. To easily hide any file that a user can't read, set hide_unreadable equal to yes .

To make files both hidden and inaccessible, use veto_files , which blocks any user interaction with files matching the supplied pattern.

Printers

Samba can act as a full print server for a Windows network. The one small catch is that your printers must first be accessible via lpr at the command line.

To create a new shared printer, enter a name (for the Windows network) in the Create Printer field, and then click the Create Printer button. You can select an existing printer from the pop-up menu and edit it by clicking Choose Printer, or remove it from the Samba configuration by clicking Delete Printer.

From Samba's perspective, there is very little difference between a shared printer and a file share. The same directives used to configure and secure shared files can also be applied to a printer. The common printer-specific directives are shown in Table 16.5.

Table 16.5. Printer-Sharing Options

Option

Purpose

path

A directory where print spool files will be saved before printing. The directory must be configured to be world-writable and have the sticky bit set.

printable

Allows authenticated clients to write to the print spool directory.

printer name

The CUPS name for the printer. You must switch to Advanced View to see this option. To view a list of the CUPS-recognized printers on your system, type lpstat -p . Any available printer can be shared.

postscript

Forces print jobs to be interpreted as PostScript.

Status

The SWAT Status page provides a quick overview of the server's current conditions, including active connections, shares, and files. The administrator can use this screen to restart the server or disable any active connections.

Each of the visible buttons effects a change on the server:

  • Auto Refresh . Sets the SWAT status page to auto refresh based on the Refresh Interval field. This is useful for monitoring server activity.

  • Stop/Start/Restart smbd . Stops, starts, or restarts smbd ”the Samba SMB file/print server. All active connections are terminated .

  • Stop/Start/Restart nmbd . Stops, starts, or restarts nmbd ”the Samba NetBIOS name server. Does not affect active connections.

  • Kill . The Kill button appears to the right of every listed connection. Clicking the button immediately terminates the link.

TIP

Samba ( smbd ) must be restarted for changes to the configuration to take effect.

View

View offers a glimpse at the configuration file behind SWAT's GUI. Sometimes it's easier to scan through a text file to locate a problem than to work with the Web interface. There are two modes in the View page. The Normal view shows the minimum configuration file needed to implement your settings.

Switching to the Full view displays all the settings, including default options, for the Samba configuration. Each option is explicitly listed, regardless of its necessity.

Samba Passwords

Any user who has Windows access enabled through the Allow User to Log In from Windows option already has a Windows password enabled and stored in a private hash file found in /private/var/db/samba/hash/ . As long as she is satisfied with using the same password on both Mac OS X and Windows, there are no changes you need to make.

If a user wants to use a different password to access Samba from a Windows computer, she can use the SWAT password settings to add a new password entry in the /private/var/db/samba/smbpasswd file.

The SWAT Password page is used to set up Samba passwords for existing Mac OS X users, or change remote user passwords if using domain-level security and a remote host for user authentication.

The Server Password portion of the screen configures local users and passwords. Be aware that these options do not affect the actual Mac OS X usernames and passwords, but must be based on valid local usernames. If you've enabled a Mac OS X user so that he can log into his account from Windows, you've effectively already used this feature. There is no need to set a new password unless you want a Windows login password that is different from your Mac OS X password.

The following options are found in the Server Password page:

  • User Name . The Mac OS X username to add to the Samba password database file. Only required for Mac OS X users where the Allow User to Log In from Windows option has not been selected.

  • New Password . The Samba password to set for that user.

  • Re-type New Password . The same as the New Password option; used to verify typing.

  • Change Password . Changes the password for a given user.

  • Add New User . Adds the new username/password mapping to the Samba password database.

  • Delete User . Deletes the named user from the Samba password database. This does not affect the Mac OS X user.

  • Disable User . Disables a user's ability to access Samba. Again, Mac OS X does not alter its user account whatsoever.

  • Enable User . Enables a disabled user account.

If Samba is using domain-level security, another server (such as a Windows primary domain controller) is the source for all authentication information. To change a user's password on the remote server, use the Client/Server Password Management features of the Password screen:

  • User Name . The remote user to change.

  • Old Password . The user's existing password.

  • New Password . The new password to set on the remote server.

  • Re-type New Password . The same as the New Password option; used to verify typing.

  • Remote Machine . The remote server that contains the username/password mappings.

Click the Change Password button to send the password changes to the remote server.

An alternative to SWAT password management is to use the smbpasswd command-line utility.

smbpasswd

The smbpasswd command is used to alter user information in the /private/var/db/samba/smbpasswd file. This can be used to set up Samba user account passwords from the command line or shell scripts.

By default, the smbpasswd command changes the Samba password for the currently logged in Mac OS X user:

 %  smbpasswd  Old SMB password: New SMB password: Retype new SMB password: Password changed for user jray 

As an administrative user, you can perform several additional functions with the command. The complete syntax for the smbpasswd is smbpasswd <options> <username> <password> . Table 16.6 shows the available options.

Table 16.6. smbpasswd Options

Option

Purpose

  -a  

Adds a new username to the local smbpasswd file.

  -d  

Disables the named user.

  -e  

Enables the named user.

-D <0-10>

Sets a debug level between 0 and 10 to control the verbosity of error reporting.

  -n  

Sets a user's password to null.

-r < remote host >

Sets the remote host to send password changes.

-j < domain name >

Joins a domain.

-U < username >

The username to send to the remote host when using -r .

  -h  

Displays a command summary.

  -s  

Silent output. Accept all input from standard input. This is useful for scripting smbpasswd .

smbstatus

The smbstatus utility provides information about the active connections and users. This is equivalent to the Status page within the SWAT management tool. For example:

 %  /usr/local/samba/bin/smbstatus  Samba version 2.2.3a Service      uid      gid      pid     machine ---------------------------------------------- Programs  jray jray  12746   brushedtooth (192.168.0.107) Sun Sep 1 03:46:41 2002 MyMP3s    jray jray  12746   brushedtooth (192.168.0.107) Sun Sep 1 22:21:32 2002 No locked files 

The available smbstatus options are shown in Table 16.7.

Table 16.7. smbstatus Options

Option

Purpose

  -b  

Summary of connected users.

  -d  

Detailed connection listing. This is the default mode.

  -L  

Lists locked files only.

  -p  

Lists the smbd process IDs and exits.

  -s  

Lists connected shares only.

-s <config file>

Chooses the smb.conf file to use.

-s <username>

Displays only information relevant to a given username.


   
Top


Mac OS X Maximum Security
Maximum Mac OS X Security
ISBN: 0672323818
EAN: 2147483647
Year: 2003
Pages: 158

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net