1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <netdb.h> 29 #include <netinet/in.h> 30 #include <arpa/inet.h> 31 #include <sys/socket.h> 32 #include "ns_internal.h" 33 #include "ldap_common.h" 34 35 /* networks attributes filters */ 36 #define _N_NAME "cn" 37 #define _N_NETWORK "ipnetworknumber" 38 #define _F_GETNETBYNAME "(&(objectClass=ipNetwork)(cn=%s))" 39 #define _F_GETNETBYNAME_SSD "(&(%%s)(cn=%s))" 40 #define _F_GETNETBYADDR "(&(objectClass=ipNetwork)(|(ipNetworkNumber=%s)" \ 41 "(ipNetworkNumber=%s)))" 42 #define _F_GETNETBYADDR_SSD "(&(%%s)(|(ipNetworkNumber=%s)" \ 43 "(ipNetworkNumber=%s)))" 44 45 static const char *networks_attrs[] = { 46 _N_NAME, 47 _N_NETWORK, 48 (char *)NULL 49 }; 50 51 /* 52 * _nss_ldap_networks2str is the data marshaling method for the networks 53 * getXbyY * (e.g., getbyname(), getbyaddr(), getnetent() backend processes. 54 * This method is called after a successful ldap search has been performed. 55 * This method will parse the ldap search values into the file format. 56 * e.g. 57 * 58 * SunRay-ce2 10.34.96.0 SunRay 59 * 60 */ 61 static int 62 _nss_ldap_networks2str(ldap_backend_ptr be, nss_XbyY_args_t *argp) 63 { 64 uint_t i; 65 int nss_result; 66 int buflen = 0, len; 67 char **network, *cname = NULL; 68 char *buffer = NULL; 69 ns_ldap_result_t *result = be->result; 70 ns_ldap_attr_t *names; 71 72 if (result == NULL) 73 return (NSS_STR_PARSE_PARSE); 74 buflen = argp->buf.buflen; 75 76 if (argp->buf.result != NULL) { 77 if ((be->buffer = calloc(1, buflen)) == NULL) { 78 nss_result = NSS_STR_PARSE_PARSE; 79 goto result_net2str; 80 } 81 buffer = be->buffer; 82 } else 83 buffer = argp->buf.buffer; 84 85 nss_result = NSS_STR_PARSE_SUCCESS; 86 (void) memset(argp->buf.buffer, 0, buflen); 87 88 names = __ns_ldap_getAttrStruct(result->entry, _N_NAME); 89 if (names == NULL || names->attrvalue == NULL) { 90 nss_result = NSS_STR_PARSE_PARSE; 91 goto result_net2str; 92 } 93 /* Get the canonical name */ 94 cname = __s_api_get_canonical_name(result->entry, names, 1); 95 /* 96 * The definition of the object class "ipNetwork" has a 97 * discrepency between RFC 2307 and 2307bis. 98 * In 2307, "cn" is a MUST attribute. In 2307bis, "cn" is a 99 * MAY attribute. 100 * If "cn" is a MAY attribute, it does not appear in RDN and can't 101 * be derived from RDN as a canonical "cn" name. In that case, use 1st 102 * "cn" value as the official name. 103 */ 104 if (cname == NULL) 105 /* 2307bis case */ 106 cname = names->attrvalue[0]; 107 if (cname == NULL || (len = strlen(cname)) < 1) { 108 nss_result = NSS_STR_PARSE_PARSE; 109 goto result_net2str; 110 } 111 network = __ns_ldap_getAttr(result->entry, _N_NETWORK); 112 if (network == NULL || network[0] == NULL || 113 (len = strlen(network[0])) < 1) { 114 nss_result = NSS_STR_PARSE_PARSE; 115 goto result_net2str; 116 } 117 len = snprintf(buffer, buflen, "%s %s", cname, network[0]); 118 TEST_AND_ADJUST(len, buffer, buflen, result_net2str); 119 /* Append aliases */ 120 for (i = 0; i < names->value_count; i++) { 121 if (names->attrvalue[i] == NULL) { 122 nss_result = NSS_STR_PARSE_PARSE; 123 goto result_net2str; 124 } 125 /* Skip the canonical name */ 126 if (strcasecmp(names->attrvalue[i], cname) != 0) { 127 len = snprintf(buffer, buflen, " %s", 128 names->attrvalue[i]); 129 TEST_AND_ADJUST(len, buffer, buflen, result_net2str); 130 } 131 } 132 133 /* The front end marshaller doesn't need to copy trailing nulls */ 134 if (argp->buf.result != NULL) 135 be->buflen = strlen(be->buffer); 136 137 result_net2str: 138 139 (void) __ns_ldap_freeResult(&be->result); 140 return (nss_result); 141 } 142 143 /* 144 * Takes an unsigned integer in host order, and returns a printable 145 * string for it as a network number. To allow for the possibility of 146 * naming subnets, only trailing dot-zeros are truncated. 147 * buf2 is untruncated version. 148 */ 149 150 static int nettoa(int anet, char *buf, char *buf2, int buflen) 151 { 152 int addr; 153 char *p; 154 struct in_addr in; 155 156 if (buf == NULL || buf2 == NULL) 157 return ((int)1); 158 159 in = inet_makeaddr(anet, INADDR_ANY); 160 addr = in.s_addr; 161 if (inet_ntop(AF_INET, (const void *)&in, buf2, INET_ADDRSTRLEN) 162 == NULL) 163 return ((int)1); 164 if (strlcpy(buf, buf2, buflen) >= buflen) 165 return ((int)1); 166 if ((IN_CLASSA_HOST & htonl(addr)) == 0) { 167 p = strchr(buf, '.'); 168 if (p == NULL) 169 return ((int)1); 170 *p = 0; 171 } else if ((IN_CLASSB_HOST & htonl(addr)) == 0) { 172 p = strchr(buf, '.'); 173 if (p == NULL) 174 return ((int)1); 175 p = strchr(p + 1, '.'); 176 if (p == NULL) 177 return ((int)1); 178 *p = 0; 179 } else if ((IN_CLASSC_HOST & htonl(addr)) == 0) { 180 p = strrchr(buf, '.'); 181 if (p == NULL) 182 return ((int)1); 183 *p = 0; 184 } 185 186 return ((int)0); 187 } 188 189 190 /* 191 * getbyname gets a network entry by name. This function constructs an 192 * ldap search filter using the network name invocation parameter and the 193 * getnetbyname search filter defined. Once the filter is constructed, we 194 * search for a matching entry and marshal the data results into struct 195 * netent for the frontend process. The function _nss_ldap_networks2ent 196 * performs the data marshaling. 197 */ 198 199 static nss_status_t 200 getbyname(ldap_backend_ptr be, void *a) 201 { 202 nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; 203 char searchfilter[SEARCHFILTERLEN]; 204 char userdata[SEARCHFILTERLEN]; 205 char netname[SEARCHFILTERLEN]; 206 int ret; 207 208 if (_ldap_filter_name(netname, argp->key.name, sizeof (netname)) != 0) 209 return ((nss_status_t)NSS_NOTFOUND); 210 211 ret = snprintf(searchfilter, sizeof (searchfilter), 212 _F_GETNETBYNAME, netname); 213 if (ret >= sizeof (searchfilter) || ret < 0) 214 return ((nss_status_t)NSS_NOTFOUND); 215 216 ret = snprintf(userdata, sizeof (userdata), 217 _F_GETNETBYNAME_SSD, netname); 218 if (ret >= sizeof (userdata) || ret < 0) 219 return ((nss_status_t)NSS_NOTFOUND); 220 221 return ((nss_status_t)_nss_ldap_lookup(be, argp, 222 _NETWORKS, searchfilter, NULL, 223 _merge_SSD_filter, userdata)); 224 } 225 226 227 /* 228 * getbyaddr gets a network entry by ip address. This function constructs an 229 * ldap search filter using the name invocation parameter and the getnetbyaddr 230 * search filter defined. Once the filter is constructed, we search for a 231 * matching entry and marshal the data results into struct netent for the 232 * frontend process. The function _nss_ldap_networks2ent performs the data 233 * marshaling. 234 */ 235 236 static nss_status_t 237 getbyaddr(ldap_backend_ptr be, void *a) 238 { 239 nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; 240 char addrstr[INET_ADDRSTRLEN], addrstr2[INET_ADDRSTRLEN]; 241 char searchfilter[SEARCHFILTERLEN]; 242 char userdata[SEARCHFILTERLEN]; 243 int ret; 244 245 if (nettoa((int)argp->key.netaddr.net, addrstr, addrstr2, 246 INET_ADDRSTRLEN) != 0) 247 return ((nss_status_t)NSS_UNAVAIL); 248 249 ret = snprintf(searchfilter, sizeof (searchfilter), 250 _F_GETNETBYADDR, addrstr, addrstr2); 251 if (ret >= sizeof (searchfilter) || ret < 0) 252 return ((nss_status_t)NSS_NOTFOUND); 253 254 ret = snprintf(userdata, sizeof (userdata), 255 _F_GETNETBYADDR_SSD, addrstr, addrstr2); 256 if (ret >= sizeof (userdata) || ret < 0) 257 return ((nss_status_t)NSS_NOTFOUND); 258 259 return ((nss_status_t)_nss_ldap_lookup(be, argp, 260 _NETWORKS, searchfilter, NULL, 261 _merge_SSD_filter, userdata)); 262 } 263 264 static ldap_backend_op_t net_ops[] = { 265 _nss_ldap_destr, 266 _nss_ldap_endent, 267 _nss_ldap_setent, 268 _nss_ldap_getent, 269 getbyname, 270 getbyaddr 271 }; 272 273 274 /* 275 * _nss_ldap_networks_constr is where life begins. This function calls the 276 * generic ldap constructor function to define and build the abstract data 277 * types required to support ldap operations. 278 */ 279 280 /*ARGSUSED0*/ 281 nss_backend_t * 282 _nss_ldap_networks_constr(const char *dummy1, const char *dummy2, 283 const char *dummy3) 284 { 285 286 return ((nss_backend_t *)_nss_ldap_constr(net_ops, 287 sizeof (net_ops)/sizeof (net_ops[0]), _NETWORKS, 288 networks_attrs, _nss_ldap_networks2str)); 289 } 290