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 <ctype.h> 30 #include <netdb.h> 31 #include "ns_internal.h" 32 #include "ldap_common.h" 33 34 /* services attributes filters */ 35 #define _S_NAME "cn" 36 #define _S_PORT "ipserviceport" 37 #define _S_PROTOCOL "ipserviceprotocol" 38 #define _F_GETSERVBYNAME "(&(objectClass=ipService)(cn=%s))" 39 #define _F_GETSERVBYNAME_SSD "(&(%%s)(cn=%s))" 40 #define _F_GETSERVBYNAMEPROTO \ 41 "(&(objectClass=ipService)(cn=%s)(ipServiceProtocol=%s))" 42 #define _F_GETSERVBYNAMEPROTO_SSD \ 43 "(&(%%s)(cn=%s)(ipServiceProtocol=%s))" 44 #define _F_GETSERVBYPORT "(&(objectClass=ipService)(ipServicePort=%ld))" 45 #define _F_GETSERVBYPORT_SSD "(&(%%s)(ipServicePort=%ld))" 46 #define _F_GETSERVBYPORTPROTO \ 47 "(&(objectClass=ipService)(ipServicePort=%ld)(ipServiceProtocol=%s))" 48 #define _F_GETSERVBYPORTPROTO_SSD \ 49 "(&(%%s)(ipServicePort=%ld)(ipServiceProtocol=%s))" 50 51 typedef struct _nss_services_cookie { 52 int index; /* index of ipserviceprotocol */ 53 char *cname; /* canonical name, don't free it */ 54 ns_ldap_result_t *result; 55 } _nss_services_cookie_t; 56 57 static const char *services_attrs[] = { 58 _S_NAME, 59 _S_PORT, 60 _S_PROTOCOL, 61 (char *)NULL 62 }; 63 64 void 65 _nss_services_cookie_free(void **ckP) { 66 _nss_services_cookie_t **cookieP = (_nss_services_cookie_t **)ckP; 67 if (cookieP && *cookieP) { 68 if ((*cookieP)->result) 69 (void) __ns_ldap_freeResult(&(*cookieP)->result); 70 free(*cookieP); 71 *cookieP = NULL; 72 } 73 } 74 75 static _nss_services_cookie_t * 76 _nss_services_cookie_new(ns_ldap_result_t *result, int index, char *cname) { 77 78 _nss_services_cookie_t *cookie; 79 80 if ((cookie = calloc(1, sizeof (*cookie))) == NULL) 81 return (NULL); 82 83 /* 84 * result has been allocated either by __ns_ldap_firstEntry 85 * or __ns_ldap_nextEntry. 86 */ 87 cookie->result = result; 88 89 cookie->index = index; 90 cookie->cname = cname; 91 92 return (cookie); 93 } 94 95 /* 96 * _nss_ldap_services2ent is the data marshaling method for the services 97 * getXbyY * (e.g., getbyname(), getbyport(), getent()) backend processes. 98 * This method is called after a successful ldap search has been performed. 99 * This method will parse the ldap search values into *serv = (struct 100 * servent *)argp->buf.result which the frontend process expects. Three error 101 * conditions are expected and returned to nsswitch. 102 * 103 * In section 5.5 of RFC 2307, it specifies that a "services" LDAP entry 104 * containing multiple ipserviceprotocol values should be able to be mapped 105 * to multiple "services" entities. Code has been added to support 106 * this one to many mapping feature. 107 */ 108 109 static int 110 _nss_ldap_services2ent(ldap_backend_ptr be, nss_XbyY_args_t *argp) 111 { 112 int i, j, k; 113 int nss_result; 114 int buflen = (int)0; 115 int firstime = (int)1; 116 unsigned long len = 0L; 117 char **mp, *cname = NULL, *protoval = NULL; 118 char *buffer = (char *)NULL; 119 char *ceiling = (char *)NULL; 120 struct servent *serv = (struct servent *)NULL; 121 ns_ldap_result_t *result; 122 ns_ldap_attr_t *attrptr, *protocol = NULL; 123 _nss_services_cookie_t *cookie = (_nss_services_cookie_t *) 124 be->services_cookie; 125 126 buffer = (char *)argp->buf.buffer; 127 buflen = (size_t)argp->buf.buflen; 128 serv = (struct servent *)argp->buf.result; 129 ceiling = buffer + buflen; 130 #ifdef DEBUG 131 (void) fprintf(stderr, "[getservent.c: _nss_ldap_services2ent]\n"); 132 #endif /* DEBUG */ 133 134 if (cookie) { 135 /* 136 * getservent_r with multiple protocol values and the entry 137 * is enumerated 2nd time or beyond 138 */ 139 result = cookie->result; 140 cname = cookie->cname; 141 } else { 142 /* 143 * getservbyname_r, getservbyport_r or 144 * getservent_r with single protocol value or multiple values 145 * and the entry is enumerated 1st time 146 */ 147 result = be->result; 148 } 149 150 nss_result = (int)NSS_STR_PARSE_SUCCESS; 151 (void) memset(argp->buf.buffer, 0, buflen); 152 153 attrptr = getattr(result, 0); 154 if (attrptr == NULL) { 155 nss_result = (int)NSS_STR_PARSE_PARSE; 156 goto result_srvs2ent; 157 } 158 for (i = 0; i < result->entry->attr_count; i++) { 159 attrptr = getattr(result, i); 160 if (attrptr == NULL) { 161 nss_result = (int)NSS_STR_PARSE_PARSE; 162 goto result_srvs2ent; 163 } 164 if (strcasecmp(attrptr->attrname, _S_NAME) == 0) { 165 for (j = 0; j < attrptr->value_count; j++) { 166 if (firstime) { 167 /* service name */ 168 if (cname == NULL) { 169 cname = __s_api_get_canonical_name( 170 result->entry, attrptr, 1); 171 } 172 if (cname == NULL || 173 (len = strlen(cname)) < 1) { 174 nss_result = 175 NSS_STR_PARSE_PARSE; 176 goto result_srvs2ent; 177 } 178 serv->s_name = buffer; 179 buffer += len + 1; 180 if (buffer >= ceiling) { 181 nss_result = 182 (int)NSS_STR_PARSE_ERANGE; 183 goto result_srvs2ent; 184 } 185 (void) strcpy(serv->s_name, cname); 186 /* alias list */ 187 mp = serv->s_aliases = 188 (char **)ROUND_UP(buffer, 189 sizeof (char **)); 190 buffer = (char *)serv->s_aliases + 191 sizeof (char *) * 192 (attrptr->value_count + 1); 193 buffer = (char *)ROUND_UP(buffer, 194 sizeof (char **)); 195 if (buffer >= ceiling) { 196 nss_result = 197 (int)NSS_STR_PARSE_ERANGE; 198 goto result_srvs2ent; 199 } 200 firstime = (int)0; 201 } 202 /* alias list */ 203 if ((attrptr->attrvalue[j] == NULL) || 204 (len = strlen(attrptr->attrvalue[j])) < 1) { 205 nss_result = (int)NSS_STR_PARSE_PARSE; 206 goto result_srvs2ent; 207 } 208 /* skip canonical name */ 209 if (strcmp(cname, attrptr->attrvalue[j]) == 0) 210 continue; 211 212 *mp = buffer; 213 buffer += len + 1; 214 if (buffer >= ceiling) { 215 nss_result = (int)NSS_STR_PARSE_ERANGE; 216 goto result_srvs2ent; 217 } 218 (void) strcpy(*mp++, attrptr->attrvalue[j]); 219 continue; 220 } 221 } 222 223 if (strcasecmp(attrptr->attrname, _S_PORT) == 0) { 224 if ((attrptr->attrvalue[0] == NULL) || 225 (len = strlen(attrptr->attrvalue[0])) < 1) { 226 nss_result = (int)NSS_STR_PARSE_PARSE; 227 goto result_srvs2ent; 228 } 229 serv->s_port = 230 htons((ushort_t)atoi(attrptr->attrvalue[0])); 231 continue; 232 } 233 234 if (strcasecmp(attrptr->attrname, _S_PROTOCOL) == 0) { 235 /* protocol name */ 236 if (attrptr->attrvalue == NULL) { 237 nss_result = (int)NSS_STR_PARSE_PARSE; 238 goto result_srvs2ent; 239 } 240 protocol = attrptr; 241 if (cookie) { 242 /* 243 * getservent_r 244 * Get current value then increment index 245 */ 246 protoval = attrptr->attrvalue[cookie->index++]; 247 } else if (attrptr->value_count > 1 && 248 argp->key.serv.proto) { 249 /* 250 * getserverbyname_r and getservbyport_r 251 * 252 * If there are more than one value and 253 * it needs to match protocol too, 254 * iterate each value to find matching one. 255 * getservent_r sets key.serv.proto to NULL, 256 * so it wouldn't run this part of code. 257 */ 258 for (k = 0; k < attrptr->value_count; k++) { 259 if (attrptr->attrvalue[k] == NULL) { 260 nss_result = 261 NSS_STR_PARSE_PARSE; 262 goto result_srvs2ent; 263 } 264 if (strcmp(attrptr->attrvalue[k], 265 argp->key.serv.proto) == 0) { 266 protoval = 267 attrptr->attrvalue[k]; 268 break; 269 } 270 } 271 } else { 272 /* 273 * 1. getserverbyname_r and getservbyport_r 274 * 275 * It does not need to match protocol or 276 * ipserviceprotocol has single value, 277 * return the first one 278 * 279 * 2. getservent_r with single value 280 * or multiple values and the entry is 281 * enumerated 1st time, 282 * return the first one 283 * 284 */ 285 protoval = attrptr->attrvalue[0]; 286 } 287 288 if (protoval == NULL || (len = strlen(protoval)) < 1) { 289 nss_result = (int)NSS_STR_PARSE_PARSE; 290 goto result_srvs2ent; 291 } 292 serv->s_proto = buffer; 293 buffer += len + 1; 294 if (buffer >= ceiling) { 295 nss_result = (int)NSS_STR_PARSE_ERANGE; 296 goto result_srvs2ent; 297 } 298 (void) strcpy(serv->s_proto, protoval); 299 continue; 300 } 301 } 302 303 if (be->enumcookie != NULL && cookie == NULL && 304 protocol->value_count > 1) { 305 /* 306 * getservent_r with multiple ipserviceprotocol values 307 * and the entry is enumerated 1st time 308 * 309 * Create cookie and save result in the cookie 310 * "attrvalue[0]" of ipserviceprotocol is returned, 311 * so it starts with index 1. Also save the canonical name. 312 */ 313 be->services_cookie = 314 (void *)_nss_services_cookie_new(be->result, 1, cname); 315 if (be->services_cookie == NULL) { 316 nss_result = NSS_STR_PARSE_PARSE; 317 goto result_srvs2ent; 318 } 319 320 /* reset be->result so it won't get freed later */ 321 be->result = NULL; 322 } 323 324 #ifdef DEBUG 325 (void) fprintf(stdout, "\n[getservent.c: _nss_ldap_services2ent]\n"); 326 (void) fprintf(stdout, " s_name: [%s]\n", serv->s_name); 327 if (mp != NULL) { 328 for (mp = serv->s_aliases; *mp != NULL; mp++) 329 (void) fprintf(stdout, " s_aliases: [%s]\n", *mp); 330 } 331 (void) fprintf(stdout, " s_port: [%d]\n", serv->s_port); 332 (void) fprintf(stdout, " s_protocol: [%s]\n", serv->s_proto); 333 #endif /* DEBUG */ 334 335 result_srvs2ent: 336 if (cookie) { 337 /* 338 * getservent_r with multiple ipserviceprotocol values and 339 * the entry is enumerated 2nd time or beyond 340 */ 341 if (nss_result != NSS_STR_PARSE_SUCCESS || 342 cookie->index >= protocol->value_count) { 343 /* 344 * If it's an error case or it has iterated all 345 * ipservicesprotocol value(s) then free cookie and 346 * set it to NULL 347 * 348 */ 349 _nss_services_cookie_free( 350 (void **)&be->services_cookie); 351 } 352 } else { 353 /* 354 * getservbyname_r, getservbyport_r, or 355 * getservent_r with single value or can't create cookie 356 */ 357 (void) __ns_ldap_freeResult(&be->result); 358 } 359 return ((int)nss_result); 360 } 361 362 363 /* 364 * getbyname gets struct servent values by service name. This 365 * function constructs an ldap search filter using the service 366 * name invocation parameter and the getservbyname search filter 367 * defined. Once the filter is constructed, we search for a matching 368 * entry and marshal the data results into *serv = (struct servent *) 369 * argp->buf.result. The function _nss_ldap_services2ent performs 370 * the data marshaling. 371 */ 372 373 static nss_status_t 374 getbyname(ldap_backend_ptr be, void *a) 375 { 376 nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; 377 const char *proto = argp->key.serv.proto; 378 char searchfilter[SEARCHFILTERLEN]; 379 char userdata[SEARCHFILTERLEN]; 380 char name[SEARCHFILTERLEN]; 381 char protocol[SEARCHFILTERLEN]; 382 int ret; 383 384 if (_ldap_filter_name(name, argp->key.serv.serv.name, sizeof (name)) 385 != 0) 386 return ((nss_status_t)NSS_NOTFOUND); 387 388 if (proto == NULL) { 389 ret = snprintf(searchfilter, sizeof (searchfilter), 390 _F_GETSERVBYNAME, name); 391 if (ret >= sizeof (searchfilter) || ret < 0) 392 return ((nss_status_t)NSS_NOTFOUND); 393 394 ret = snprintf(userdata, sizeof (userdata), 395 _F_GETSERVBYNAME_SSD, name); 396 if (ret >= sizeof (userdata) || ret < 0) 397 return ((nss_status_t)NSS_NOTFOUND); 398 } else { 399 if (_ldap_filter_name(protocol, proto, sizeof (protocol)) != 0) 400 return ((nss_status_t)NSS_NOTFOUND); 401 402 ret = snprintf(searchfilter, sizeof (searchfilter), 403 _F_GETSERVBYNAMEPROTO, name, protocol); 404 if (ret >= sizeof (searchfilter) || ret < 0) 405 return ((nss_status_t)NSS_NOTFOUND); 406 407 ret = snprintf(userdata, sizeof (userdata), 408 _F_GETSERVBYNAMEPROTO_SSD, name, protocol); 409 if (ret >= sizeof (userdata) || ret < 0) 410 return ((nss_status_t)NSS_NOTFOUND); 411 } 412 413 return ((nss_status_t)_nss_ldap_lookup(be, argp, 414 _SERVICES, searchfilter, NULL, 415 _merge_SSD_filter, userdata)); 416 } 417 418 419 /* 420 * getbyport gets struct servent values by service port. This 421 * function constructs an ldap search filter using the service 422 * name invocation parameter and the getservbyport search filter 423 * defined. Once the filter is constructed, we search for a matching 424 * entry and marshal the data results into *serv = (struct servent *) 425 * argp->buf.result. The function _nss_ldap_services2ent performs 426 * the data marshaling. 427 */ 428 429 static nss_status_t 430 getbyport(ldap_backend_ptr be, void *a) 431 { 432 nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; 433 const char *proto = argp->key.serv.proto; 434 char portstr[12]; 435 char searchfilter[SEARCHFILTERLEN]; 436 char userdata[SEARCHFILTERLEN]; 437 char protocol[SEARCHFILTERLEN]; 438 int ret; 439 440 ret = snprintf(portstr, sizeof (portstr), " %d", 441 ntohs((ushort_t)argp->key.serv.serv.port)); 442 if (ret >= sizeof (portstr) || ret < 0) 443 return ((nss_status_t)NSS_NOTFOUND); 444 445 if (proto == NULL) { 446 ret = snprintf(searchfilter, sizeof (searchfilter), 447 _F_GETSERVBYPORT, strtol(portstr, (char **)NULL, 10)); 448 if (ret >= sizeof (searchfilter) || ret < 0) 449 return ((nss_status_t)NSS_NOTFOUND); 450 451 ret = snprintf(userdata, sizeof (userdata), 452 _F_GETSERVBYPORT_SSD, strtol(portstr, (char **)NULL, 10)); 453 if (ret >= sizeof (userdata) || ret < 0) 454 return ((nss_status_t)NSS_NOTFOUND); 455 } else { 456 if (_ldap_filter_name(protocol, proto, sizeof (protocol)) != 0) 457 return ((nss_status_t)NSS_NOTFOUND); 458 459 ret = snprintf(searchfilter, sizeof (searchfilter), 460 _F_GETSERVBYPORTPROTO, 461 strtol(portstr, (char **)NULL, 10), protocol); 462 if (ret >= sizeof (searchfilter) || ret < 0) 463 return ((nss_status_t)NSS_NOTFOUND); 464 465 ret = snprintf(userdata, sizeof (userdata), 466 _F_GETSERVBYPORTPROTO_SSD, 467 strtol(portstr, (char **)NULL, 10), protocol); 468 if (ret >= sizeof (userdata) || ret < 0) 469 return ((nss_status_t)NSS_NOTFOUND); 470 } 471 472 return ((nss_status_t)_nss_ldap_lookup(be, argp, 473 _SERVICES, searchfilter, NULL, 474 _merge_SSD_filter, userdata)); 475 } 476 477 static ldap_backend_op_t serv_ops[] = { 478 _nss_ldap_destr, 479 _nss_ldap_endent, 480 _nss_ldap_setent, 481 _nss_ldap_getent, 482 getbyname, 483 getbyport 484 }; 485 486 487 /* 488 * _nss_ldap_services_constr is where life begins. This function calls 489 * the generic ldap constructor function to define and build the 490 * abstract data types required to support ldap operations. 491 */ 492 493 /*ARGSUSED0*/ 494 nss_backend_t * 495 _nss_ldap_services_constr(const char *dummy1, const char *dummy2, 496 const char *dummy3) 497 { 498 499 return ((nss_backend_t *)_nss_ldap_constr(serv_ops, 500 sizeof (serv_ops)/sizeof (serv_ops[0]), _SERVICES, 501 services_attrs, _nss_ldap_services2ent)); 502 } 503