/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2015 Gary Mills * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "ldap_map.h" #include "ldap_parse.h" #include "ldap_glob.h" #include "nis_parse_ldap_conf.h" __nis_ldap_proxy_info proxyInfo = {NULL, (auth_method_t)NO_VALUE_SET, (tls_method_t)NO_VALUE_SET, NULL, NULL, NULL, NULL, NULL, (follow_referral_t)NO_VALUE_SET}; __nis_config_t ldapConfig; __nisdb_table_mapping_t ldapDBTableMapping; __nis_table_mapping_t *ldapTableMapping = NULL; __yp_domain_context_t ypDomains; parse_error p_error = no_parse_error; int cur_line_num = 0; int start_line_num = 0; int seq_num = 0; const char *warn_file = NULL; char _key_val[38]; const char *command_line_source = NULL; const char *file_source = NULL; const char *ldap_source = NULL; static const char *const *cmdline_config = NULL; static bool_t got_config_data = FALSE; /* high level parsing functions functions */ static int parse_ldap_cmd_line(const char *const *cmdline_options, __nis_ldap_proxy_info *proxy_info, __nis_config_t *nis_config, __nis_table_mapping_t **table_mapping, __nis_config_info_t *config_info, __nisdb_table_mapping_t *table_info); static int parse_ldap_default_conf(__nis_ldap_proxy_info *proxy_info, __nis_config_t *nis_config, __nis_config_info_t *config_info, __nisdb_table_mapping_t *table_info); static int parse_ldap_config_file(const char *config_file, __nis_ldap_proxy_info *proxy_info, __nis_config_t *nis_config, __nis_table_mapping_t **table_mapping, __nis_config_info_t *config_info, __nisdb_table_mapping_t *table_info); static int parse_ldap_config_dn_attrs(__nis_ldap_proxy_info *proxy_info, __nis_config_t *nis_config, __nis_table_mapping_t **table_mapping, __nis_config_info_t *config_info, __nisdb_table_mapping_t *table_info); static int yp_parse_ldap_default_conf(__nis_ldap_proxy_info *proxy_info, __nis_config_t *nis_config, __nis_config_info_t *config_info, __nisdb_table_mapping_t *table_info); /* Forward declarations */ int yp_parse_ldap_config_file(const char *, __nis_ldap_proxy_info *, __nis_config_t *, __nis_table_mapping_t **, __nis_config_info_t *, __nisdb_table_mapping_t *, __yp_domain_context_t *); /* helper functions */ static config_key get_attrib_num_cmdline(const char *s, const char **begin_s, const char **end_s); static config_key get_file_attr_val(int fd, char **attr_val); static void get_attribute_list( const __nis_ldap_proxy_info *proxy_info, const __nis_config_t *nis_config, const __nis_config_info_t *config_info, const __nisdb_table_mapping_t *table_info, char **ldap_config_attributes); /* * FUNCTION: parse_ldap_migration * * Parses the information for LDAP. The values are first * obtained from the command line, secondly from the preference * file, and finally from an LDAP profile (if so configured in * the command line or preference file). Any unset values will * be set to their default values. * * If no command line options, no settings in the /etc/default * configuration file, and no mapping file, then no mapping * should be used. * * RETURN VALUE: * 0 Success * -1 Config file stat/open or parse error * 1 No mapping should be used. * * INPUT: command line parameters, configuration file */ int parse_ldap_migration( const char *const *cmdline_options, const char *config_file) { int rc = 0; __nis_config_info_t config_info = {NULL, NULL, (auth_method_t)NO_VALUE_SET, (tls_method_t)NO_VALUE_SET, NULL, NULL, NULL}; struct stat buf; p_error = no_parse_error; if (verbose) report_info("Getting LDAP configuration", NULL); initialize_parse_structs(&proxyInfo, &ldapConfig, &ldapDBTableMapping); if (yp2ldap) initialize_yp_parse_structs(&ypDomains); if (cmdline_options != NULL) { got_config_data = TRUE; /* NIS to LDAP does not read command line attributes */ if (!yp2ldap) rc = parse_ldap_cmd_line(cmdline_options, &proxyInfo, &ldapConfig, &ldapTableMapping, &config_info, &ldapDBTableMapping); else rc = 0; } if (rc == 0) { if (yp2ldap) rc = yp_parse_ldap_default_conf(&proxyInfo, &ldapConfig, &config_info, &ldapDBTableMapping); else rc = parse_ldap_default_conf(&proxyInfo, &ldapConfig, &config_info, &ldapDBTableMapping); } if (config_file == NULL) { if (yp2ldap) { if (stat(YP_DEFAULT_MAPPING_FILE, &buf) == 0) config_file = YP_DEFAULT_MAPPING_FILE; } else { if (stat(DEFAULT_MAPPING_FILE, &buf) == 0) config_file = DEFAULT_MAPPING_FILE; } } if (rc == 0 && config_file != NULL) { got_config_data = TRUE; warn_file = config_file; cmdline_config = cmdline_options; if (yp2ldap) rc = yp_parse_ldap_config_file(config_file, &proxyInfo, &ldapConfig, &ldapTableMapping, &config_info, &ldapDBTableMapping, &ypDomains); else rc = parse_ldap_config_file(config_file, &proxyInfo, &ldapConfig, &ldapTableMapping, &config_info, &ldapDBTableMapping); warn_file = NULL; cmdline_config = NULL; } if (rc == 0 && (config_info.config_dn != NULL) && (config_info.config_dn[0] != '\0')) { rc = parse_ldap_config_dn_attrs(&proxyInfo, &ldapConfig, &ldapTableMapping, &config_info, &ldapDBTableMapping); } free_config_info(&config_info); if (rc == 0 && got_config_data == FALSE) rc = 1; set_default_values(&proxyInfo, &ldapConfig, &ldapDBTableMapping); if (yp2ldap == 1 && rc == 0) { rc = second_parser_pass(&ldapTableMapping); if (rc == 0) rc = final_parser_pass(&ldapTableMapping, &ypDomains); if (rc == -2) return (-1); } if (rc == 0) rc = finish_parse(&proxyInfo, &ldapTableMapping); if (rc == 0) rc = linked2hash(ldapTableMapping); if ((rc == 0) && yptol_mode) rc = map_id_list_init(); if (rc != 0) { free_parse_structs(); } else if (verbose) report_info("LDAP configuration complete", NULL); return (rc); } /* * FUNCTION: parse_ldap_cmd_line * * Parses the information for LDAP from the command line * * RETURN VALUE: 0 on success, -1 on failure * * INPUT: command line values */ static int parse_ldap_cmd_line( const char *const *cmdline_options, __nis_ldap_proxy_info *proxy_info, __nis_config_t *nis_config, __nis_table_mapping_t **table_mapping, __nis_config_info_t *config_info, __nisdb_table_mapping_t *table_info) { int rc = 0; config_key attrib_num; const char *begin_s; const char *end_s; if (verbose) report_info("Command line values: ", NULL); while (*cmdline_options != NULL) { if (verbose) report_info("\t", *cmdline_options); attrib_num = get_attrib_num_cmdline( *cmdline_options, &begin_s, &end_s); if (attrib_num == key_bad) { command_line_source = "command line"; report_error(*cmdline_options, NULL); command_line_source = NULL; rc = -1; break; } else if (IS_CONFIG_KEYWORD(attrib_num)) { rc = add_config_attribute(attrib_num, begin_s, end_s - begin_s, config_info); } else if (IS_BIND_INFO(attrib_num)) { rc = add_bind_attribute(attrib_num, begin_s, end_s - begin_s, proxy_info); } else if (IS_OPER_INFO(attrib_num)) { rc = add_operation_attribute(attrib_num, begin_s, end_s - begin_s, nis_config, table_info); } else { rc = add_mapping_attribute(attrib_num, begin_s, end_s - begin_s, table_mapping); } if (rc < 0) { command_line_source = "command line"; report_error(begin_s, _key_val); command_line_source = NULL; break; } cmdline_options++; } return (rc); } static int parse_ldap_default_conf( __nis_ldap_proxy_info *proxy_info, __nis_config_t *nis_config, __nis_config_info_t *config_info, __nisdb_table_mapping_t *table_info) { int rc = 0; char *ldap_config_attributes[n_config_keys]; char attr_buf[128]; char *attr; char *attr_val; int defflags; config_key attrib_num; int i; int len; int attr_len; void *defp; if ((defp = defopen_r(ETCCONFFILE)) != NULL) { file_source = ETCCONFFILE; if (verbose) report_info("default configuration values: ", NULL); /* Set defread_r() to be case insensitive */ defflags = defcntl_r(DC_GETFLAGS, 0, defp); TURNOFF(defflags, DC_CASE); (void) defcntl_r(DC_SETFLAGS, defflags, defp); get_attribute_list(proxy_info, nis_config, config_info, table_info, ldap_config_attributes); i = 0; while ((attr = ldap_config_attributes[i++]) != NULL) { (void) strlcpy(attr_buf, attr, sizeof (attr_buf)); /* * if nisplusUpdateBatching, make sure * we don't match nisplusUpdateBatchingTimeout */ if (strcmp(attr, UPDATE_BATCHING) == 0) { attr_len = strlen(attr); attr_buf[attr_len] = '='; attr_buf[attr_len + 1] = '\0'; attr_val = defread_r(attr_buf, defp); if (attr_val == 0) { attr_buf[attr_len] = ' '; attr_val = defread_r(attr_buf, defp); } if (attr_val == 0) { attr_buf[attr_len] = '\t'; attr_val = defread_r(attr_buf, defp); } if (attr_val == 0) { attr_buf[attr_len] = '\n'; attr_val = defread_r(attr_buf, defp); } } else { attr_val = defread_r(attr_buf, defp); } if (attr_val == NULL) continue; got_config_data = TRUE; attrib_num = get_attrib_num(attr, strlen(attr)); if (attrib_num == key_bad) { report_error(attr, NULL); rc = -1; break; } /* * Allow either entries of the form * attr val * or * attr = val */ while (is_whitespace(*attr_val)) attr_val++; if (*attr_val == '=') attr_val++; while (is_whitespace(*attr_val)) attr_val++; len = strlen(attr_val); while (len > 0 && is_whitespace(attr_val[len - 1])) len--; if (verbose) { report_info("\t", attr); report_info("\t\t", attr_val); } if (IS_BIND_INFO(attrib_num)) { rc = add_bind_attribute(attrib_num, attr_val, len, proxy_info); } else if (IS_OPER_INFO(attrib_num)) { rc = add_operation_attribute(attrib_num, attr_val, len, nis_config, table_info); } if (p_error != no_parse_error) { report_error(attr_val, attr); rc = -1; break; } } file_source = NULL; /* Close the /etc/default file */ defclose_r(defp); } return (rc); } static int yp_parse_ldap_default_conf( __nis_ldap_proxy_info *proxy_info, __nis_config_t *nis_config, __nis_config_info_t *config_info, __nisdb_table_mapping_t *table_info) { int rc = 0; char *ldap_config_attributes[n_config_keys]; char attr_buf[128]; char *attr; char *attr_val; int defflags; config_key attrib_num; int i, len; void *defp; if ((defp = defopen_r(YP_ETCCONFFILE)) != NULL) { file_source = YP_ETCCONFFILE; if (verbose) report_info("default configuration values: ", NULL); /* Set defread_r() to be case insensitive */ defflags = defcntl_r(DC_GETFLAGS, 0, defp); TURNOFF(defflags, DC_CASE); (void) defcntl_r(DC_SETFLAGS, defflags, defp); get_attribute_list(proxy_info, nis_config, config_info, table_info, ldap_config_attributes); i = 0; while ((attr = ldap_config_attributes[i++]) != NULL) { if ((strlcpy(attr_buf, attr, sizeof (attr_buf))) >= sizeof (attr_buf)) { report_error( "Static buffer attr_buf overflow", NULL); defclose_r(defp); return (-1); } if ((attr_val = defread_r(attr_buf, defp)) == NULL) continue; got_config_data = TRUE; attrib_num = get_attrib_num(attr, strlen(attr)); if (attrib_num == key_bad) { report_error(attr, NULL); rc = -1; break; } /* * Allow either entries of the form * attr val * or * attr = val */ while (is_whitespace(*attr_val)) attr_val++; if (*attr_val == '=') attr_val++; while (is_whitespace(*attr_val)) attr_val++; len = strlen(attr_val); while (len > 0 && is_whitespace(attr_val[len - 1])) len--; if (verbose) { report_info("\t", attr); report_info("\t\t", attr_val); } if (IS_YP_BIND_INFO(attrib_num)) { rc = add_bind_attribute(attrib_num, attr_val, len, proxy_info); } else if (IS_YP_OPER_INFO(attrib_num)) { rc = add_operation_attribute(attrib_num, attr_val, len, nis_config, table_info); } if (p_error != no_parse_error) { report_error(attr_val, attr); rc = -1; break; } } file_source = NULL; /* Close the /etc/default file */ defclose_r(defp); } return (rc); } /* * FUNCTION: get_attrib_num_cmdline * * Parses the information for LDAP from the command line * The form of the command line request is * -x attribute=value * * RETURN VALUE: 0 on success, -1 on failure * * INPUT: command line values */ static config_key get_attrib_num_cmdline( const char *s, const char **begin_s, const char **end_s) { const char *s_end = s + strlen(s); const char *equal_s; const char *s1; config_key attrib_num; while (s < s_end && is_whitespace(*s)) s++; for (equal_s = s; equal_s < s_end; equal_s++) if (*equal_s == EQUAL_CHAR) break; if (equal_s == s_end) { p_error = parse_bad_command_line_attribute_format; return (key_bad); } for (s1 = equal_s; s1 > s && is_whitespace(s1[-1]); s1--) ; if (s1 == s) { p_error = parse_bad_command_line_attribute_format; return (key_bad); } attrib_num = get_attrib_num(s, s1 - s); if (attrib_num != key_bad) { s1 = equal_s + 1; while (s1 < s_end && is_whitespace(*s1)) s1++; *begin_s = s1; while (s_end > s1 && is_whitespace(s_end[-1])) s_end--; *end_s = s_end; } return (attrib_num); } /* * FUNCTION: parse_ldap_config_file * * Parses the information for LDAP from a configuration * file. If no file is specified, /var/nis/NIS+LDAPmapping * is used * * RETURN VALUE: 0 on success, -1 on failure * * INPUT: configuration file name */ static int parse_ldap_config_file( const char *config_file, __nis_ldap_proxy_info *proxy_info, __nis_config_t *nis_config, __nis_table_mapping_t **table_mapping, __nis_config_info_t *config_info, __nisdb_table_mapping_t *table_info) { int rc = 0; config_key attrib_num; int fd; char *attr_val; int len; if ((fd = open(config_file, O_RDONLY)) == -1) { p_error = parse_open_file_error; report_error(config_file, NULL); return (-1); } start_line_num = 1; cur_line_num = 1; if (verbose) report_info("Reading configuration from ", config_file); file_source = config_file; while ((attrib_num = get_file_attr_val(fd, &attr_val)) > 0) { len = attr_val == NULL ? 0 : strlen(attr_val); if (IS_CONFIG_KEYWORD(attrib_num)) { rc = add_config_attribute(attrib_num, attr_val, len, config_info); } else if (IS_BIND_INFO(attrib_num)) { rc = add_bind_attribute(attrib_num, attr_val, len, proxy_info); } else if (IS_OPER_INFO(attrib_num)) { rc = add_operation_attribute(attrib_num, attr_val, len, nis_config, table_info); } else { rc = add_mapping_attribute(attrib_num, attr_val, len, table_mapping); } if (rc < 0) { report_error(attr_val == NULL ? "" : attr_val, _key_val); if (attr_val) free(attr_val); break; } if (attr_val) free(attr_val); } (void) close(fd); if (attrib_num == key_bad) { report_error(_key_val, NULL); rc = -1; } start_line_num = 0; file_source = NULL; return (rc); } /* * FUNCTION: yp_parse_ldap_config_file * * Parses the information for LDAP from a configuration * file. If no file is specified, /var/yp/NISLDAPmapping * is used * * RETURN VALUE: 0 on success, -1 on failure * * INPUT: configuration file name */ int yp_parse_ldap_config_file( const char *config_file, __nis_ldap_proxy_info *proxy_info, __nis_config_t *nis_config, __nis_table_mapping_t **table_mapping, __nis_config_info_t *config_info, __nisdb_table_mapping_t *table_info, __yp_domain_context_t *ypDomains) { int rc = 0; config_key attrib_num; int fd; char *attr_val = NULL; int len; if ((fd = open(config_file, O_RDONLY)) == -1) { p_error = parse_open_file_error; report_error(config_file, NULL); return (-1); } start_line_num = 1; cur_line_num = 1; if (verbose) report_info("Reading configuration from ", config_file); file_source = config_file; while ((attrib_num = get_file_attr_val(fd, &attr_val)) > 0) { len = attr_val == NULL ? 0 : strlen(attr_val); if (IS_YP_CONFIG_KEYWORD(attrib_num)) { rc = add_config_attribute(attrib_num, attr_val, len, config_info); } else if (IS_YP_BIND_INFO(attrib_num)) { rc = add_bind_attribute(attrib_num, attr_val, len, proxy_info); } else if (IS_YP_OPER_INFO(attrib_num)) { rc = add_operation_attribute(attrib_num, attr_val, len, nis_config, table_info); } else if (IS_YP_DOMAIN_INFO(attrib_num)) { rc = add_ypdomains_attribute(attrib_num, attr_val, len, ypDomains); } else if (IS_YP_MAP_ATTR(attrib_num)) { rc = add_mapping_attribute(attrib_num, attr_val, len, table_mapping); } else { rc = -1; p_error = parse_unsupported_format; } if (rc < 0) { report_error(attr_val == NULL ? "" : attr_val, _key_val); if (attr_val) free(attr_val); break; } if (attr_val) { free(attr_val); attr_val = NULL; } } (void) close(fd); if (attrib_num == key_bad) { report_error(_key_val, NULL); rc = -1; } start_line_num = 0; file_source = NULL; return (rc); } /* * FUNCTION: get_file_attr_val * * Gets the next attribute from the configuration file. * * RETURN VALUE: The config key if more attributes * no_more_keys if eof * key_bad if error */ static config_key get_file_attr_val(int fd, char **attr_val) { char buf[BUFSIZE]; char *start_tag; char *start_val; char *end_val; char *cut_here; char *s; char *a; char *attribute_value; int ret; config_key attrib_num = no_more_keys; *attr_val = NULL; if ((ret = read_line(fd, buf, sizeof (buf))) > 0) { for (s = buf; is_whitespace(*s); s++) ; start_tag = s; while (*s != '\0' && !is_whitespace(*s)) s++; if (verbose) report_info("\t", start_tag); attrib_num = get_attrib_num(start_tag, s - start_tag); if (attrib_num == key_bad) return (key_bad); while (is_whitespace(*s)) s++; if (*s == '\0') return (attrib_num); start_val = s; /* note that read_line will not return a line ending with \ */ for (; *s != '\0'; s++) { if (*s == ESCAPE_CHAR) s++; } while (s > start_val && is_whitespace(s[-1])) s--; attribute_value = calloc(1, (size_t)(s - start_val) + 1); if (attribute_value == NULL) { p_error = parse_no_mem_error; return (key_bad); } attr_val[0] = attribute_value; a = *attr_val; end_val = s; cut_here = 0; for (s = start_val; s < end_val; s++) { if (*s == POUND_SIGN) { cut_here = s; while (s < end_val) { if (*s == DOUBLE_QUOTE_CHAR || *s == SINGLE_QUOTE_CHAR) { cut_here = 0; break; } s++; } } } if (cut_here != 0) end_val = cut_here; for (s = start_val; s < end_val; s++) *a++ = *s; *a++ = '\0'; } if (ret == -1) return (key_bad); return (attrib_num); } static LDAP * connect_to_ldap_config_server( char *sever_name, int server_port, __nis_config_info_t *config_info) { LDAP *ld = NULL; int ldapVersion = LDAP_VERSION3; int derefOption = LDAP_DEREF_ALWAYS; int timelimit = LDAP_NO_LIMIT; int sizelimit = LDAP_NO_LIMIT; int errnum; bool_t retrying = FALSE; int sleep_seconds = 1; struct berval cred; if (config_info->tls_method == no_tls) { ld = ldap_init(sever_name, server_port); if (ld == NULL) { p_error = parse_ldap_init_error; report_error(strerror(errno), NULL); return (NULL); } } else { if ((errnum = ldapssl_client_init( config_info->tls_cert_db, NULL)) < 0) { p_error = parse_ldapssl_client_init_error; report_error(ldapssl_err2string(errnum), NULL); return (NULL); } ld = ldapssl_init(sever_name, server_port, 1); if (ld == NULL) { p_error = parse_ldapssl_init_error; report_error(strerror(errno), NULL); return (NULL); } } (void) ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &ldapVersion); (void) ldap_set_option(ld, LDAP_OPT_DEREF, &derefOption); (void) ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF); (void) ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &timelimit); (void) ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &sizelimit); /* * Attempt to bind to the LDAP server. * We will loop until success or until an error other * than LDAP_CONNECT_ERROR or LDAP_SERVER_DOWN */ if (verbose) report_info("Connecting to ", sever_name); for (;;) { if (config_info->auth_method == simple) { errnum = ldap_simple_bind_s(ld, config_info->proxy_dn, config_info->proxy_passwd); } else if (config_info->auth_method == cram_md5) { cred.bv_len = strlen(config_info->proxy_passwd); cred.bv_val = config_info->proxy_passwd; errnum = ldap_sasl_cram_md5_bind_s(ld, config_info->proxy_dn, &cred, NULL, NULL); } else if (config_info->auth_method == digest_md5) { cred.bv_len = strlen(config_info->proxy_passwd); cred.bv_val = config_info->proxy_passwd; errnum = ldap_x_sasl_digest_md5_bind_s(ld, config_info->proxy_dn, &cred, NULL, NULL); } else { errnum = ldap_simple_bind_s(ld, NULL, NULL); } if (errnum == LDAP_SUCCESS) break; if (errnum == LDAP_CONNECT_ERROR || errnum == LDAP_SERVER_DOWN) { if (!retrying) { if (verbose) report_info( "LDAP server unavailable. Retrying...", NULL); retrying = TRUE; } (void) sleep(sleep_seconds); sleep_seconds *= 2; if (sleep_seconds > MAX_LDAP_CONFIG_RETRY_TIME) sleep_seconds = MAX_LDAP_CONFIG_RETRY_TIME; p_error = no_parse_error; continue; } p_error = parse_ldap_bind_error; report_error2(config_info->proxy_dn, ldap_err2string(errnum)); (void) ldap_unbind(ld); return (NULL); } if (verbose) report_info("Reading values from ", config_info->config_dn); return (ld); } /* * FUNCTION: process_ldap_config_result * * Extracts the LDAPMessage containing the nis+/LDAP * configuration * * RETURN VALUE: 0 on success, -1 on failure * * INPUT: LDAP the LDAP connection * LDAPMessage the LDAP message */ static int process_ldap_config_result( LDAP *ld, LDAPMessage *resultMsg, __nis_ldap_proxy_info *proxy_info, __nis_config_t *nis_config, __nis_table_mapping_t **table_mapping, __nisdb_table_mapping_t *table_info) { LDAPMessage *e; int errnum; char *attr; BerElement *ber = NULL; config_key attrib_num; char **vals; int n; int i; char *attr_val; int len; int rc = 0; bool_t error_reported = FALSE; e = ldap_first_entry(ld, resultMsg); if (e != NULL) { for (attr = ldap_first_attribute(ld, e, &ber); attr != NULL; attr = ldap_next_attribute(ld, e, ber)) { if (verbose) report_info("\t", attr); attrib_num = get_attrib_num(attr, strlen(attr)); if (attrib_num == key_bad) { report_error(attr, NULL); break; } if ((vals = ldap_get_values(ld, e, attr)) != NULL) { n = ldap_count_values(vals); /* parse the attribute values */ for (i = 0; i < n; i++) { attr_val = vals[i]; while (is_whitespace(*attr_val)) attr_val++; if (verbose) report_info("\t\t", attr_val); len = strlen(attr_val); while (len > 0 && is_whitespace(attr_val[len - 1])) len--; if (yp2ldap) { if (IS_YP_BIND_INFO(attrib_num)) { rc = add_bind_attribute(attrib_num, attr_val, len, proxy_info); } else if (IS_YP_OPER_INFO(attrib_num)) { rc = add_operation_attribute(attrib_num, attr_val, len, nis_config, table_info); } else if (IS_YP_MAP_ATTR(attrib_num)) { rc = add_mapping_attribute(attrib_num, attr_val, len, table_mapping); } else { p_error = parse_unsupported_format; } } else { if (IS_BIND_INFO(attrib_num)) { rc = add_bind_attribute(attrib_num, attr_val, len, proxy_info); } else if (IS_OPER_INFO(attrib_num)) { rc = add_operation_attribute(attrib_num, attr_val, len, nis_config, table_info); } else { rc = add_mapping_attribute(attrib_num, attr_val, len, table_mapping); } } if (p_error != no_parse_error) { report_error(attr_val, attr); error_reported = TRUE; break; } } ldap_value_free(vals); } else { (void) ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &errnum); if (errnum != LDAP_SUCCESS) p_error = parse_ldap_get_values_error; } ldap_memfree(attr); if (p_error != no_parse_error) break; } } else { errnum = ldap_result2error(ld, resultMsg, FALSE); if (errnum != LDAP_SUCCESS) p_error = parse_ldap_search_error; } if (ber != NULL) ber_free(ber, 0); if (!error_reported && p_error != no_parse_error) { report_error(ldap_err2string(errnum), 0); } if (p_error != no_parse_error) rc = -1; return (rc); } /* * FUNCTION: process_ldap_referral * * Retrieves the configuration for a referral url * * RETURN VALUE: 0 on success, -1 on failure, 1 on skip * * INPUT: url the ldap url * __nis_ldap_proxy_info */ static int process_ldap_referral( char *url, char **attrs, __nis_ldap_proxy_info *proxy_info, __nis_config_t *nis_config, __nis_table_mapping_t **table_mapping, __nis_config_info_t *config_info, __nisdb_table_mapping_t *table_info) { LDAPURLDesc *ludpp = NULL; int rc; LDAP *ld = NULL; int errnum; LDAPMessage *resultMsg = NULL; if ((rc = ldap_url_parse(url, &ludpp)) != LDAP_SUCCESS) return (1); #ifdef LDAP_URL_OPT_SECURE if (ludpp->lud_options & LDAP_URL_OPT_SECURE) { if (config_info->tls_method != ssl_tls) { ldap_free_urldesc(ludpp); return (1); } } else { if (config_info->tls_method != no_tls) { ldap_free_urldesc(ludpp); return (1); } } #endif if ((ld = connect_to_ldap_config_server(ludpp->lud_host, ludpp->lud_port, config_info)) == NULL) { ldap_free_urldesc(ludpp); return (-1); } errnum = ldap_search_s(ld, config_info->config_dn, LDAP_SCOPE_BASE, "objectclass=nisplusLDAPconfig", attrs, 0, &resultMsg); ldap_source = config_info->config_dn; if (errnum != LDAP_SUCCESS) { p_error = parse_ldap_search_error; report_error(ldap_err2string(errnum), 0); rc = -1; } else { rc = process_ldap_config_result(ld, resultMsg, proxy_info, nis_config, table_mapping, table_info); } ldap_source = NULL; (void) ldap_unbind(ld); if (resultMsg != NULL) (void) ldap_msgfree(resultMsg); return (rc); } /* * FUNCTION: process_ldap_referral_msg * * Retrieves the configuration from referred servers * * RETURN VALUE: 0 on success, -1 on failure * * INPUT: LDAP the LDAP connection * LDAPMessage the LDAP message * __nis_ldap_proxy_info */ static int process_ldap_referral_msg( LDAP *ld, LDAPMessage *resultMsg, char **attrs, __nis_ldap_proxy_info *proxy_info, __nis_config_t *nis_config, __nis_table_mapping_t **table_mapping, __nis_config_info_t *config_info, __nisdb_table_mapping_t *table_info) { int errCode; char **referralsp = NULL; int i; int rc; rc = ldap_parse_result(ld, resultMsg, &errCode, NULL, NULL, &referralsp, NULL, 0); if (rc != LDAP_SUCCESS || errCode != LDAP_REFERRAL) { p_error = parse_ldap_get_values_error; report_error(ldap_err2string(errCode), 0); rc = -1; } else { for (i = 0; referralsp[i] != NULL; i++) { rc = process_ldap_referral(referralsp[i], attrs, proxy_info, nis_config, table_mapping, config_info, table_info); if (rc <= 0) break; else report_info("Cannot use referral \n", referralsp[i]); } if (rc > 0) { p_error = parse_no_available_referrals_error; report_error(0, 0); } } if (referralsp) ldap_value_free(referralsp); return (rc); } /* * FUNCTION: parse_ldap_config_dn_attrs * * Parses the information for LDAP from the LDAP profile * - the profile object name, the LDAP server, and the * authentication method must be specified. * * RETURN VALUE: 0 on success, -1 on failure * * INPUT: __nis_ldap_proxy_info */ static int parse_ldap_config_dn_attrs( __nis_ldap_proxy_info *proxy_info, __nis_config_t *nis_config, __nis_table_mapping_t **table_mapping, __nis_config_info_t *config_info, __nisdb_table_mapping_t *table_info) { int rc = 0; LDAP *ld = NULL; int errnum; char *ldap_config_attributes[n_config_keys]; LDAPMessage *resultMsg = NULL; /* Determine if properly configured for LDAP lookup */ if (config_info->auth_method == simple && config_info->proxy_dn == NULL) p_error = parse_no_proxy_dn_error; else if (config_info->auth_method == (auth_method_t)NO_VALUE_SET) p_error = parse_no_config_auth_error; else if ((config_info->default_servers == NULL) || (config_info->default_servers[0] == '\0')) p_error = parse_no_config_server_addr; if (p_error != no_parse_error) { report_error(NULL, NULL); return (-1); } if (config_info->tls_method == (tls_method_t)NO_VALUE_SET) config_info->tls_method = no_tls; else if (config_info->tls_method == ssl_tls && (config_info->tls_cert_db == NULL || *config_info->tls_cert_db == '\0')) { p_error = parse_no_config_cert_db; report_error(NULL, NULL); return (-1); } if (verbose) report_info( "Getting configuration from LDAP server(s): ", config_info->default_servers); /* Determine which attributes should be retrieved */ get_attribute_list(proxy_info, nis_config, NULL, table_info, ldap_config_attributes); if ((ld = connect_to_ldap_config_server(config_info->default_servers, 0, config_info)) == NULL) return (-1); /* Get the attribute values */ errnum = ldap_search_s(ld, config_info->config_dn, LDAP_SCOPE_BASE, "objectclass=nisplusLDAPconfig", ldap_config_attributes, 0, &resultMsg); ldap_source = config_info->config_dn; if (errnum == LDAP_REFERRAL) { rc = process_ldap_referral_msg(ld, resultMsg, ldap_config_attributes, proxy_info, nis_config, table_mapping, config_info, table_info); } else if (errnum != LDAP_SUCCESS) { p_error = parse_ldap_search_error; report_error(ldap_err2string(errnum), 0); rc = -1; } else { rc = process_ldap_config_result(ld, resultMsg, proxy_info, nis_config, table_mapping, table_info); } ldap_source = NULL; (void) ldap_unbind(ld); if (resultMsg != NULL) (void) ldap_msgfree(resultMsg); return (rc); } bool_t is_cmd_line_option(config_key a_num) { const char *const *cmdline_options = cmdline_config; config_key attrib_num; const char *begin_s; const char *end_s; if (cmdline_options == NULL) return (FALSE); while (*cmdline_options != NULL) { attrib_num = get_attrib_num_cmdline( *cmdline_options, &begin_s, &end_s); if (attrib_num == a_num) break; cmdline_options++; } return (*cmdline_options != NULL); } /* * FUNCTION: get_attribute_list * * Get a list of attributes from the LDAP server that have not yet * been gotten. If config_info is NULL, the associated parameters * are not needed. * * RETURN VALUE: none * * INPUT: Returns a list of parameters in attributes * which is assumed to be of sufficient size. */ static void get_attribute_list( const __nis_ldap_proxy_info *proxy_info, const __nis_config_t *nis_config, const __nis_config_info_t *config_info, const __nisdb_table_mapping_t *table_info, char **attributes) { int n_attrs; /* Determine which attributes should be retrieved */ n_attrs = 0; if (config_info != NULL) { if (yp2ldap) { if (config_info->config_dn == NULL) attributes[n_attrs++] = YP_CONFIG_DN; if (config_info->default_servers == NULL) attributes[n_attrs++] = YP_CONFIG_SERVER_LIST; if (config_info->auth_method == (auth_method_t)NO_VALUE_SET) attributes[n_attrs++] = YP_CONFIG_AUTH_METHOD; if (config_info->tls_method == (tls_method_t)NO_VALUE_SET) attributes[n_attrs++] = YP_CONFIG_TLS_OPTION; if (config_info->proxy_dn == NULL) attributes[n_attrs++] = YP_CONFIG_PROXY_USER; if (config_info->proxy_passwd == NULL) attributes[n_attrs++] = YP_CONFIG_PROXY_PASSWD; if (config_info->tls_cert_db == NULL) attributes[n_attrs++] = YP_CONFIG_TLS_CERT_DB; } else { if (config_info->config_dn == NULL) attributes[n_attrs++] = CONFIG_DN; if (config_info->default_servers == NULL) attributes[n_attrs++] = CONFIG_SERVER_LIST; if (config_info->auth_method == (auth_method_t)NO_VALUE_SET) attributes[n_attrs++] = CONFIG_AUTH_METHOD; if (config_info->tls_method == (tls_method_t)NO_VALUE_SET) attributes[n_attrs++] = CONFIG_TLS_OPTION; if (config_info->proxy_dn == NULL) attributes[n_attrs++] = CONFIG_PROXY_USER; if (config_info->proxy_passwd == NULL) attributes[n_attrs++] = CONFIG_PROXY_PASSWD; if (config_info->tls_cert_db == NULL) attributes[n_attrs++] = CONFIG_TLS_CERT_DB; } } else { if (yp2ldap) { attributes[n_attrs++] = YP_DOMAIN_CONTEXT; attributes[n_attrs++] = YPPASSWDD_DOMAINS; attributes[n_attrs++] = YP_DB_ID_MAP; attributes[n_attrs++] = YP_COMMENT_CHAR; attributes[n_attrs++] = YP_MAP_FLAGS; attributes[n_attrs++] = YP_ENTRY_TTL; attributes[n_attrs++] = YP_NAME_FIELDS; attributes[n_attrs++] = YP_SPLIT_FIELD; attributes[n_attrs++] = YP_REPEATED_FIELD_SEPARATORS; attributes[n_attrs++] = YP_LDAP_OBJECT_DN; attributes[n_attrs++] = NIS_TO_LDAP_MAP; attributes[n_attrs++] = LDAP_TO_NIS_MAP; } else { attributes[n_attrs++] = DB_ID_MAP; attributes[n_attrs++] = ENTRY_TTL; attributes[n_attrs++] = LDAP_OBJECT_DN; attributes[n_attrs++] = NISPLUS_TO_LDAP_MAP; attributes[n_attrs++] = LDAP_TO_NISPLUS_MAP; } } if (yp2ldap) { if (proxy_info->default_servers == NULL) attributes[n_attrs++] = PREFERRED_SERVERS; if (proxy_info->auth_method == (auth_method_t)NO_VALUE_SET) attributes[n_attrs++] = AUTH_METHOD; if (proxy_info->tls_method == (tls_method_t)NO_VALUE_SET) attributes[n_attrs++] = YP_TLS_OPTION; if (proxy_info->tls_cert_db == NULL) attributes[n_attrs++] = YP_TLS_CERT_DB; if (proxy_info->default_search_base == NULL) attributes[n_attrs++] = SEARCH_BASE; if (proxy_info->proxy_dn == NULL) attributes[n_attrs++] = YP_PROXY_USER; if (proxy_info->proxy_passwd == NULL) attributes[n_attrs++] = YP_PROXY_PASSWD; if (proxy_info->default_nis_domain == NULL) attributes[n_attrs++] = YP_LDAP_BASE_DOMAIN; if (proxy_info->bind_timeout.tv_sec == (time_t)NO_VALUE_SET) attributes[n_attrs++] = YP_BIND_TIMEOUT; if (proxy_info->search_timeout.tv_sec == (time_t)NO_VALUE_SET) attributes[n_attrs++] = YP_SEARCH_TIMEOUT; if (proxy_info->modify_timeout.tv_sec == (time_t)NO_VALUE_SET) attributes[n_attrs++] = YP_MODIFY_TIMEOUT; if (proxy_info->add_timeout.tv_sec == (time_t)NO_VALUE_SET) attributes[n_attrs++] = YP_ADD_TIMEOUT; if (proxy_info->delete_timeout.tv_sec == (time_t)NO_VALUE_SET) attributes[n_attrs++] = YP_DELETE_TIMEOUT; if (proxy_info->search_time_limit == (int)NO_VALUE_SET) attributes[n_attrs++] = YP_SEARCH_TIME_LIMIT; if (proxy_info->search_size_limit == (int)NO_VALUE_SET) attributes[n_attrs++] = YP_SEARCH_SIZE_LIMIT; if (proxy_info->follow_referral == (follow_referral_t)NO_VALUE_SET) attributes[n_attrs++] = YP_FOLLOW_REFERRAL; if (table_info->retrieveError == (__nis_retrieve_error_t)NO_VALUE_SET) attributes[n_attrs++] = YP_RETRIEVE_ERROR_ACTION; if (table_info->retrieveErrorRetry.attempts == NO_VALUE_SET) attributes[n_attrs++] = YP_RETREIVE_ERROR_ATTEMPTS; if (table_info->retrieveErrorRetry.timeout == (time_t)NO_VALUE_SET) attributes[n_attrs++] = YP_RETREIVE_ERROR_TIMEOUT; if (table_info->storeError == (__nis_store_error_t)NO_VALUE_SET) attributes[n_attrs++] = YP_STORE_ERROR_ACTION; if (table_info->storeErrorRetry.attempts == NO_VALUE_SET) attributes[n_attrs++] = YP_STORE_ERROR_ATTEMPTS; if (table_info->storeErrorRetry.timeout == (time_t)NO_VALUE_SET) attributes[n_attrs++] = YP_STORE_ERROR_TIMEOUT; if (table_info->refreshError == (__nis_refresh_error_t)NO_VALUE_SET) attributes[n_attrs++] = REFRESH_ERROR_ACTION; if (table_info->refreshErrorRetry.attempts == NO_VALUE_SET) attributes[n_attrs++] = REFRESH_ERROR_ATTEMPTS; if (table_info->refreshErrorRetry.timeout == (time_t)NO_VALUE_SET) attributes[n_attrs++] = REFRESH_ERROR_TIMEOUT; if (table_info->matchFetch == (__nis_match_fetch_t)NO_VALUE_SET) attributes[n_attrs++] = YP_MATCH_FETCH; } else { if (proxy_info->default_servers == NULL) attributes[n_attrs++] = PREFERRED_SERVERS; if (proxy_info->auth_method == (auth_method_t)NO_VALUE_SET) attributes[n_attrs++] = AUTH_METHOD; if (proxy_info->tls_method == (tls_method_t)NO_VALUE_SET) attributes[n_attrs++] = TLS_OPTION; if (proxy_info->tls_cert_db == NULL) attributes[n_attrs++] = TLS_CERT_DB; if (proxy_info->default_search_base == NULL) attributes[n_attrs++] = SEARCH_BASE; if (proxy_info->proxy_dn == NULL) attributes[n_attrs++] = PROXY_USER; if (proxy_info->proxy_passwd == NULL) attributes[n_attrs++] = PROXY_PASSWD; if (proxy_info->default_nis_domain == NULL) attributes[n_attrs++] = LDAP_BASE_DOMAIN; if (proxy_info->bind_timeout.tv_sec == (time_t)NO_VALUE_SET) attributes[n_attrs++] = BIND_TIMEOUT; if (proxy_info->search_timeout.tv_sec == (time_t)NO_VALUE_SET) attributes[n_attrs++] = SEARCH_TIMEOUT; if (proxy_info->modify_timeout.tv_sec == (time_t)NO_VALUE_SET) attributes[n_attrs++] = MODIFY_TIMEOUT; if (proxy_info->add_timeout.tv_sec == (time_t)NO_VALUE_SET) attributes[n_attrs++] = ADD_TIMEOUT; if (proxy_info->delete_timeout.tv_sec == (time_t)NO_VALUE_SET) attributes[n_attrs++] = DELETE_TIMEOUT; if (proxy_info->search_time_limit == (int)NO_VALUE_SET) attributes[n_attrs++] = SEARCH_TIME_LIMIT; if (proxy_info->search_size_limit == (int)NO_VALUE_SET) attributes[n_attrs++] = SEARCH_SIZE_LIMIT; if (proxy_info->follow_referral == (follow_referral_t)NO_VALUE_SET) attributes[n_attrs++] = FOLLOW_REFERRAL; if (table_info->retrieveError == (__nis_retrieve_error_t)NO_VALUE_SET) attributes[n_attrs++] = RETRIEVE_ERROR_ACTION; if (table_info->retrieveErrorRetry.attempts == NO_VALUE_SET) attributes[n_attrs++] = RETREIVE_ERROR_ATTEMPTS; if (table_info->retrieveErrorRetry.timeout == (time_t)NO_VALUE_SET) attributes[n_attrs++] = RETREIVE_ERROR_TIMEOUT; if (table_info->storeError == (__nis_store_error_t)NO_VALUE_SET) attributes[n_attrs++] = STORE_ERROR_ACTION; if (table_info->storeErrorRetry.attempts == NO_VALUE_SET) attributes[n_attrs++] = STORE_ERROR_ATTEMPTS; if (table_info->storeErrorRetry.timeout == (time_t)NO_VALUE_SET) attributes[n_attrs++] = STORE_ERROR_TIMEOUT; if (table_info->refreshError == (__nis_refresh_error_t)NO_VALUE_SET) attributes[n_attrs++] = REFRESH_ERROR_ACTION; if (table_info->refreshErrorRetry.attempts == NO_VALUE_SET) attributes[n_attrs++] = REFRESH_ERROR_ATTEMPTS; if (table_info->refreshErrorRetry.timeout == (time_t)NO_VALUE_SET) attributes[n_attrs++] = REFRESH_ERROR_TIMEOUT; if (table_info->matchFetch == (__nis_match_fetch_t)NO_VALUE_SET) attributes[n_attrs++] = MATCH_FETCH; } switch (nis_config->initialUpdate) { case (__nis_initial_update_t)NO_VALUE_SET: attributes[n_attrs++] = INITIAL_UPDATE_ACTION; attributes[n_attrs++] = INITIAL_UPDATE_ONLY; break; case (__nis_initial_update_t)INITIAL_UPDATE_NO_ACTION: case (__nis_initial_update_t)NO_INITIAL_UPDATE_NO_ACTION: attributes[n_attrs++] = INITIAL_UPDATE_ACTION; break; case (__nis_initial_update_t)FROM_NO_INITIAL_UPDATE: case (__nis_initial_update_t)TO_NO_INITIAL_UPDATE: attributes[n_attrs++] = INITIAL_UPDATE_ONLY; break; } if (nis_config->threadCreationError == (__nis_thread_creation_error_t)NO_VALUE_SET) attributes[n_attrs++] = THREAD_CREATE_ERROR_ACTION; if (nis_config->threadCreationErrorTimeout.attempts == NO_VALUE_SET) attributes[n_attrs++] = THREAD_CREATE_ERROR_ATTEMPTS; if (nis_config->threadCreationErrorTimeout.timeout == (time_t)NO_VALUE_SET) attributes[n_attrs++] = THREAD_CREATE_ERROR_TIMEOUT; if (nis_config->dumpError == (__nis_dump_error_t)NO_VALUE_SET) attributes[n_attrs++] = DUMP_ERROR_ACTION; if (nis_config->dumpErrorTimeout.attempts == NO_VALUE_SET) attributes[n_attrs++] = DUMP_ERROR_ATTEMPTS; if (nis_config->dumpErrorTimeout.timeout == (time_t)NO_VALUE_SET) attributes[n_attrs++] = DUMP_ERROR_TIMEOUT; if (nis_config->resyncService == (__nis_resync_service_t)NO_VALUE_SET) attributes[n_attrs++] = RESYNC; if (nis_config->updateBatching == (__nis_update_batching_t)NO_VALUE_SET) attributes[n_attrs++] = UPDATE_BATCHING; if (nis_config->updateBatchingTimeout.timeout == (time_t)NO_VALUE_SET) attributes[n_attrs++] = UPDATE_BATCHING_TIMEOUT; if (nis_config->numberOfServiceThreads == (int)NO_VALUE_SET) attributes[n_attrs++] = NUMBER_THEADS; if (nis_config->emulate_yp == (int)NO_VALUE_SET) attributes[n_attrs++] = YP_EMULATION; /* maxRPCRecordSize is not configurable through LDAP profiles */ if (nis_config->maxRPCRecordSize == (int)NO_VALUE_SET) attributes[n_attrs++] = MAX_RPC_RECSIZE; attributes[n_attrs++] = NULL; } /* * Notes on adding new attributes * 1. Determine where the attribute value will be saved * Currently, the following structures are defined: * __nis_config_info_t config_info * __nis_ldap_proxy_info proxyInfo * __nis_config_t ldapConfig * __nisdb_table_mapping_t ldapDBTableMapping * __nis_table_mapping_t ldapTableMapping * or add a new structure or variable - this will require * more code. * 2. Initialize the value to a known unconfigured value. * This can be done in initialize_parse_structs or * parse_ldap_migration. * 3. In the header file nis_parse_ldap_conf.h, add the name * of the attribute. (Currently, the attribute name is assumed * to be the same for the command line, the preference file, * and LDAP.) The names are grouped logically. Add a corresponding * config_key to the enum. Note that position in this file is * essential because the macros such as IS_BIND_INFO depend on * the sequence. The corresponding macro (IS_CONFIG_KEYWORD, * IS_BIND_INFO, or IS_OPER_INFO) may need to be adjusted. These * are used to partition the attributes into smaller chunks. * 4. Add the correspond entry to the keyword_lookup array in * nis_parse_ldap_attr.c, which is used to determine the config_key * from the corresponding key word. * 5. Add the attribute to the list of attributes to retrieve from * the LDAP server if no value has been set in the function * parse_ldap_config_dn_attrs. (This assumes that the attribute * is not used to get the configuration from the LDAP server.) * 6. Add logic to parse the individual attribute in * add_config_attribute, add_bind_attribute, * add_operation_attribute, or add_mapping_attribute depending * which group of attributes the added attribute belongs to. * 7. In set_default_values, if the attribute value has not been set, set * the default value. If any additional fixup is needed depending * on other configuration values, it should be done here. * 8. If an attribute name is a subset of another, parse_ldap_default_conf * should be modified. */