23
votes

I'm trying to write function similar to http://whatismyudid.com/ that, then approved, will return the users UDID and store it to a database for future reference with that user.

I have written a .mobileconfig xml doc that opens in the Profile Installer just fine but when I tell it to install the profile it responds with [alert] Invalid Profile but no alert body. No description, no code, no help.

I'm new to the mobile configuration game so any help would thrill me.

Here is my configuration file:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>PayloadContent</key>
    <dict>
        <key>URL</key>
        <string>http://apps.mortlabs.com/device/retrieve.php</string>
        <key>DeviceAttributes</key>
        <array>
            <string>UDID</string>
            <string>IMEI</string>
            <string>ICCID</string>
            <string>VERSION</string>
            <string>PRODUCT</string>
        </array>
    </dict>
    <key>PayloadOrganization</key>
    <string>MortLabs.com</string>
    <key>PayloadDisplayName</key>
    <string>Profile Service</string>
    <key>PayloadVersion</key>
    <integer>1</integer>
    <key>PayloadUUID</key>
    <string>B958E359-34C2-42F4-BD0C-C985E6D5376B</string>
    <key>PayloadIdentifier</key>
    <string>com.mortlabs.profile-service</string>
    <key>PayloadDescription</key>
    <string>This temporary profile will be used to find and display your current device's UDID.</string>
    <key>PayloadType</key>
    <string>Profile Service</string>
</dict>
</plist>

The profile is initialized by navigating to http://apps.mortlabs.com/device/enroll.php with mobile safari

4

4 Answers

14
votes

I found that by using the above that Apache was being talked to by the Ipad/Iphone - The post by Kyle2011 at https://discussions.apple.com/thread/3089948?start=0&tstart=0 filled in the rest of the solution.

Basically at the bottom of the retrieve.php page you need to redirect the browser to a directory by using a line similar to the following:-

header("Location: https://www.example.com/enrolment?params={$params}");

Where enrolment is a directory - this then calls the DirectoryIndex (typically index.php) which can then display stuff to your user.

To populate the $params variable you need the following line at the top of your retrieve.php script

$data = file_get_contents('php://input');

You can then parse the $data string to get what you need (try file_put_contents("data.txt", $data); or Kyle2011's example)

I also changed the Payload UDID to something different by using udidgen in a terminal on a Mac rather than just using whatismyudid.com's.

Update: From iOS 7.1 some of the files (the .plist IIRC) need to be served over https:// - they will fail to install if everything is served over http:// - probably best to serve everything including the .ipa over https:// to ensure future changes on Apple's side don't cause a problem.

6
votes

Note about the last page ( FOLDER ).

If you want to use a page script for final redirection in place of a folder.

you can change this :

header("Location: https://www.example.com/enrolment?params={$params}");

by

header("Location: https://www.example.com/enrolment.php?params={$params}", true, 301);

Source : header function on php.net manual

it's work !

1
votes

Try setting the URL to an address without .php extension. This solved the problem for me. Now my only problem is that I can't find out how to retrieve the data sent from the iOS device to my server. It does not seem to be in the $_POST variable.

1
votes

The error you're getting is because iOS expects your profile service URL (the one it sends its UDID to) to return a configuration profile (i.e. a .mobileconfig file). I currently capture device UDIDs without returning this profile; my devices generate the alert you describe but the data is on my server.

For reference, here's the (very) simple PHP file I use to capture the data:

<?php
// set file to write
$file = 'device_data/data.p7s';

$fp = fopen($file, 'w') or die('Could not open file!');
fwrite($fp, $HTTP_RAW_POST_DATA) or die('Could not write to file');
fclose($fp);
?>

The key here is the use of the $HTTP_RAW_POST_DATA variable to capture the HTTP request body exactly as sent, without attempting to parse it into the usual name/value pairs. I'd suggest reading the documentation at this point, but it really doesn't tell you much.

Security tip: whatever the user sends in the request body, you're writing to a file on your server. If the user decides to send a shell script, PHP file, or other executable content, then visits the URL of the file you create, they can execute the code the just uploaded on your web server. So, make sure the file you write to can't be accessed via HTTP! (A .htaccess file would do the trick, or write to somewhere outside the web root.)