#include <stdio.h>
#include <stdlib.h>
#include <syslog.h>
#include <string.h>
#include <OpenDirectory/OpenDirectory.h>
typedef enum {
OD_CB_KEEPGOING,
OD_CB_REJECTED,
OD_CB_ERROR
} callback_ret_t;
static void pr_msg(const char *fmt, ...);
static int od_search(CFStringRef attr_to_match, char *value_to_match);
int
main(int argc, char **argv)
{
int ret;
char *pattern;
if (argc < 2 || argc > 3) {
fprintf(stderr, "Usage: dumammap <map name> [ <key> ]\n");
return 1;
}
if (argc == 2) {
ret = od_search(kODAttributeTypeMetaAutomountMap, argv[1]);
} else {
if (asprintf(&pattern, "%s,automountMapName=%s", argv[2],
argv[1]) == -1) {
pr_msg("malloc failed");
return 2;
}
ret = od_search(kODAttributeTypeRecordName, pattern);
free(pattern);
}
return ret ? 0 : 2;
}
static char *
od_CFStringtoCString(CFStringRef cfstr)
{
char *string;
CFIndex length;
length = CFStringGetMaximumSizeForEncoding(CFStringGetLength(cfstr),
kCFStringEncodingUTF8);
string = malloc(length + 1);
if (string == NULL)
return (NULL);
if (!CFStringGetCString(cfstr, string, length + 1,
kCFStringEncodingUTF8)) {
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 callback_ret_t
od_print_record(ODRecordRef record)
{
CFErrorRef error;
char *errstring;
CFArrayRef keys;
CFStringRef key;
CFArrayRef values;
CFStringRef value;
char *key_cstring, *value_cstring;
error = NULL;
keys = ODRecordCopyValues(record, kODAttributeTypeRecordName, &error);
if (keys == NULL) {
if (error != NULL) {
errstring = od_get_error_string(error);
pr_msg("od_print_record: can't get kODAttributeTypeRecordName attribute for record: %s",
errstring);
free(errstring);
return (OD_CB_ERROR);
} else {
pr_msg("od_print_record: record has no kODAttributeTypeRecordName attribute");
return (OD_CB_REJECTED);
}
}
if (CFArrayGetCount(keys) == 0) {
CFRelease(keys);
pr_msg("od_print_record: record has no kODAttributeTypeRecordName attribute");
return (OD_CB_REJECTED);
}
key = CFArrayGetValueAtIndex(keys, 0);
error = NULL;
values = ODRecordCopyValues(record,
kODAttributeTypeAutomountInformation, &error);
if (values == NULL) {
CFRelease(keys);
if (error != NULL) {
errstring = od_get_error_string(error);
pr_msg("od_print_record: can't get kODAttributeTypeAutomountInformation attribute for record: %s",
errstring);
free(errstring);
return (OD_CB_ERROR);
} else {
pr_msg("od_print_record: record has no kODAttributeTypeAutomountInformation attribute");
return (OD_CB_REJECTED);
}
}
if (CFArrayGetCount(values) == 0) {
CFRelease(values);
CFRelease(keys);
pr_msg("od_print_record: record has no kODAttributeTypeRecordName attribute");
return (OD_CB_REJECTED);
}
value = CFArrayGetValueAtIndex(values, 0);
key_cstring = od_CFStringtoCString(key);
value_cstring = od_CFStringtoCString(value);
printf("%s %s\n", key_cstring, value_cstring);
free(key_cstring);
free(value_cstring);
CFRelease(values);
CFRelease(keys);
return (OD_CB_KEEPGOING);
}
static int
od_search(CFStringRef attr_to_match, char *value_to_match)
{
int ret;
CFErrorRef error;
char *errstring;
ODNodeRef node_ref;
CFArrayRef attrs;
CFStringRef value_to_match_cfstr;
ODQueryRef query_ref;
CFArrayRef results;
CFIndex num_results;
CFIndex i;
ODRecordRef record;
callback_ret_t callback_ret;
error = NULL;
node_ref = ODNodeCreateWithNodeType(kCFAllocatorDefault, kODSessionDefault,
kODNodeTypeAuthentication, &error);
if (node_ref == NULL) {
errstring = od_get_error_string(error);
pr_msg("od_search: can't create search node for /Search: %s",
errstring);
free(errstring);
return (0);
}
value_to_match_cfstr = CFStringCreateWithCString(kCFAllocatorDefault,
value_to_match, kCFStringEncodingUTF8);
if (value_to_match_cfstr == NULL) {
CFRelease(node_ref);
pr_msg("od_search: can't make CFString from %s",
value_to_match);
return (0);
}
attrs = CFArrayCreate(kCFAllocatorDefault,
(const void *[2]){kODAttributeTypeRecordName,
kODAttributeTypeAutomountInformation}, 2,
&kCFTypeArrayCallBacks);
if (attrs == NULL) {
CFRelease(value_to_match_cfstr);
CFRelease(node_ref);
pr_msg("od_search: can't make array of attribute types");
return (0);
}
error = NULL;
query_ref = ODQueryCreateWithNode(kCFAllocatorDefault, node_ref,
kODRecordTypeAutomount, attr_to_match, kODMatchEqualTo,
value_to_match_cfstr, attrs, 0, &error);
CFRelease(attrs);
CFRelease(value_to_match_cfstr);
if (query_ref == NULL) {
CFRelease(node_ref);
errstring = od_get_error_string(error);
pr_msg("od_search: can't create query: %s",
errstring);
free(errstring);
return (0);
}
error = NULL;
results = ODQueryCopyResults(query_ref, false, &error);
if (results == NULL) {
CFRelease(query_ref);
CFRelease(node_ref);
errstring = od_get_error_string(error);
pr_msg("od_search: query failed: %s", errstring);
free(errstring);
return (0);
}
ret = 0;
num_results = CFArrayGetCount(results);
for (i = 0; i < num_results; i++) {
record = (ODRecordRef)CFArrayGetValueAtIndex(results, i);
callback_ret = od_print_record(record);
if (callback_ret == OD_CB_KEEPGOING) {
ret = 1;
} else if (callback_ret == OD_CB_ERROR) {
break;
}
}
CFRelease(results);
CFRelease(query_ref);
CFRelease(node_ref);
return (ret);
}
static void
pr_msg(const char *fmt, ...)
{
va_list ap;
(void) fprintf(stderr, "dumpammap: ");
va_start(ap, fmt);
(void) vfprintf(stderr, fmt, ap);
putc('\n', stderr);
va_end(ap);
}