/* Compile: * gcc -W -Wall -O3 search.c -lldap -o search * Run without parameters to see usage. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include struct private { gnutls_session_t session; void *tlsg_ctx; struct berval peer_der_dn; }; char **values(LDAP *conn, LDAPMessage *entry, char *attr) { char **list; int count, used; struct berval **vals; vals = ldap_get_values_len(conn, entry, attr); if (!vals) return NULL; count = ldap_count_values_len(vals); if (count < 1) { ldap_value_free_len(vals); errno = 0; return NULL; } list = malloc((count + 1) * sizeof (char *)); if (!list) { ldap_value_free_len(vals); errno = ENOMEM; return NULL; } for (used = 0; used < count; used++) if (NULL == (list[used] = strndup(vals[used]->bv_val, vals[used]->bv_len))) break; if (used != count) { ldap_value_free_len(vals); while (used > 0) free(list[--used]); free(list); errno = ENOMEM; return NULL; } list[count] = NULL; return list; } void values_free(char **list) { int i; if (!list) return; for (i = 0; list[i]; i++) free(list[i]); free(list); } char **attributes(LDAP *conn, LDAPMessage *entry) { char **list = NULL, **temp; size_t size = 0; size_t used = 0; BerElement *ber; char *one; ber = NULL; one = ldap_first_attribute(conn, entry, &ber); while (one != NULL) { if (used >= size) { size = (used | 7) + 8; temp = realloc(list, (size + 1) * sizeof (char *)); if (!temp) { ber_free(ber, 0); while (used > 0) ldap_memfree(list[--used]); free(list); errno = ENOMEM; return NULL; } list = temp; } list[used++] = one; one = ldap_next_attribute(conn, entry, ber); } ber_free(ber, 0); if (used < 1) { errno = 0; return NULL; } list[used] = NULL; return list; } void attributes_free(char **list) { int i; if (!list) return; for (i = 0; list[i]; i++) ldap_memfree(list[i]); free(list); } int main(int argc, char *argv[]) { int result, value, i, k; LDAP *connection; LDAPMessage *message, *curr, *entry; char *dn, **attr_list, **value_list; struct timeval timeout; struct private *pvt; if (argc < 5 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) { fprintf(stderr, "search version 0.6\n"); fprintf(stderr, "\n"); fprintf(stderr, "Usage: %s [ -h | --help ]\n", argv[0]); fprintf(stderr, " %s CIPHER_SUITE ldap://server BASEDN FILTER [ ATTRIBUTES ]\n", argv[0]); fprintf(stderr, "\n"); fprintf(stderr, "This program will attempt to connect to the specified\n"); fprintf(stderr, "server (using START_TLS), and do a simple search.\n"); return 0; } /* Set cipher suite: */ result = ldap_set_option(NULL, LDAP_OPT_X_TLS_CIPHER_SUITE, argv[1]); if (result != LDAP_OPT_SUCCESS) { fprintf(stderr, "%s: %s.\n", argv[1], ldap_err2string(result)); return 1; } /* Set protocol version: */ value = 3; result = ldap_set_option(NULL, LDAP_OPT_PROTOCOL_VERSION, &value); if (result != LDAP_OPT_SUCCESS) { fprintf(stderr, "Cannot set protocol version 3: %s.\n", ldap_err2string(result)); return 1; } /* Initialize connection. */ result = ldap_initialize(&connection, argv[2]); if (result != LDAP_OPT_SUCCESS) { fprintf(stderr, "%s: %s.\n", argv[2], ldap_err2string(result)); return 1; } /* Secure connection. */ #ifdef CHECK_TLS if (!ldap_tls_inplace(connection)) { #endif result = ldap_start_tls_s(connection, NULL, NULL); if (result != LDAP_OPT_SUCCESS) { fprintf(stderr, "StartTLS: %s.\n", ldap_err2string(result)); return 1; } #ifdef CHECK_TLS } #endif /* Do a synchronous search. */ timeout.tv_sec = 10; /* 10-second timeout. */ timeout.tv_usec = 0; message = NULL; result = ldap_search_ext_s(connection, /* base */ argv[3], /* scope */ LDAP_SCOPE_SUB, /* filter */ argv[4], /* attrs */ (argc < 6) ? NULL : argv + 5, /* attribute names only */ 0, /* server controls */ NULL, /* client controls */ NULL, /* timeout */ &timeout, /* sizelimit */ 1000, &message); if (result != LDAP_OPT_SUCCESS) { fprintf(stderr, "Search failed: %s.\n", ldap_err2string(result)); ldap_msgfree(message); return 1; } printf("Success!\n"); /* Get the TLS/SSL security context. */ result = ldap_get_option(connection, LDAP_OPT_X_TLS_SSL_CTX, (void **)&pvt); if (result == LDAP_OPT_SUCCESS) { gnutls_session_t tls = pvt->session; gnutls_cipher_algorithm_t cipher = gnutls_cipher_get(tls); gnutls_mac_algorithm_t mac = gnutls_mac_get(tls); gnutls_certificate_type_t cert_type = gnutls_certificate_type_get(tls); size_t cipher_size = gnutls_cipher_get_key_size(cipher) * CHAR_BIT; /* Reported in bytes */ size_t mac_size = gnutls_mac_get_key_size(mac) * CHAR_BIT; /* Reported in bytes */ const char *cipher_name = gnutls_cipher_get_name(cipher); const char *kx_name = gnutls_kx_get_name(gnutls_kx_get(tls)); const char *mac_name = gnutls_mac_get_name(mac); const char *compression_name = gnutls_compression_get_name(gnutls_compression_get(tls)); const char *cert_type_name = gnutls_certificate_type_get_name(cert_type); const gnutls_datum_t *cert_list; unsigned int cert_list_size = 0; cert_list = gnutls_certificate_get_peers(tls, &cert_list_size); if (cipher_name && cipher_size > 0) printf("Cipher: %s, %d bits\n", cipher_name, (int)cipher_size); if (mac_name && mac_size > 0) printf("MAC: %s, %d bits\n", mac_name, (int)mac_size); if (kx_name) printf("Key exchange: %s\n", kx_name); if (compression_name) printf("Compression type: %s\n", compression_name); if (cert_type_name) printf("Certificate type: %s\n", cert_type_name); if (cert_list && cert_list_size > 0 && cert_type == GNUTLS_CRT_X509) { for (i = 0; (size_t)i < cert_list_size; i++) { gnutls_x509_crt_t cert; gnutls_x509_crt_init(&cert); if (!gnutls_x509_crt_import(cert, &cert_list[i], GNUTLS_X509_FMT_DER)) { gnutls_datum_t info; if (!gnutls_x509_crt_print(cert, GNUTLS_CRT_PRINT_ONELINE, &info)) { printf("\t%s\n", info.data); gnutls_free(info.data); } else printf("\t(Unprintable x509 certificate)\n"); } else printf("\t(Bad x509 certificate)\n"); gnutls_x509_crt_deinit(cert); } } printf("\n"); } curr = ldap_first_message(connection, message); while (curr != NULL) { if (ldap_msgtype(curr) == LDAP_RES_SEARCH_ENTRY) { /* See if we can get a DN. */ dn = ldap_get_dn(connection, curr); if (dn) { printf("DN: %s\n", dn); ldap_memfree(dn); } /* Check for entries. */ entry = ldap_first_entry(connection, curr); while (entry) { attr_list = attributes(connection, entry); if (attr_list) { for (i = 0; attr_list[i]; i++) { value_list = values(connection, entry, attr_list[i]); if (value_list) for (k = 0; value_list[k]; k++) printf("\t%s: %s\n", attr_list[i], value_list[k]); values_free(value_list); } } attributes_free(attr_list); entry = ldap_next_entry(connection, entry); } } else if (ldap_msgtype(curr) == LDAP_RES_SEARCH_RESULT) { printf("End of response.\n"); } curr = ldap_next_message(connection, curr); } /* Discard results. */ ldap_msgfree(message); return 0; }