#
#	File:		AppleShare X Client Developer Notes, version 1.0.0
#
#	Contains:	Misc helpful stuff about AppleShare Client in Mac OS X
#
#	Compiled by:	Brad Suinn
#
#	Copyright:	© 2001 by Apple Computer, Inc., all rights reserved.
#
#	Writers:
#
#		(bms)	Brad Suinn 
#
#	Change History (most recent first):
#
#				5/25/01	bms		Initial brain dump
#
#	To Do:
#
#   


/*	-------------------------------------------------------------------------
	This is an active project, so any and all of this is subject to change
	without notice at any time.  No guarentees that any of this is correct, 
	but I will do my best to keep it updated.  I figured you would rather 
	have this information NOW, rather then waiting for the nice pretty copy
	later on.
	------------------------------------------------------------------------- */

/*	-------------------------------------------------------------------------
	Deleting busy files
	------------------------------------------------------------------------- */
	If a remove is done and the file is currently open/busy,
	1)  Look at dir id 2 and see if a ".AFP Temp" private meta data folder exists
	2)  If not, attempt to create one and make it invisible and off the desktop view
	3)  If private meta data folder was created, item is renamed to be
	    "tempXXX" where XXX is nodeID and then moved to the private meta data
	    folder.  If the private meta data folder failed to create, then return
	    EBUSY.
	
/*	-------------------------------------------------------------------------
	Server signatures
	------------------------------------------------------------------------- */
	All AFP servers should support server signatures.  If not, the Mac OS X GM
	client gets confused about where the server is already mounted or not.  
	If you do not support server signatures, you better have a server names
	that are unique because that will be our fall back to create a signature
	for you (coming soon).
	
	
/*	-------------------------------------------------------------------------
	Unix permissions & UTF8 name code support
	------------------------------------------------------------------------- */
    If the afp version is AFP 2.X, then Unix privileges and UTF8 name
    support is automatically disabled.
    

/*	-------------------------------------------------------------------------
	Unix permissions
	------------------------------------------------------------------------- */
    // struct returned when the kFPUnixPrivsBit is used
    struct FPUnixPrivs {
	    unsigned long uid;
	    unsigned long gid;
        unsigned long permissions;
        unsigned long ua_permissions;
    };
	
	1)  permissions is the full unix permissions including the execute bits.  This
	bitmap is used when the client is changing the permissions on the server.  
	Note:  This is also how I determine if its a symlink or not by checking
	the IFMT flag.
	2)  ua_permissions is in the same format as the AFP Access rights (refer to
	Inside AppleTalk, page 13-88) consisting of
	
	kSP = 1, kRP = 2, kWP = 4, kOwner = 128
	
	UARights - one byte with kOwner if owner and kRP/kWP, kSP if has execute permission
	World - one byte with kRP/kWP, kSP if has execute privs
	Group - one byte with kRP/kWP, kSP if has execute privs
	Owner - one byte with kRP/kWP, kSP if has execute privs

	Note:  We are mapping the kSP bit directly to the unix execute permission
	3)	If kFPUnixPrivsBit is supported, then it must be supported on 
	directories AND files.

	
/*	-------------------------------------------------------------------------
	FPGetFileDirParms Attribute bits
	------------------------------------------------------------------------- */
	Supported bits are Invisible, MultiUser, and the Inhibit bits
	Inhibit bits map to "locked box" which is IMMUTABLE on Mac OS X

	Not supported Bits and why:
	System - AShare Client 3.8.x does not support it
	DAlreadyOpen/RAlreadyOpen - VIDI fakes these up without us
	BackupNeeded - AShare Client 3.8.x does not support it
	CopyProtect - Not supported any more
	IsExpFolder/Mounted/InExpFolder - not supported by Mac OS X Personal File
	Sharing


/*	-------------------------------------------------------------------------
	Multiple mounts from same server
	------------------------------------------------------------------------- */
    When a server is mounted, its server signature is converted from 16 bit 
    ASCII to 24 bit ASCII.  Then a server string of "afp_%s-%d" is created 
    with %s being the 24 bit ASCII server sig and %d being the volume id.  This
    server string is then used in the mount points mnt_stat.f_mntfromname.
    When another servers is being accessed, we get the server sig of the server,
    convert it to the 24 bit ASCII, then check all current mount points and 
    string compare it to mnt_stat.f_mntfromname.  If it matches, then the 
    server is already mounted and we use that session.


/*	-------------------------------------------------------------------------
	Permissions mapping notes
	------------------------------------------------------------------------- */
    1)	Permissions mapping AFP 2.X are:
	    a)  For AFP 2.X, Files get same permissions as enclosing folder
	    b)	Files always have execute
	    c)	Directories have execute if they have either Read or Write access
    2)	AccessDate and AttributeModDate just set to AFP modification date
    3)  Under Cocoa, the gid is always "unknown" because we have no way of
        knowing if the local and server permissions are in the same scope.
        ie is the local user bsuinn in the exact same group as the 
        AFP user of "Brad Suinn"?  Consider if bsuinn is part of the unix group
        apple_sw_engineers that has 500 people, while AFP user "Brad Suinn"
        is just part of the group AppleShare_Engineers with only 5 members.
    4)  If unix permissions are not supported, 
        b)  Under Cocoa, all files and folders are set to be the uid
        c)  Under Cocoa, "owner" access rights are set by using the AFP 
        UARights.  "other" rights are from AFP World access rights.  "group"
        access rights are always zero.
    5)  The full AFP access rights can be obtained from cocoa by making a
        fsctl call on the desired folder/file.


/*	-------------------------------------------------------------------------
	FPGetFileDirParms and kFPUTF8Name pathtype
	------------------------------------------------------------------------- */
	When kFPUTF8Name is used in the FPGetFileDirParms, the reply parameters will
	have a two byte utf8 name offset AND then a extra four bytes of zeros.  Since
	we are reusing the old ProDosInfo bit, we wanted to make it the same size
	reply field.


/*	-------------------------------------------------------------------------
	PathTypes
	------------------------------------------------------------------------- */
	kFPShortName = 1	(Not supported by OS X AppleShare client)
	kFPLongName = 2
	kFPUTF8Name = 3
	
	
/*	-------------------------------------------------------------------------
	New Function Codes
	------------------------------------------------------------------------- */
	kFPByteRangeLockExt = 		59,
	kFPCatSearchExt = 			67, 
	kFPEnumerateExt = 			66, 
	kFPReadExt = 				60, 
	kFPWriteExt = 				61,
	kFPGetSessionToken = 		64,
	kFPDisconnectOldSession = 	65

	
/*	-------------------------------------------------------------------------
	New Volume Attributes from the FPGetVolParms
	------------------------------------------------------------------------- */
    kSupportsUnixPrivs = 		0x20,
    kSupportsUTF8Names = 		0x40

	Note:  if kSupportsUnixPrivs is set, then it must be supported on 
	directories AND files.


/*	-------------------------------------------------------------------------
	Subfunctions for FPMapID and FPMapName
	------------------------------------------------------------------------- */
	For FPMapID,
	Subfunction 1 is map User ID to Mac Roman User name
	Subfunction 2 is map Group ID to Mac Roman Group name
	Subfunction 3 is map User ID to UTF8 User name
	Subfunction 4 is map Group ID to UTF8 Group name
	
	For FPMapName,
	Subfunction 1 is map UTF8 User name to User ID
	Subfunction 2 is map UTF8 Group name to UTF8 Group ID
	Subfunction 3 is map Mac Roman User name to User ID
	Subfunction 4 is map Mac Roman Group name to UTF8 Group ID
	
	
/*	-------------------------------------------------------------------------
	Drop Boxes and Locked Folders Unix Permissions 
	------------------------------------------------------------------------- */
	1)  A Drop Box Folder icon (blue circle with plus sign on it) will appear when 
	the folder has Write and Execute access
	2)  A Locked Folder icon (red circle with horizontal line) will appear when the 
	folder has no permissions at all
	
	
/*	-------------------------------------------------------------------------
	NodeIDs MUST be unique! 
	------------------------------------------------------------------------- */
    Files and folders must have unique File Numbers and Directory IDs that are
    returned in the FPGetFileDirParms.  I used those ids as indexs into some
    hash tables.  Those same ids will also be used in the FPResolveID when 
    needed.
	
	
/*	-------------------------------------------------------------------------
	fsctl calls supported by AppleShare, see afpfs.h for defines
	------------------------------------------------------------------------- */
    #define FSCTL(path, cmd, data, options) syscall(242, (path), (cmd), (data), (options))

    #define afpfsGetParmsFSCTL		    _IOR('z', 11, struct GetParmsPB)
	#define afpfsGetMountInfoFSCTL		_IOWR('z', 12, struct afpfs_mount_args)
	#define afpfsCreateFileDescFSCTL	_IOWR('z', 13, struct CreateFileDescPB)
	#define afpfsMapIDNameFSCTL		    _IOWR('z', 14, struct MapIDNamePB)
	#define afpfsGetAccessRightsFSCTL	_IOR('z', 15, struct AccessRightsPB)
	#define afpfsSetAccessRightsFSCTL	_IOW('z', 16, struct AccessRightsPB)
	#define afpfsByteRangeLockFSCTL		_IOWR('z', 17, struct ByteRangeLockPB)
	#define afpfsGetAttenFSCTL		    _IOWR('z', 18, struct GetAttenPB)
	#define afpfsSleepWakeFSCTL		    _IOW('z', 19, struct SleepWakePB)
	#define afpfsUserCommandFSCTL	    _IOWR('z', 20, struct UserCommandPB)

    example:
        static char gDefaultTargetPath[] = "/Volumes/Remote_HFS/";
        struct UserCommandPB pb;
        
        result = FSCTL(target, afpfsUserCommandFSCTL, &pb, 0);

    1)  afpfsGetParmsFSCTL - returns server quantum size and current socketID (used for reconnect)
    2)  afpfsGetMountInfoFSCTL - returns args used to mount the server.  Some special values are:
        sockfd = 0;
        isPasswordEncrypted = 1;    /* I encrypt the password before returning it */
        volumePassword is not encrypted.  
    3)  afpfsCreateFileDescFSCTL - no longer supported.  Always returns ENOTSUP.
    4)  afpfsMapIDNameFSCTL - makes the FPMapID or FPMapName call for you.
    5)  afpfsGetAccessRightsFSCTL - returns the AFP Access Rights.
    6)  afpfsSetAccessRightsFSCTL - sets the AFP Access Rights .
    7)  afpfsByteRangeLockFSCTL - implements the byte range locks.
    8)  afpfsGetAttenFSCTL - returns some misc info.  Not really for use by anyone else.
    9)  afpfsSleepWakeFSCTL - sends the FPZzz packet to server.
    10) afpfsUserCommandFSCTL - allows a packet to be sent using the current session.  
        If pb->afpPB.commandCode != dsGetReply, then it sends the command, else it gets the reply.
        In the future, this will be wrapped up in a nice API to be used for session stealing.
        Use at your own risk for now.
    
    
/*	-------------------------------------------------------------------------
	symlinks
	------------------------------------------------------------------------- */
    1)  If unix permissions are supported, then I check if (unixPermissions & IFMT) == IFLNK,
    then its a symlink.
    2)  If unix permissions are not supported, then if the file type is 'slnk' and
    the creator is 'rhap', then its a symlink.


/*	-------------------------------------------------------------------------
	Carbon Deny Modes
	------------------------------------------------------------------------- */
    1)  In cocoa, O_SHLOCK -> kDenyWrite
    2)  In cocoa, O_EXLOCK -> kDenyRead and kDenyWrite
     
     
/*	-------------------------------------------------------------------------
	Setting up encrypted AFP sessions using ssh (from the clever Adam Wells)
	------------------------------------------------------------------------- */
	Here's how to do an AFP connection over SSH.  Both the client and the 
	server must have Mac OS X 10.0.3 installed (which comes by default on 
	Mac OS X Server, but the client needs to have it to get the latest 
	SSH software).

	In this example, the server is at IP address 192.168.0.100, and it 
	has a valid user named "brad" which was created earlier.

	On the Mac OS X Server machine:

	1) In System Preferences, go to the Sharing panel and check "allow 
	remote login".  This starts sshd.  (When you check the checkbox, it 
	may take several seconds before it fills in -- this is the machine 
	generating a new host key.)

	2) In Server Admin, start the IP Filtering service.  Set it to block 
	all ports, except port 22 (ssh).  (If you're administering the server 
	remotely, you'd also want to leave port 660 open for Server Admin.) 
	If you're not super security-conscious, set it to just block port 548.

	3) Start the AFP server.  It won't be able to listen on 
	192.168.0.100:548, since that's blocked by IP Filtering, but it will 
	still listen on localhost:548.  Note that until you turn off IP 
	Filtering, this AFP server will ONLY be able to accept encrypted 
	connections.

	On the Mac OS X Client:

	4) Open a new Terminal window, and issue this command:

	ssh -l brad 192.168.0.100 -L 10548:192.168.0.100:548 sleep 300

	(That's a lower-case "L" right after ssh.)  This logs into the server 
	via ssh, and then forwards local port 10548 to port 548 (afp) on the 
	server, over the encrypted connection.  It should prompt for the 
	password of user "brad".  If it's the first time you've made an ssh 
	connection from this client to this server, you'll get a message that 
	this is a new host key.  Standard ssh hygiene here -- verify the RSA 
	key fingerprint through some out-of-band method if you want to make 
	absolutely sure you're connecting to who you think you're connecting 
	to.

	5) In the Finder, hit Cmd-K to connect to a server and enter 
	"afp://localhost:10548".  This will connect to the local port, which 
	is forwarded over the SSH connection to the server, where it connects 
	to the AFP service on port 548.  (Note that you have 300 seconds to 
	complete your AFP login.)  It will popup an AFP username/password 
	window.  Log in with brad's username and password.  (You can, 
	however, actually log in with the username/password of any user on 
	the server -- it doesn't have to match the ssh username/password.) 
	The icon of the AFP server should appear on the desktop.

	6) Copy files, etc. over the AFP connection.  All file transfers are 
	encrypted with ssh -- anyone sniffing packets won't see cleartext AFP 
	data.

	7) When you're done, log out of the AFP server by dragging its icon 
	to the trash.  The encrypted ssh tunnel comes down and your SSH 
	connection is automatically disconnected.

	That's it!  To make a new connection to the server, you need to log 
	in via ssh again as in step 4.