#include <stdio.h>
#include <syslog.h>
#include <OpenDirectory/OpenDirectory.h>
static inline CFIndex
od_cfstrlen(CFStringRef cfstr)
{
return (CFStringGetMaximumSizeForEncoding(CFStringGetLength(cfstr),
kCFStringEncodingUTF8));
}
static inline Boolean
od_cfstrlcpy(char *string, CFStringRef cfstr, size_t size)
{
return (CFStringGetCString(cfstr, string, (CFIndex)size,
kCFStringEncodingUTF8));
}
static char *
od_CFStringtoCString(CFStringRef cfstr)
{
char *string;
CFIndex length;
length = od_cfstrlen(cfstr);
string = malloc(length + 1);
if (string == NULL)
return (NULL);
if (!od_cfstrlcpy(string, cfstr, length + 1)) {
free(string);
return (NULL);
}
return (string);
}
static char *
od_get_error_string(CFErrorRef err)
{
CFStringRef errstringref;
char *errstring;
if (err != NULL) {
errstringref = CFErrorCopyDescription(err);
errstring = od_CFStringtoCString(errstringref);
CFRelease(errstringref);
} else
errstring = strdup("Unknown error");
return (errstring);
}
static CFMutableStringRef
get_home_dir_url(CFStringRef homedir)
{
CFRange homedir_range, item_start, item_stop, item_actual;
CFStringRef substring;
CFMutableStringRef url;
homedir_range = CFRangeMake(0, CFStringGetLength(homedir));
if (CFStringFindWithOptions(homedir, CFSTR("<path>"), homedir_range,
kCFCompareCaseInsensitive, &item_start) &&
CFStringFindWithOptions(homedir, CFSTR("</path>"), homedir_range,
kCFCompareCaseInsensitive, &item_stop)) {
item_actual = CFRangeMake(item_start.location + item_start.length,
item_stop.location - (item_start.location + item_start.length));
substring = CFStringCreateWithSubstring(kCFAllocatorDefault,
homedir, item_actual);
if (substring == NULL) {
fprintf(stderr, "od_user_homes: CFStringCreateWithSubstring() failed for path\n");
return (NULL);
}
if (CFStringCompare(substring, CFSTR(""), 0) != kCFCompareEqualTo &&
CFStringCompare(substring, CFSTR("/"), 0) != kCFCompareEqualTo) {
CFRelease(substring);
return (NULL);
}
CFRelease(substring);
}
if (CFStringFindWithOptions(homedir, CFSTR("<url>"), homedir_range,
kCFCompareCaseInsensitive, &item_start) &&
CFStringFindWithOptions(homedir, CFSTR("</url>"), homedir_range,
kCFCompareCaseInsensitive, &item_stop)) {
item_actual = CFRangeMake(item_start.location + item_start.length,
item_stop.location - (item_start.location + item_start.length));
substring = CFStringCreateWithSubstring(kCFAllocatorDefault,
homedir, item_actual);
if (substring == NULL) {
fprintf(stderr, "od_user_homes: CFStringCreateWithSubstring() failed for URL\n");
return (NULL);
}
url = CFStringCreateMutableCopy(kCFAllocatorDefault, 0,
substring);
CFRelease(substring);
return (url);
} else {
return (NULL);
}
}
int
main(int argc, char **argv)
{
CFStringRef username;
CFErrorRef error;
char *errstring;
ODNodeRef noderef;
CFTypeRef attrs[] = { kODAttributeTypeMetaNodeLocation,
kODAttributeTypeHomeDirectory,
kODAttributeTypeNFSHomeDirectory };
CFArrayRef attributes;
ODQueryRef query;
CFArrayRef results;
CFIndex count;
int status;
CFIndex i;
ODRecordRef record;
CFArrayRef values;
if (argc == 1) {
return 0;
}
if (argc != 2) {
fprintf(stderr, "Usage: od_user_homes <username>\n");
return 1;
}
username = CFStringCreateWithCStringNoCopy(kCFAllocatorDefault, argv[1],
kCFStringEncodingUTF8, kCFAllocatorNull);
if (username == NULL) {
fprintf(stderr, "od_user_home: Can't create CFString for user name\n");
return 2;
}
error = NULL;
noderef = ODNodeCreateWithNodeType(kCFAllocatorDefault,
kODSessionDefault, kODNodeTypeAuthentication, &error);
if (noderef == NULL) {
errstring = od_get_error_string(error);
fprintf(stderr, "od_user_home: Can't create OD node: %s\n",
errstring);
free(errstring);
return 2;
}
attributes = CFArrayCreate(kCFAllocatorDefault,
attrs, sizeof(attrs)/sizeof(*attrs), &kCFTypeArrayCallBacks);
query = ODQueryCreateWithNodeType(kCFAllocatorDefault,
kODNodeTypeAuthentication, kODRecordTypeUsers,
kODAttributeTypeRecordName, kODMatchEqualTo, username, attributes,
INT_MAX, &error);
if (query == NULL) {
errstring = od_get_error_string(error);
fprintf(stderr, "od_user_home: Can't create OD query: %s\n",
errstring);
free(errstring);
return 2;
}
results = ODQueryCopyResults(query, FALSE, &error);
if (results == NULL) {
if (error != NULL) {
errstring = od_get_error_string(error);
fprintf(stderr, "od_user_home: Can't copy OD query results: %s\n",
errstring);
free(errstring);
return 2;
}
return 2;
}
count = CFArrayGetCount(results);
status = 2;
for (i = 0; i < count && status != 0; i++) {
record = (ODRecordRef) CFArrayGetValueAtIndex(results, i);
values = ODRecordCopyValues(record,
kODAttributeTypeMetaNodeLocation, &error);
if (values == NULL) {
if (error != NULL) {
errstring = od_get_error_string(error);
fprintf(stderr, "od_user_homes: Can't get kODAttributeTypeMetaNodeLocation from record: %s\n",
errstring);
free(errstring);
return 2;
}
continue;
} else {
if (CFArrayGetCount(values) != 0) {
CFStringRef location = CFArrayGetValueAtIndex(values, 0);
if (CFStringHasPrefix(location, CFSTR("/Local")) == TRUE) {
CFRelease(values);
continue;
}
}
CFRelease(values);
}
values = ODRecordCopyValues(record,
kODAttributeTypeHomeDirectory, &error);
if (values == NULL) {
if (error != NULL) {
errstring = od_get_error_string(error);
fprintf(stderr, "od_user_homes: Can't get kODAttributeTypeMetaNodeLocation from record: %s\n",
errstring);
free(errstring);
return 2;
}
continue;
} else {
if (CFArrayGetCount(values) != 0) {
CFStringRef homedir = CFArrayGetValueAtIndex(values, 0);
if (CFGetTypeID(homedir) == CFStringGetTypeID()) {
CFMutableStringRef url;
char *urlstr;
url = get_home_dir_url(homedir);
if (url != NULL) {
CFStringFindAndReplace(url,
CFSTR("afp://"),
CFSTR("afp://;AUTH=NO%20USER%20AUTHENT@"),
CFRangeMake(0, CFStringGetLength(url)),
0);
urlstr = od_CFStringtoCString(url);
if (urlstr == NULL) {
fprintf(stderr, "od_user_homes: Can't convert path string to C string\n");
return 2;
}
printf("%s\n", urlstr);
free(urlstr);
CFRelease(url);
status = 0;
}
}
}
CFRelease(values);
}
}
CFRelease(results);
CFRelease(query);
CFRelease(attributes);
CFRelease(noderef);
CFRelease(username);
return status;
}