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 /* protocols attributes filters */ 35 #define _P_NAME "cn" 36 #define _P_PROTO "ipprotocolnumber" 37 #define _F_GETPROTOBYNAME "(&(objectClass=ipProtocol)(cn=%s))" 38 #define _F_GETPROTOBYNAME_SSD "(&(%%s)(cn=%s))" 39 #define _F_GETPROTOBYNUMBER \ 40 "(&(objectClass=ipProtocol)(ipProtocolNumber=%d))" 41 #define _F_GETPROTOBYNUMBER_SSD \ 42 "(&(%%s)(ipProtocolNumber=%d))" 43 44 static const char *protocols_attrs[] = { 45 _P_NAME, 46 _P_PROTO, 47 (char *)NULL 48 }; 49 50 51 /* 52 * _nss_ldap_protocols2ent is the data marshaling method for the protocols 53 * getXbyY * (e.g., getbyname(), getbynumber(), getent()) 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 *proto = (struct 56 * protoent *)argp->buf.result which the frontend process expects. Three error 57 * conditions are expected and returned to nsswitch. 58 */ 59 60 static int 61 _nss_ldap_protocols2ent(ldap_backend_ptr be, nss_XbyY_args_t *argp) 62 { 63 int i, j; 64 int nss_result; 65 int buflen = (int)0; 66 int firstime = (int)1; 67 unsigned long len = 0L; 68 char *cp, **mp, *cname = NULL; 69 char *buffer = (char *)NULL; 70 char *ceiling = (char *)NULL; 71 struct protoent *proto = (struct protoent *)NULL; 72 ns_ldap_result_t *result = be->result; 73 ns_ldap_attr_t *attrptr; 74 75 buffer = (char *)argp->buf.buffer; 76 buflen = (size_t)argp->buf.buflen; 77 if (!argp->buf.result) { 78 nss_result = (int)NSS_STR_PARSE_ERANGE; 79 goto result_pls2ent; 80 } 81 proto = (struct protoent *)argp->buf.result; 82 ceiling = buffer + buflen; 83 84 nss_result = (int)NSS_STR_PARSE_SUCCESS; 85 (void) memset(argp->buf.buffer, 0, buflen); 86 87 attrptr = getattr(result, 0); 88 if (attrptr == NULL) { 89 nss_result = (int)NSS_STR_PARSE_PARSE; 90 goto result_pls2ent; 91 } 92 for (i = 0; i < result->entry->attr_count; i++) { 93 attrptr = getattr(result, i); 94 if (attrptr == NULL) { 95 nss_result = (int)NSS_STR_PARSE_PARSE; 96 goto result_pls2ent; 97 } 98 if (strcasecmp(attrptr->attrname, _P_NAME) == 0) { 99 for (j = 0; j < attrptr->value_count; j++) { 100 if (firstime) { 101 /* protocol name */ 102 cname = __s_api_get_canonical_name( 103 result->entry, attrptr, 1); 104 if (cname == NULL || 105 (len = strlen(cname)) < 1) { 106 nss_result = 107 NSS_STR_PARSE_PARSE; 108 goto result_pls2ent; 109 } 110 proto->p_name = buffer; 111 buffer += len + 1; 112 if (buffer >= ceiling) { 113 nss_result = 114 (int)NSS_STR_PARSE_ERANGE; 115 goto result_pls2ent; 116 } 117 (void) strcpy(proto->p_name, cname); 118 mp = proto->p_aliases = 119 (char **)ROUND_UP(buffer, 120 sizeof (char **)); 121 buffer = (char *)proto->p_aliases + 122 sizeof (char *) * 123 (attrptr->value_count + 1); 124 buffer = (char *)ROUND_UP(buffer, 125 sizeof (char **)); 126 if (buffer >= ceiling) { 127 nss_result = 128 (int)NSS_STR_PARSE_ERANGE; 129 goto result_pls2ent; 130 } 131 firstime = (int)0; 132 } 133 /* alias list */ 134 if ((attrptr->attrvalue[j] == NULL) || 135 (len = strlen(attrptr->attrvalue[j])) < 1) { 136 nss_result = NSS_STR_PARSE_PARSE; 137 goto result_pls2ent; 138 } 139 /* 140 * When the data is imported by ldapaddent, 141 * it does not save the aliase in the "cn" 142 * that is same as the canonical name but only 143 * differnt in case. 144 * e.g. 145 * icmp 1 ICMP 146 * 147 * is saved as 148 * 149 * dn: cn=icmp, ... 150 * ... 151 * cn: icmp 152 * ... 153 * So it needs to replicate the canonical name 154 * as an aliase of upper case. 155 * 156 * But in the case of 157 * ospf 89 OSPFIGP 158 * it creates a redundant aliase. 159 * e.g. 160 * dn: cn=icmp, ... 161 * ... 162 * cn: ospf 163 * cn: OSPFIGP 164 * ... 165 * 166 * getent services ospf 167 * ==> ospf 89 ospf OSPFIGP 168 * 169 * Some condition check is added to handle this 170 * scenario. Such check also works with 171 * following scenario. 172 * dn: cn=icmp, ... 173 * ... 174 * cn: icmp 175 * cn: ICMP 176 * ... 177 */ 178 if (strcmp(proto->p_name, 179 attrptr->attrvalue[j]) == 0) { 180 if (attrptr->value_count > 1) 181 /* Do not replicate */ 182 continue; 183 for (cp = attrptr->attrvalue[j]; 184 *cp; cp++) 185 *cp = toupper(*cp); 186 } 187 *mp = buffer; 188 buffer += len + 1; 189 if (buffer >= ceiling) { 190 nss_result = (int)NSS_STR_PARSE_ERANGE; 191 goto result_pls2ent; 192 } 193 (void) strcpy(*mp++, attrptr->attrvalue[j]); 194 continue; 195 } 196 } 197 if (strcasecmp(attrptr->attrname, _P_PROTO) == 0) { 198 if ((attrptr->attrvalue[0] == NULL) || 199 (len = strlen(attrptr->attrvalue[0])) < 1) { 200 nss_result = (int)NSS_STR_PARSE_PARSE; 201 goto result_pls2ent; 202 } 203 errno = 0; 204 proto->p_proto = (int)strtol(attrptr->attrvalue[0], 205 (char **)NULL, 10); 206 if (errno != 0) { 207 nss_result = (int)NSS_STR_PARSE_PARSE; 208 goto result_pls2ent; 209 } 210 continue; 211 } 212 } 213 214 #ifdef DEBUG 215 (void) fprintf(stdout, "\n[getprotoent.c: _nss_ldap_protocols2ent]\n"); 216 (void) fprintf(stdout, " p_name: [%s]\n", proto->p_name); 217 if (mp != NULL) { 218 for (mp = proto->p_aliases; *mp != NULL; mp++) 219 (void) fprintf(stdout, " p_aliases: [%s]\n", *mp); 220 } 221 (void) fprintf(stdout, " p_proto: [%d]\n", proto->p_proto); 222 #endif /* DEBUG */ 223 224 result_pls2ent: 225 226 (void) __ns_ldap_freeResult(&be->result); 227 return ((int)nss_result); 228 } 229 230 231 /* 232 * getbyname gets struct protoent values by protocol name. This 233 * function constructs an ldap search filter using the protocol 234 * name invocation parameter and the getprotobyname search filter 235 * defined. Once the filter is constructed, we search for a matching 236 * entry and marshal the data results into *proto = (struct * 237 * protoent *)argp->buf.result. The function _nss_ldap_protocols2ent 238 * performs the data marshaling. 239 */ 240 241 static nss_status_t 242 getbyname(ldap_backend_ptr be, void *a) 243 { 244 nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; 245 char searchfilter[SEARCHFILTERLEN]; 246 char userdata[SEARCHFILTERLEN]; 247 char name[SEARCHFILTERLEN]; 248 int ret; 249 250 if (_ldap_filter_name(name, argp->key.name, sizeof (name)) != 0) 251 return ((nss_status_t)NSS_NOTFOUND); 252 253 ret = snprintf(searchfilter, sizeof (searchfilter), 254 _F_GETPROTOBYNAME, name); 255 if (ret >= sizeof (searchfilter) || ret < 0) 256 return ((nss_status_t)NSS_NOTFOUND); 257 258 ret = snprintf(userdata, sizeof (userdata), 259 _F_GETPROTOBYNAME_SSD, name); 260 if (ret >= sizeof (userdata) || ret < 0) 261 return ((nss_status_t)NSS_NOTFOUND); 262 263 return ((nss_status_t)_nss_ldap_lookup(be, argp, 264 _PROTOCOLS, searchfilter, NULL, 265 _merge_SSD_filter, userdata)); 266 } 267 268 269 /* 270 * getbynumber gets struct protoent values by protocol number. This 271 * function constructs an ldap search filter using the protocol 272 * name invocation parameter and the getprotobynumber search filter 273 * defined. Once the filter is constructed, we search for a matching 274 * entry and marshal the data results into *proto = (struct * 275 * protoent *)argp->buf.result. The function _nss_ldap_protocols2ent 276 * performs the data marshaling. 277 */ 278 279 static nss_status_t 280 getbynumber(ldap_backend_ptr be, void *a) 281 { 282 nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; 283 char searchfilter[SEARCHFILTERLEN]; 284 char userdata[SEARCHFILTERLEN]; 285 int ret; 286 287 ret = snprintf(searchfilter, sizeof (searchfilter), 288 _F_GETPROTOBYNUMBER, argp->key.number); 289 if (ret >= sizeof (searchfilter) || ret < 0) 290 return ((nss_status_t)NSS_NOTFOUND); 291 292 ret = snprintf(userdata, sizeof (userdata), 293 _F_GETPROTOBYNUMBER_SSD, argp->key.number); 294 if (ret >= sizeof (userdata) || ret < 0) 295 return ((nss_status_t)NSS_NOTFOUND); 296 297 return ((nss_status_t)_nss_ldap_lookup(be, argp, 298 _PROTOCOLS, searchfilter, NULL, 299 _merge_SSD_filter, userdata)); 300 } 301 302 static ldap_backend_op_t proto_ops[] = { 303 _nss_ldap_destr, 304 _nss_ldap_endent, 305 _nss_ldap_setent, 306 _nss_ldap_getent, 307 getbyname, 308 getbynumber 309 }; 310 311 312 /* 313 * _nss_ldap_protocols_constr is where life begins. This function calls 314 * the generic ldap constructor function to define and build the abstract 315 * data types required to support ldap operations. 316 */ 317 318 /*ARGSUSED0*/ 319 nss_backend_t * 320 _nss_ldap_protocols_constr(const char *dummy1, const char *dummy2, 321 const char *dummy3) 322 { 323 324 return ((nss_backend_t *)_nss_ldap_constr(proto_ops, 325 sizeof (proto_ops)/sizeof (proto_ops[0]), _PROTOCOLS, 326 protocols_attrs, _nss_ldap_protocols2ent)); 327 } 328