This discussion is locked
Adam Wenocur

Q: Can the mount_afp command in Leopard use Keychain as it did in Tiger?

Has anyone been able to use a keychain password with the mount_afp command in Leopard?

I had this working in Tiger, but in Leopard all of my remote mounts are being stored in the keychain as network passwords identified by URL rather than as AppleShare passwords. I tried adding /sbin/mount_afp to the list of allowed applications for these network passwords as I did in Tiger, and mount_afp can't find the keychain items, even when the URL in the keychain item is identical to the URL I specify on the command line.

These keychain items do work in the Finder (via NetAuthAgent), even after I modify the URLs, adding such things as port numbers and usernames.

Late 2005 PowerBook G4, Mac OS X (10.5.2)

Posted on Feb 18, 2008 9:31 PM

Close

Q: Can the mount_afp command in Leopard use Keychain as it did in Tiger?

  • All replies
  • Helpful answers

  • by Adam Wenocur,

    Adam Wenocur Adam Wenocur Mar 12, 2008 4:20 PM in response to Adam Wenocur
    Level 2 (285 points)
    Mar 12, 2008 4:20 PM in response to Adam Wenocur
    I found a workaround for this by writing a program that uses the Security framework to grab the password from the keychain, calls /sbin/mount_afp via execve, and pipes the password to the stdin of the mount_afp process. This isn't as good a solution as having mount_afp use the keychain directly, as it foregoes the checksum of the process image, and hence would not detect a malicious program substituted for mount_afp.

    If this functionality were present in mount_afp for Leopard, I'd still find it useful.
  • by LuigiG,

    LuigiG LuigiG Mar 17, 2008 1:43 PM in response to Adam Wenocur
    Level 1 (0 points)
    Mar 17, 2008 1:43 PM in response to Adam Wenocur
    Hi,

    Would it be too intrusive too ask for the source code?
    I'm exactly in the same boat!

    Cheers,
    L
  • by Adam Wenocur,

    Adam Wenocur Adam Wenocur Mar 24, 2008 2:28 PM in response to LuigiG
    Level 2 (285 points)
    Mar 24, 2008 2:28 PM in response to LuigiG
    Sure, let me clean it up a bit, and I'll post it.
  • by Adam Wenocur,

    Adam Wenocur Adam Wenocur Mar 24, 2008 9:29 PM in response to Adam Wenocur
    Level 2 (285 points)
    Mar 24, 2008 9:29 PM in response to Adam Wenocur
    The following C program should be compiled with the Security framework as follows:

    cc -framework Security -o mountwrapper mountwrapper.c

    This program works only under Leopard, and requires that you have an AFP Internet password in your keychain with the exact hostname, username, and port number you specify on the command line. It does not look for approximate or ambiguous matches.

    #include <unistd.h>
    #include <stdio.h>
    #include <Security/SecKeychain.h>
    #include <stdlib.h>
    #include <string.h>

    extern char **environ;

    int main(int argc, char **argv)
    {

    UInt32 passwordLength = 0;
    void *passwordData;
    OSStatus keychainStatus = 0;
    UInt16 serverPort = 0;
    if(argc < 6)
    {
    fprintf(stderr, "Usage: mountwrapper <hostname> <username> <share> <port> <mountpoint>\n");
    return 1;
    }
    sscanf(argv[4], "%hu", &serverPort);
    keychainStatus = SecKeychainFindInternetPassword(0, strlen(argv[1]), argv[1], 0, 0, strlen(argv[2]), argv[2], strlen(argv[3]), argv[3], serverPort, kSecProtocolTypeAFP, kSecAuthenticationTypeDefault, &passwordLength, &passwordData, 0);
    if(keychainStatus || !passwordLength)
    {
    fprintf(stderr, "Keychain error: %i\n", keychainStatus);
    return 1;
    }
    int pipein = 0, pipeout = 0, forkValue;
    {
    int myPipes1[2], myPipes2[2];
    pipe(myPipes1);
    pipe(myPipes2);
    forkValue = fork();
    if(forkValue)
    {
    pipein=myPipes1[0];
    pipeout=myPipes2[1];
    close(myPipes2[0]);
    close(myPipes1[1]);
    }
    else
    {
    pipein = myPipes2[0];
    pipeout = myPipes1[1];
    close(myPipes1[0]);
    close(myPipes2[1]);
    }
    }

    if(!forkValue)
    {
    setsid();
    int URLLength;
    char *URL = malloc((URLLength = strlen(argv[1]) + strlen(argv[2]) + strlen(argv[3]) + strlen(argv[4]) + 12) + 1);
    char *newArgv[] = {"mount_afp", "-i", "-o", "nobrowse", URL, argv[5], 0};
    char *newEnv[] = {0};
    snprintf(URL, URLLength, "afp://%s@%s:%hu%s", argv[2], argv[1], serverPort, argv[3]);
    while(pipein < 3)
    {
    int oldpipein;
    pipein = dup2(oldpipein = pipein, 8);
    close(oldpipein);
    }
    while(pipeout < 3)
    {
    int oldpipeout;
    pipein = dup2(oldpipeout = pipeout, 9);
    close(oldpipeout);
    }
    dup2(pipein, 0);
    dup2(pipeout, 1);
    dup2(pipeout, 2);
    execve("/sbin/mount_afp", newArgv, environ);

    }
    else
    {
    char buffer\[1024\];
    int returnParams = 0;
    write(pipeout, passwordData, passwordLength);
    write(pipeout, "\n", 1);
    size_t bytesRead = read(pipein, buffer, 1024);
    size_t bufferOffset = 0;
    if(bytesRead > 10)
    if(!strncmp(buffer, "Password:", 9))
    bufferOffset += 11;
    fwrite(buffer + bufferOffset, 1, bytesRead, stderr);
    wait(&returnParams);



    }
    return 0;
    }
  • by Adam Wenocur,

    Adam Wenocur Adam Wenocur Mar 25, 2008 12:14 AM in response to Adam Wenocur
    Level 2 (285 points)
    Mar 25, 2008 12:14 AM in response to Adam Wenocur
    oops; I put a potential buffer overrun in there; that line toward the end should be:

    fwrite(buffer + bufferOffset, 1, bytesRead - bufferOffset, stderr);

    not:

    fwrite(buffer + bufferOffset, 1, bytesRead, stderr);
  • by LuigiG,

    LuigiG LuigiG Apr 7, 2008 12:10 PM in response to Adam Wenocur
    Level 1 (0 points)
    Apr 7, 2008 12:10 PM in response to Adam Wenocur
    Hey, unsigned (1<<32) thanks!!