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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <netdb.h> 30 #include <netinet/in.h> 31 #include <arpa/inet.h> 32 #include <sys/socket.h> 33 #include "ns_internal.h" 34 #include "ldap_common.h" 35 36 /* networks attributes filters */ 37 #define _N_NAME "cn" 38 #define _N_NETWORK "ipnetworknumber" 39 #define _F_GETNETBYNAME "(&(objectClass=ipNetwork)(cn=%s))" 40 #define _F_GETNETBYNAME_SSD "(&(%%s)(cn=%s))" 41 #define _F_GETNETBYADDR "(&(objectClass=ipNetwork)(ipNetworkNumber=%s))" 42 #define _F_GETNETBYADDR_SSD "(&(%%s)(ipNetworkNumber=%s))" 43 44 static const char *networks_attrs[] = { 45 _N_NAME, 46 _N_NETWORK, 47 (char *)NULL 48 }; 49 50 /* 51 * _nss_ldap_networks2ent is the data marshaling method for the networks 52 * getXbyY * (e.g., getbyname(), getbyaddr(), getnetent() backend processes. 53 * This method is called after a successful ldap search has been performed. 54 * This method will parse the ldap search values into struct netent = 55 * argp->buf.buffer which the frontend process expects. Three error conditions 56 * are expected and returned to nsswitch. 57 */ 58 59 static int 60 _nss_ldap_networks2ent(ldap_backend_ptr be, nss_XbyY_args_t *argp) 61 { 62 int i, j; 63 int nss_result; 64 int buflen = (int)0; 65 int firstime = (int)1; 66 unsigned long len = 0L; 67 char **mp, *cname = NULL; 68 #ifdef DEBUG 69 char addrstr[16]; 70 #endif /* DEBUG */ 71 char *buffer = (char *)NULL; 72 char *ceiling = (char *)NULL; 73 struct netent *ntk = (struct netent *)NULL; 74 ns_ldap_result_t *result = be->result; 75 ns_ldap_attr_t *attrptr; 76 77 buffer = argp->buf.buffer; 78 buflen = (size_t)argp->buf.buflen; 79 if (!argp->buf.result) { 80 nss_result = (int)NSS_STR_PARSE_ERANGE; 81 goto result_net2ent; 82 } 83 ntk = (struct netent *)argp->buf.result; 84 ceiling = buffer + buflen; 85 86 nss_result = (int)NSS_STR_PARSE_SUCCESS; 87 (void) memset(argp->buf.buffer, 0, buflen); 88 89 attrptr = getattr(result, 0); 90 if (attrptr == NULL) { 91 nss_result = (int)NSS_STR_PARSE_PARSE; 92 goto result_net2ent; 93 } 94 95 for (i = 0; i < result->entry->attr_count; i++) { 96 attrptr = getattr(result, i); 97 if (attrptr == NULL) { 98 nss_result = (int)NSS_STR_PARSE_PARSE; 99 goto result_net2ent; 100 } 101 if (strcasecmp(attrptr->attrname, _N_NAME) == 0) { 102 for (j = 0; j < attrptr->value_count; j++) { 103 if (firstime) { 104 /* 105 * The definition of the object class 106 * "ipNetwork" has a descripency between 107 * RFC 2307 and 2307bis. 108 * In 2307, "cn" is a MUST attribute. 109 * In 2307bis, "cn" is a MAY attribute. 110 * If "cn" is a MAY attribute, 111 * it does not appear in RDN and can't 112 * be derived from RDN as a canonical 113 * "cn" name. In that case, use 1st 114 * "cn" value as the official name. 115 */ 116 cname = __s_api_get_canonical_name( 117 result->entry, attrptr, 1); 118 if (cname == NULL) 119 /* 2307bis case */ 120 cname = attrptr->attrvalue[j]; 121 122 if (cname == NULL || 123 (len = strlen(cname)) < 1) { 124 nss_result = 125 NSS_STR_PARSE_PARSE; 126 goto result_net2ent; 127 } 128 ntk->n_name = buffer; 129 buffer += len + 1; 130 if (buffer >= ceiling) { 131 nss_result = 132 (int)NSS_STR_PARSE_ERANGE; 133 goto result_net2ent; 134 } 135 (void) strcpy(ntk->n_name, cname); 136 /* alias list */ 137 mp = ntk->n_aliases = 138 (char **)ROUND_UP(buffer, 139 sizeof (char **)); 140 buffer = (char *)ntk->n_aliases + 141 sizeof (char *) * 142 (attrptr->value_count + 1); 143 buffer = (char *)ROUND_UP(buffer, 144 sizeof (char **)); 145 if (buffer >= ceiling) { 146 nss_result = 147 (int)NSS_STR_PARSE_ERANGE; 148 goto result_net2ent; 149 } 150 firstime = (int)0; 151 } 152 /* alias list */ 153 if ((attrptr->attrvalue[j] == NULL) || 154 (len = strlen(attrptr->attrvalue[j])) < 1) { 155 nss_result = (int)NSS_STR_PARSE_PARSE; 156 goto result_net2ent; 157 } 158 /* skip canonical name(official name) */ 159 if (strcmp(attrptr->attrvalue[j], cname) == 0) 160 continue; 161 *mp = buffer; 162 buffer += len + 1; 163 if (buffer >= ceiling) { 164 nss_result = (int)NSS_STR_PARSE_ERANGE; 165 goto result_net2ent; 166 } 167 (void) strcpy(*mp++, attrptr->attrvalue[j]); 168 continue; 169 } 170 } 171 if (strcasecmp(attrptr->attrname, _N_NETWORK) == 0) { 172 if ((attrptr->attrvalue[0] == NULL) || 173 (len = strlen(attrptr->attrvalue[0])) < 1) { 174 nss_result = (int)NSS_STR_PARSE_PARSE; 175 goto result_net2ent; 176 } 177 if ((ntk->n_net = (in_addr_t) 178 inet_network(attrptr->attrvalue[0])) == 179 (in_addr_t)-1) { 180 nss_result = (int)NSS_STR_PARSE_PARSE; 181 goto result_net2ent; 182 } 183 #ifdef DEBUG 184 strlcpy(addrstr, attrptr->attrvalue[0], 185 sizeof (addrstr)); 186 #endif /* DEBUG */ 187 continue; 188 } 189 } 190 ntk->n_addrtype = AF_INET; 191 192 #ifdef DEBUG 193 (void) fprintf(stdout, "\n[getnetent.c: _nss_ldap_networks2ent]\n"); 194 (void) fprintf(stdout, " n_name: [%s]\n", ntk->n_name); 195 if (mp != NULL) { 196 for (mp = ntk->n_aliases; *mp != NULL; mp++) 197 (void) fprintf(stdout, " n_aliases: [%s]\n", *mp); 198 } 199 if (ntk->n_addrtype == AF_INET) 200 (void) fprintf(stdout, " n_addrtype: [AF_INET]\n"); 201 else 202 (void) fprintf(stdout, " n_addrtype: [%d]\n", 203 ntk->n_addrtype); 204 (void) fprintf(stdout, " n_net: [%s]\n", addrstr); 205 #endif /* DEBUG */ 206 207 result_net2ent: 208 209 (void) __ns_ldap_freeResult(&be->result); 210 return ((int)nss_result); 211 } 212 213 214 /* 215 * Takes an unsigned integer in host order, and returns a printable 216 * string for it as a network number. To allow for the possibility of 217 * naming subnets, only trailing dot-zeros are truncated. 218 */ 219 220 static int nettoa(int anet, char *buf, int buflen) 221 { 222 int addr; 223 char *p; 224 struct in_addr in; 225 226 if (buf == 0) 227 return ((int)1); 228 229 in = inet_makeaddr(anet, INADDR_ANY); 230 addr = in.s_addr; 231 if (strlcpy(buf, inet_ntoa(in), buflen) >= buflen) 232 return ((int)1); 233 if ((IN_CLASSA_HOST & htonl(addr)) == 0) { 234 p = strchr(buf, '.'); 235 if (p == NULL) 236 return ((int)1); 237 *p = 0; 238 } else if ((IN_CLASSB_HOST & htonl(addr)) == 0) { 239 p = strchr(buf, '.'); 240 if (p == NULL) 241 return ((int)1); 242 p = strchr(p + 1, '.'); 243 if (p == NULL) 244 return ((int)1); 245 *p = 0; 246 } else if ((IN_CLASSC_HOST & htonl(addr)) == 0) { 247 p = strrchr(buf, '.'); 248 if (p == NULL) 249 return ((int)1); 250 *p = 0; 251 } 252 253 return ((int)0); 254 } 255 256 257 /* 258 * getbyname gets a network entry by name. This function constructs an 259 * ldap search filter using the network name invocation parameter and the 260 * getnetbyname search filter defined. Once the filter is constructed, we 261 * search for a matching entry and marshal the data results into struct 262 * netent for the frontend process. The function _nss_ldap_networks2ent 263 * performs the data marshaling. 264 */ 265 266 static nss_status_t 267 getbyname(ldap_backend_ptr be, void *a) 268 { 269 nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; 270 char searchfilter[SEARCHFILTERLEN]; 271 char userdata[SEARCHFILTERLEN]; 272 char netname[SEARCHFILTERLEN]; 273 int ret; 274 275 if (_ldap_filter_name(netname, argp->key.name, sizeof (netname)) != 0) 276 return ((nss_status_t)NSS_NOTFOUND); 277 278 ret = snprintf(searchfilter, sizeof (searchfilter), 279 _F_GETNETBYNAME, netname); 280 if (ret >= sizeof (searchfilter) || ret < 0) 281 return ((nss_status_t)NSS_NOTFOUND); 282 283 ret = snprintf(userdata, sizeof (userdata), 284 _F_GETNETBYNAME_SSD, netname); 285 if (ret >= sizeof (userdata) || ret < 0) 286 return ((nss_status_t)NSS_NOTFOUND); 287 288 return ((nss_status_t)_nss_ldap_lookup(be, argp, 289 _NETWORKS, searchfilter, NULL, 290 _merge_SSD_filter, userdata)); 291 } 292 293 294 /* 295 * getbyaddr gets a network entry by ip address. This function constructs an 296 * ldap search filter using the name invocation parameter and the getnetbyaddr 297 * search filter defined. Once the filter is constructed, we search for a 298 * matching entry and marshal the data results into struct netent for the 299 * frontend process. The function _nss_ldap_networks2ent performs the data 300 * marshaling. 301 */ 302 303 static nss_status_t 304 getbyaddr(ldap_backend_ptr be, void *a) 305 { 306 nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; 307 char addrstr[16]; 308 char searchfilter[SEARCHFILTERLEN]; 309 char userdata[SEARCHFILTERLEN]; 310 int ret; 311 312 if (nettoa((int)argp->key.netaddr.net, addrstr, 16) != 0) 313 return ((nss_status_t)NSS_UNAVAIL); 314 315 ret = snprintf(searchfilter, sizeof (searchfilter), 316 _F_GETNETBYADDR, addrstr); 317 if (ret >= sizeof (searchfilter) || ret < 0) 318 return ((nss_status_t)NSS_NOTFOUND); 319 320 ret = snprintf(userdata, sizeof (userdata), 321 _F_GETNETBYADDR_SSD, addrstr); 322 if (ret >= sizeof (userdata) || ret < 0) 323 return ((nss_status_t)NSS_NOTFOUND); 324 325 return ((nss_status_t)_nss_ldap_lookup(be, argp, 326 _NETWORKS, searchfilter, NULL, 327 _merge_SSD_filter, userdata)); 328 } 329 330 static ldap_backend_op_t net_ops[] = { 331 _nss_ldap_destr, 332 _nss_ldap_endent, 333 _nss_ldap_setent, 334 _nss_ldap_getent, 335 getbyname, 336 getbyaddr 337 }; 338 339 340 /* 341 * _nss_ldap_networks_constr is where life begins. This function calls the 342 * generic ldap constructor function to define and build the abstract data 343 * types required to support ldap operations. 344 */ 345 346 /*ARGSUSED0*/ 347 nss_backend_t * 348 _nss_ldap_networks_constr(const char *dummy1, const char *dummy2, 349 const char *dummy3) 350 { 351 352 return ((nss_backend_t *)_nss_ldap_constr(net_ops, 353 sizeof (net_ops)/sizeof (net_ops[0]), _NETWORKS, 354 networks_attrs, _nss_ldap_networks2ent)); 355 } 356