/* ccapi/lib/ccapi_v2.c */ /* * Copyright 2006 Massachusetts Institute of Technology. * All Rights Reserved. * * Export of this software from the United States of America may * require a specific license from the United States Government. * It is the responsibility of any person or organization contemplating * export to obtain such a license before exporting. * * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and * distribute this software and its documentation for any purpose and * without fee is hereby granted, provided that the above copyright * notice appear in all copies and that both that copyright notice and * this permission notice appear in supporting documentation, and that * the name of M.I.T. not be used in advertising or publicity pertaining * to distribution of the software without specific, written prior * permission. Furthermore if you modify this software you must label * your software as modified software and not distribute it in such a * fashion that it might be confused with the original M.I.T. software. * M.I.T. makes no representations about the suitability of * this software for any purpose. It is provided "as is" without express * or implied warranty. */ #include "cci_common.h" #include "ccapi_string.h" #include "ccapi_context.h" #include "ccapi_ccache.h" #include "ccapi_ccache_iterator.h" #include "ccapi_credentials.h" #include "ccapi_credentials_iterator.h" #include infoNC infoNC_initializer = { NULL, NULL, CC_CRED_UNKNOWN }; /* ------------------------------------------------------------------------ */ static cc_int32 cci_remap_version (cc_int32 in_v2_version, cc_uint32 *out_v3_version) { cc_result err = ccNoError; if (!out_v3_version) { err = cci_check_error (ccErrBadParam); } if (!err) { if (in_v2_version == CC_CRED_V5) { *out_v3_version = cc_credentials_v5; } else { err = ccErrBadCredentialsVersion; } } return cci_check_error (err); } /* ------------------------------------------------------------------------ */ static cc_result _cci_remap_error (cc_result in_error, const char *in_function, const char *in_file, int in_line) { _cci_check_error (in_error, in_function, in_file, in_line); if (in_error >= CC_NOERROR && in_error <= CC_ERR_CRED_VERSION) { return in_error; } switch (in_error) { case ccNoError: return CC_NOERROR; case ccIteratorEnd: return CC_END; case ccErrBadParam: case ccErrContextNotFound: case ccErrInvalidContext: case ccErrInvalidCredentials: case ccErrInvalidCCacheIterator: case ccErrInvalidCredentialsIterator: case ccErrInvalidLock: case ccErrBadLockType: return CC_BAD_PARM; case ccErrNoMem: return CC_NOMEM; case ccErrInvalidCCache: case ccErrCCacheNotFound: return CC_NO_EXIST; case ccErrCredentialsNotFound: return CC_NOTFOUND; case ccErrBadName: return CC_BADNAME; case ccErrBadCredentialsVersion: return CC_ERR_CRED_VERSION; case ccErrBadAPIVersion: return CC_BAD_API_VERSION; case ccErrContextLocked: case ccErrContextUnlocked: case ccErrCCacheLocked: case ccErrCCacheUnlocked: return CC_LOCKED; case ccErrServerUnavailable: case ccErrServerInsecure: case ccErrServerCantBecomeUID: case ccErrBadInternalMessage: case ccErrClientNotFound: return CC_IO; case ccErrNotImplemented: return CC_NOT_SUPP; default: cci_debug_printf ("%s(): Unhandled error", __FUNCTION__); return CC_BAD_PARM; } } #define cci_remap_error(err) _cci_remap_error(err, __FUNCTION__, __FILE__, __LINE__) #if TARGET_OS_MAC #pragma mark - #endif /* ------------------------------------------------------------------------ */ cc_result cc_shutdown (apiCB **io_context) { cc_result err = ccNoError; if (!io_context) { err = cci_check_error (ccErrBadParam); } if (!err) { err = ccapi_context_release (*io_context); } if (!err) { *io_context = NULL; } return cci_remap_error (err); } /* ------------------------------------------------------------------------ */ cc_result cc_get_change_time (apiCB *in_context, cc_time_t *out_change_time) { cc_result err = ccNoError; if (!in_context ) { err = cci_check_error (ccErrBadParam); } if (!out_change_time) { err = cci_check_error (ccErrBadParam); } if (!err) { err = ccapi_context_get_change_time (in_context, out_change_time); } return cci_remap_error (err); } /* ------------------------------------------------------------------------ */ cc_result cc_get_NC_info (apiCB *in_context, infoNC ***out_info) { cc_result err = CC_NOERROR; infoNC **info = NULL; cc_uint64 count = 0; /* Preflight the size */ cc_uint64 i; if (!in_context) { err = cci_check_error (ccErrBadParam); } if (!out_info ) { err = cci_check_error (ccErrBadParam); } if (!err) { ccache_cit *iterator = NULL; err = cc_seq_fetch_NCs_begin (in_context, &iterator); while (!err) { ccache_p *ccache = NULL; err = cc_seq_fetch_NCs_next (in_context, &ccache, iterator); if (!err) { count++; } if (ccache) { cc_close (in_context, &ccache); } } if (err == CC_END) { err = CC_NOERROR; } if (!err) { err = cc_seq_fetch_NCs_end (in_context, &iterator); } } if (!err) { info = malloc (sizeof (*info) * (count + 1)); if (info) { for (i = 0; i < count + 1; i++) { info[i] = NULL; } } else { err = cci_check_error (CC_NOMEM); } } if (!err) { ccache_cit *iterator = NULL; err = cc_seq_fetch_NCs_begin (in_context, &iterator); for (i = 0; !err && i < count; i++) { ccache_p *ccache = NULL; err = cc_seq_fetch_NCs_next (in_context, &ccache, iterator); if (!err) { info[i] = malloc (sizeof (*info[i])); if (info[i]) { *info[i] = infoNC_initializer; } else { err = cci_check_error (CC_NOMEM); } } if (!err) { err = cc_get_name (in_context, ccache, &info[i]->name); } if (!err) { err = cc_get_principal (in_context, ccache, &info[i]->principal); } if (!err) { err = cc_get_cred_version (in_context, ccache, &info[i]->vers); } if (ccache) { cc_close (in_context, &ccache); } } if (!err) { err = cc_seq_fetch_NCs_end (in_context, &iterator); } } if (!err) { *out_info = info; info = NULL; } if (info) { cc_free_NC_info (in_context, &info); } return cci_check_error (err); } #if TARGET_OS_MAC #pragma mark - #endif /* ------------------------------------------------------------------------ */ cc_int32 cc_open (apiCB *in_context, const char *in_name, cc_int32 in_version, cc_uint32 in_flags, ccache_p **out_ccache) { cc_result err = ccNoError; cc_ccache_t ccache = NULL; cc_uint32 compat_version; cc_uint32 real_version; if (!in_context) { err = cci_check_error (ccErrBadParam); } if (!in_name ) { err = cci_check_error (ccErrBadParam); } if (!out_ccache) { err = cci_check_error (ccErrBadParam); } if (!err) { err = cci_remap_version (in_version, &compat_version); } if (!err) { err = ccapi_context_open_ccache (in_context, in_name, &ccache); } /* We must not allow a CCAPI v2 caller to open a v5-only ccache as a v4 ccache and vice versa. Allowing that would break (valid) assumptions made by CCAPI v2 callers. */ if (!err) { err = ccapi_ccache_get_credentials_version (ccache, &real_version); } if (!err) { /* check the version and set up the ccache to use it */ if (compat_version & real_version) { err = cci_ccache_set_compat_version (ccache, compat_version); } else { err = ccErrBadCredentialsVersion; } } if (!err) { *out_ccache = ccache; ccache = NULL; } if (ccache) { ccapi_ccache_release (ccache); } return cci_remap_error (err); } /* ------------------------------------------------------------------------ */ cc_result cc_create (apiCB *in_context, const char *in_name, const char *in_principal, cc_int32 in_version, cc_uint32 in_flags, ccache_p **out_ccache) { cc_result err = ccNoError; cc_ccache_t ccache = NULL; cc_uint32 compat_version; if (!in_context) { err = cci_check_error (ccErrBadParam); } if (!in_name ) { err = cci_check_error (ccErrBadParam); } if (!out_ccache) { err = cci_check_error (ccErrBadParam); } if (!err) { err = cci_remap_version (in_version, &compat_version); } if (!err) { err = ccapi_context_create_ccache (in_context, in_name, compat_version, in_principal, &ccache); } if (!err) { err = cci_ccache_set_compat_version (ccache, compat_version); } if (!err) { *out_ccache = ccache; ccache = NULL; } if (ccache) { ccapi_ccache_release (ccache); } return cci_remap_error (err); } /* ------------------------------------------------------------------------ */ cc_result cc_close (apiCB *in_context, ccache_p **io_ccache) { cc_result err = ccNoError; if (!in_context) { err = cci_check_error (ccErrBadParam); } if (!io_ccache ) { err = cci_check_error (ccErrBadParam); } if (!err) { err = ccapi_ccache_release (*io_ccache); } if (!err) { *io_ccache = NULL; } return cci_remap_error (err); } /* ------------------------------------------------------------------------ */ cc_result cc_destroy (apiCB *in_context, ccache_p **io_ccache) { cc_result err = ccNoError; if (!in_context) { err = cci_check_error (ccErrBadParam); } if (!io_ccache ) { err = cci_check_error (ccErrBadParam); } if (!err) { err = ccapi_ccache_destroy (*io_ccache); } if (!err) { *io_ccache = NULL; } return cci_remap_error (err); } /* ------------------------------------------------------------------------ */ cc_result cc_get_name (apiCB *in_context, ccache_p *in_ccache, char **out_name) { cc_result err = ccNoError; cc_string_t name = NULL; if (!in_context) { err = cci_check_error (ccErrBadParam); } if (!in_ccache ) { err = cci_check_error (ccErrBadParam); } if (!out_name ) { err = cci_check_error (ccErrBadParam); } if (!err) { err = ccapi_ccache_get_name (in_ccache, &name); } if (!err) { char *string = strdup (name->data); if (string) { *out_name = string; } else { err = cci_check_error (ccErrNoMem); } } if (name) { ccapi_string_release (name); } return cci_remap_error (err); } /* ------------------------------------------------------------------------ */ cc_result cc_get_cred_version (apiCB *in_context, ccache_p *in_ccache, cc_int32 *out_version) { cc_result err = ccNoError; cc_uint32 compat_version; if (!in_context ) { err = cci_check_error (ccErrBadParam); } if (!in_ccache ) { err = cci_check_error (ccErrBadParam); } if (!out_version) { err = cci_check_error (ccErrBadParam); } if (!err) { err = cci_ccache_get_compat_version (in_ccache, &compat_version); } if (!err) { if (compat_version == cc_credentials_v5) { *out_version = CC_CRED_V5; } else { err = ccErrBadCredentialsVersion; } } return cci_remap_error (err); } /* ------------------------------------------------------------------------ */ cc_result cc_set_principal (apiCB *in_context, ccache_p *io_ccache, cc_int32 in_version, char *in_principal) { cc_result err = ccNoError; cc_uint32 version; cc_uint32 compat_version; if (!in_context ) { err = cci_check_error (ccErrBadParam); } if (!io_ccache ) { err = cci_check_error (ccErrBadParam); } if (!in_principal) { err = cci_check_error (ccErrBadParam); } if (!err) { err = cci_remap_version (in_version, &version); } if (!err) { err = cci_ccache_get_compat_version (io_ccache, &compat_version); } if (!err && version != compat_version) { err = cci_check_error (ccErrBadCredentialsVersion); } if (!err) { err = ccapi_ccache_set_principal (io_ccache, version, in_principal); } return cci_remap_error (err); } /* ------------------------------------------------------------------------ */ cc_result cc_get_principal (apiCB *in_context, ccache_p *in_ccache, char **out_principal) { cc_result err = ccNoError; cc_uint32 compat_version; cc_string_t principal = NULL; if (!in_context ) { err = cci_check_error (ccErrBadParam); } if (!in_ccache ) { err = cci_check_error (ccErrBadParam); } if (!out_principal) { err = cci_check_error (ccErrBadParam); } if (!err) { err = cci_ccache_get_compat_version (in_ccache, &compat_version); } if (!err) { err = ccapi_ccache_get_principal (in_ccache, compat_version, &principal); } if (!err) { char *string = strdup (principal->data); if (string) { *out_principal = string; } else { err = cci_check_error (ccErrNoMem); } } if (principal) { ccapi_string_release (principal); } return cci_remap_error (err); } /* ------------------------------------------------------------------------ */ cc_result cc_store (apiCB *in_context, ccache_p *io_ccache, cred_union in_credentials) { cc_result err = ccNoError; cc_credentials_union *creds_union = NULL; if (!in_context) { err = cci_check_error (ccErrBadParam); } if (!io_ccache ) { err = cci_check_error (ccErrBadParam); } if (!err) { err = cci_cred_union_to_credentials_union (&in_credentials, &creds_union); } if (!err) { err = ccapi_ccache_store_credentials (io_ccache, creds_union); } if (creds_union) { cci_credentials_union_release (creds_union); } return cci_remap_error (err); } /* ------------------------------------------------------------------------ */ cc_result cc_remove_cred (apiCB *in_context, ccache_p *in_ccache, cred_union in_credentials) { cc_result err = ccNoError; cc_credentials_iterator_t iterator = NULL; cc_uint32 found = 0; if (!in_context) { err = cci_check_error (ccErrBadParam); } if (!in_ccache ) { err = cci_check_error (ccErrBadParam); } if (!err) { err = ccapi_ccache_new_credentials_iterator (in_ccache, &iterator); } while (!err && !found) { cc_credentials_t creds = NULL; err = ccapi_credentials_iterator_next (iterator, &creds); if (!err) { err = cci_cred_union_compare_to_credentials_union (&in_credentials, creds->data, &found); } if (!err && found) { err = ccapi_ccache_remove_credentials (in_ccache, creds); } ccapi_credentials_release (creds); } if (err == ccIteratorEnd) { err = cci_check_error (ccErrCredentialsNotFound); } return cci_remap_error (err); } #if TARGET_OS_MAC #pragma mark - #endif /* ------------------------------------------------------------------------ */ cc_result cc_seq_fetch_NCs_begin (apiCB *in_context, ccache_cit **out_iterator) { cc_result err = ccNoError; cc_ccache_iterator_t iterator = NULL; if (!in_context ) { err = cci_check_error (ccErrBadParam); } if (!out_iterator) { err = cci_check_error (ccErrBadParam); } if (!err) { err = ccapi_context_new_ccache_iterator (in_context, &iterator); } if (!err) { *out_iterator = (ccache_cit *) iterator; iterator = NULL; /* take ownership */ } if (iterator) { ccapi_ccache_iterator_release (iterator); } return cci_remap_error (err); } /* ------------------------------------------------------------------------ */ cc_result cc_seq_fetch_NCs_next (apiCB *in_context, ccache_p **out_ccache, ccache_cit *in_iterator) { cc_result err = ccNoError; cc_ccache_iterator_t iterator = (cc_ccache_iterator_t) in_iterator; cc_ccache_t ccache = NULL; const char *saved_ccache_name; if (!in_context ) { err = cci_check_error (ccErrBadParam); } if (!out_ccache ) { err = cci_check_error (ccErrBadParam); } if (!in_iterator) { err = cci_check_error (ccErrBadParam); } if (!err) { err = cci_ccache_iterator_get_saved_ccache_name (iterator, &saved_ccache_name); } if (!err) { if (saved_ccache_name) { err = ccapi_context_open_ccache (in_context, saved_ccache_name, &ccache); if (!err) { err = cci_ccache_set_compat_version (ccache, cc_credentials_v5); } if (!err) { err = cci_ccache_iterator_set_saved_ccache_name (iterator, NULL); } } else { cc_uint32 version = 0; err = ccapi_ccache_iterator_next (iterator, &ccache); if (!err) { err = ccapi_ccache_get_credentials_version (ccache, &version); } if (!err) { err = cci_ccache_set_compat_version (ccache, version); } } } if (!err) { *out_ccache = ccache; ccache = NULL; /* take ownership */ } if (ccache) { ccapi_ccache_release (ccache); } return cci_remap_error (err); } /* ------------------------------------------------------------------------ */ cc_result cc_seq_fetch_NCs_end (apiCB *in_context, ccache_cit **io_iterator) { cc_result err = ccNoError; cc_ccache_iterator_t iterator = (cc_ccache_iterator_t) *io_iterator; if (!in_context ) { err = cci_check_error (ccErrBadParam); } if (!io_iterator) { err = cci_check_error (ccErrBadParam); } if (!err) { err = ccapi_ccache_iterator_release (iterator); } if (!err) { *io_iterator = NULL; } return cci_remap_error (err); } #if TARGET_OS_MAC #pragma mark - #endif /* ------------------------------------------------------------------------ */ cc_result cc_seq_fetch_creds_begin (apiCB *in_context, const ccache_p *in_ccache, ccache_cit **out_iterator) { cc_result err = ccNoError; cc_credentials_iterator_t iterator = NULL; cc_uint32 compat_version; if (!in_context ) { err = cci_check_error (ccErrBadParam); } if (!in_ccache ) { err = cci_check_error (ccErrBadParam); } if (!out_iterator) { err = cci_check_error (ccErrBadParam); } if (!err) { err = cci_ccache_get_compat_version ((cc_ccache_t) in_ccache, &compat_version); } if (!err) { err = ccapi_ccache_new_credentials_iterator ((cc_ccache_t) in_ccache, &iterator); } if (!err) { err = cci_credentials_iterator_set_compat_version (iterator, compat_version); } if (!err) { *out_iterator = (ccache_cit *) iterator; iterator = NULL; /* take ownership */ } if (iterator) { ccapi_credentials_iterator_release (iterator); } return cci_remap_error (err); } /* ------------------------------------------------------------------------ */ cc_result cc_seq_fetch_creds_next (apiCB *in_context, cred_union **out_creds, ccache_cit *in_iterator) { cc_result err = ccNoError; cc_credentials_iterator_t iterator = (cc_credentials_iterator_t) in_iterator; cc_uint32 compat_version; if (!in_context ) { err = cci_check_error (ccErrBadParam); } if (!out_creds ) { err = cci_check_error (ccErrBadParam); } if (!in_iterator) { err = cci_check_error (ccErrBadParam); } if (!err) { err = cci_credentials_iterator_get_compat_version (iterator, &compat_version); } while (!err) { cc_credentials_t credentials = NULL; err = ccapi_credentials_iterator_next (iterator, &credentials); if (!err && (credentials->data->version & compat_version)) { /* got the next credentials for the correct version */ err = cci_credentials_union_to_cred_union (credentials->data, out_creds); break; } if (credentials) { ccapi_credentials_release (credentials); } } return cci_remap_error (err); } /* ------------------------------------------------------------------------ */ cc_result cc_seq_fetch_creds_end (apiCB *in_context, ccache_cit **io_iterator) { cc_result err = ccNoError; cc_credentials_iterator_t iterator = (cc_credentials_iterator_t) *io_iterator; if (!in_context ) { err = cci_check_error (ccErrBadParam); } if (!io_iterator) { err = cci_check_error (ccErrBadParam); } if (!err) { err = ccapi_credentials_iterator_release (iterator); } if (!err) { *io_iterator = NULL; } return cci_remap_error (err); } #if TARGET_OS_MAC #pragma mark - #endif /* ------------------------------------------------------------------------ */ cc_result cc_free_principal (apiCB *in_context, char **io_principal) { cc_result err = ccNoError; if (!in_context ) { err = cci_check_error (ccErrBadParam); } if (!io_principal) { err = cci_check_error (ccErrBadParam); } if (!err) { free (*io_principal); *io_principal = NULL; } return cci_remap_error (err); } /* ------------------------------------------------------------------------ */ cc_result cc_free_name (apiCB *in_context, char **io_name) { cc_result err = ccNoError; if (!in_context) { err = cci_check_error (ccErrBadParam); } if (!io_name ) { err = cci_check_error (ccErrBadParam); } if (!err) { free (*io_name); *io_name = NULL; } return cci_remap_error (err); } /* ------------------------------------------------------------------------ */ cc_result cc_free_creds (apiCB *in_context, cred_union **io_credentials) { cc_result err = ccNoError; if (!in_context ) { err = cci_check_error (ccErrBadParam); } if (!io_credentials) { err = cci_check_error (ccErrBadParam); } if (!err) { err = cci_cred_union_release (*io_credentials); if (!err) { *io_credentials = NULL; } } return cci_remap_error (err); } /* ------------------------------------------------------------------------ */ cc_result cc_free_NC_info (apiCB *in_context, infoNC ***io_info) { cc_result err = ccNoError; if (!in_context) { err = cci_check_error (ccErrBadParam); } if (!io_info ) { err = cci_check_error (ccErrBadParam); } if (!err && *io_info) { infoNC **data = *io_info; int i; for (i = 0; data[i] != NULL; i++) { cc_free_principal (in_context, &data[i]->principal); cc_free_name (in_context, &data[i]->name); free (data[i]); } free (data); *io_info = NULL; } return cci_remap_error (err); }