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 <ctype.h> 29 #include <netdb.h> 30 #include "ns_internal.h" 31 #include "ldap_common.h" 32 33 /* protocols attributes filters */ 34 #define _P_NAME "cn" 35 #define _P_PROTO "ipprotocolnumber" 36 #define _F_GETPROTOBYNAME "(&(objectClass=ipProtocol)(cn=%s))" 37 #define _F_GETPROTOBYNAME_SSD "(&(%%s)(cn=%s))" 38 #define _F_GETPROTOBYNUMBER \ 39 "(&(objectClass=ipProtocol)(ipProtocolNumber=%d))" 40 #define _F_GETPROTOBYNUMBER_SSD \ 41 "(&(%%s)(ipProtocolNumber=%d))" 42 43 static const char *protocols_attrs[] = { 44 _P_NAME, 45 _P_PROTO, 46 (char *)NULL 47 }; 48 49 typedef struct protocol_alias { 50 char *protocol; 51 char *alias; 52 } protocol_alias_t; 53 54 static const protocol_alias_t ip_aliases[10] = { 55 { "ip", "IP" }, 56 { "ipip", "IP-IP" }, 57 { "ipcomp", "IPComp" }, 58 { "ipv6", "IPv6" }, 59 { "ipv6-route", "IPv6-Route" }, 60 { "ipv6-frag", "IPv6-Frag" }, 61 { "ipv6-icmp", "IPv6-ICMP" }, 62 { "ipv6-nonxt", "IPv6-NoNxt" }, 63 { "ipv6-opts", "IPv6-Opts" }, 64 { NULL, NULL } 65 }; 66 67 /* 68 * When the data is imported by ldapaddent, it does not save the aliase in the 69 * "cn" that is same as the canonical name but only different in case. 70 * e.g. 71 * icmp 1 ICMP 72 * 73 * is saved as 74 * 75 * dn: cn=icmp, ... 76 * ... 77 * cn: icmp 78 * ... 79 * 80 * So it needs to replicate the canonical name as an alias of upper case. 81 * But some protocol does have different aliases. 82 * 83 * e.g. 84 * dn: cn=ospf, ... 85 * ... 86 * cn: ospf 87 * cn: OSPFIGP 88 * ... 89 * 90 * For many ip* protocols, the aliases are mixed cased. Maybe it's case 91 * insensitive. But this fucntion tries to restore the aliases to the original 92 * form as much as possible. If the alias can't be found in the aliases table, 93 * it assumes the alias is all upper case. 94 * 95 */ 96 static char * 97 get_alias(char *protocol) { 98 int i; 99 char *cp; 100 101 if (strncmp(protocol, "ip", 2) == 0) { 102 for (i = 0; ip_aliases[i].protocol != NULL; i++) { 103 if (strcmp(protocol, ip_aliases[i].protocol) == 0) 104 return (ip_aliases[i].alias); 105 } 106 /* 107 * No aliase in the table. Return an all upper case aliase 108 */ 109 for (cp = protocol; *cp; cp++) 110 *cp = toupper(*cp); 111 112 return (protocol); 113 } else { 114 /* Return an all upper case aliase */ 115 for (cp = protocol; *cp; cp++) 116 *cp = toupper(*cp); 117 118 return (protocol); 119 } 120 121 } 122 /* 123 * _nss_ldap_protocols2str is the data marshaling method for the protocols 124 * getXbyY * (e.g., getbyname(), getbynumber(), getent()) backend processes. 125 * This method is called after a successful ldap search has been performed. 126 * This method will parse the ldap search values into a file format. 127 * e.g. 128 * idrp 45 IDRP 129 * or 130 * ospf 89 OSPFIGP 131 */ 132 133 static int 134 _nss_ldap_protocols2str(ldap_backend_ptr be, nss_XbyY_args_t *argp) 135 { 136 uint_t i; 137 int nss_result; 138 int buflen = 0, len; 139 char *cname = NULL; 140 char *buffer = NULL, **number, *alias; 141 ns_ldap_result_t *result = be->result; 142 ns_ldap_attr_t *names; 143 144 if (result == NULL) 145 return (NSS_STR_PARSE_PARSE); 146 147 buflen = argp->buf.buflen; 148 if (argp->buf.result != NULL) { 149 if ((be->buffer = calloc(1, buflen)) == NULL) { 150 nss_result = NSS_STR_PARSE_PARSE; 151 goto result_pls2str; 152 } 153 buffer = be->buffer; 154 } else 155 buffer = argp->buf.buffer; 156 157 nss_result = NSS_STR_PARSE_SUCCESS; 158 (void) memset(argp->buf.buffer, 0, buflen); 159 160 names = __ns_ldap_getAttrStruct(result->entry, _P_NAME); 161 if (names == NULL || names->attrvalue == NULL) { 162 nss_result = NSS_STR_PARSE_PARSE; 163 goto result_pls2str; 164 } 165 /* Get the canonical name */ 166 cname = __s_api_get_canonical_name(result->entry, names, 1); 167 if (cname == NULL || (len = strlen(cname)) < 1) { 168 nss_result = NSS_STR_PARSE_PARSE; 169 goto result_pls2str; 170 } 171 number = __ns_ldap_getAttr(result->entry, _P_PROTO); 172 if (number == NULL || number[0] == NULL || 173 (len = strlen(number[0])) < 1) { 174 nss_result = NSS_STR_PARSE_PARSE; 175 goto result_pls2str; 176 } 177 len = snprintf(buffer, buflen, "%s %s", cname, number[0]); 178 TEST_AND_ADJUST(len, buffer, buflen, result_pls2str); 179 /* Append aliases */ 180 if (names->value_count == 1) { 181 /* create an aliase from protocol name */ 182 alias = get_alias(cname); 183 len = snprintf(buffer, buflen, " %s", alias); 184 TEST_AND_ADJUST(len, buffer, buflen, result_pls2str); 185 186 } else { 187 for (i = 0; i < names->value_count; i++) { 188 if (names->attrvalue[i] == NULL) { 189 nss_result = NSS_STR_PARSE_PARSE; 190 goto result_pls2str; 191 } 192 /* Skip the canonical name */ 193 if (strcasecmp(names->attrvalue[i], cname) != 0) { 194 len = snprintf(buffer, buflen, " %s", 195 names->attrvalue[i]); 196 TEST_AND_ADJUST(len, buffer, buflen, 197 result_pls2str); 198 } 199 } 200 } 201 202 /* The front end marshaller doesn't need to copy trailing nulls */ 203 if (argp->buf.result != NULL) 204 be->buflen = strlen(be->buffer); 205 206 result_pls2str: 207 208 (void) __ns_ldap_freeResult(&be->result); 209 return ((int)nss_result); 210 } 211 212 213 /* 214 * getbyname gets struct protoent values by protocol name. This 215 * function constructs an ldap search filter using the protocol 216 * name invocation parameter and the getprotobyname search filter 217 * defined. Once the filter is constructed, we search for a matching 218 * entry and marshal the data results into *proto = (struct * 219 * protoent *)argp->buf.result. The function _nss_ldap_protocols2ent 220 * performs the data marshaling. 221 */ 222 223 static nss_status_t 224 getbyname(ldap_backend_ptr be, void *a) 225 { 226 nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; 227 char searchfilter[SEARCHFILTERLEN]; 228 char userdata[SEARCHFILTERLEN]; 229 char name[SEARCHFILTERLEN]; 230 int ret; 231 232 if (_ldap_filter_name(name, argp->key.name, sizeof (name)) != 0) 233 return ((nss_status_t)NSS_NOTFOUND); 234 235 ret = snprintf(searchfilter, sizeof (searchfilter), 236 _F_GETPROTOBYNAME, name); 237 if (ret >= sizeof (searchfilter) || ret < 0) 238 return ((nss_status_t)NSS_NOTFOUND); 239 240 ret = snprintf(userdata, sizeof (userdata), 241 _F_GETPROTOBYNAME_SSD, name); 242 if (ret >= sizeof (userdata) || ret < 0) 243 return ((nss_status_t)NSS_NOTFOUND); 244 245 return ((nss_status_t)_nss_ldap_lookup(be, argp, 246 _PROTOCOLS, searchfilter, NULL, 247 _merge_SSD_filter, userdata)); 248 } 249 250 251 /* 252 * getbynumber gets struct protoent values by protocol number. This 253 * function constructs an ldap search filter using the protocol 254 * name invocation parameter and the getprotobynumber search filter 255 * defined. Once the filter is constructed, we search for a matching 256 * entry and marshal the data results into *proto = (struct * 257 * protoent *)argp->buf.result. The function _nss_ldap_protocols2ent 258 * performs the data marshaling. 259 */ 260 261 static nss_status_t 262 getbynumber(ldap_backend_ptr be, void *a) 263 { 264 nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; 265 char searchfilter[SEARCHFILTERLEN]; 266 char userdata[SEARCHFILTERLEN]; 267 int ret; 268 269 ret = snprintf(searchfilter, sizeof (searchfilter), 270 _F_GETPROTOBYNUMBER, argp->key.number); 271 if (ret >= sizeof (searchfilter) || ret < 0) 272 return ((nss_status_t)NSS_NOTFOUND); 273 274 ret = snprintf(userdata, sizeof (userdata), 275 _F_GETPROTOBYNUMBER_SSD, argp->key.number); 276 if (ret >= sizeof (userdata) || ret < 0) 277 return ((nss_status_t)NSS_NOTFOUND); 278 279 return ((nss_status_t)_nss_ldap_lookup(be, argp, 280 _PROTOCOLS, searchfilter, NULL, 281 _merge_SSD_filter, userdata)); 282 } 283 284 static ldap_backend_op_t proto_ops[] = { 285 _nss_ldap_destr, 286 _nss_ldap_endent, 287 _nss_ldap_setent, 288 _nss_ldap_getent, 289 getbyname, 290 getbynumber 291 }; 292 293 294 /* 295 * _nss_ldap_protocols_constr is where life begins. This function calls 296 * the generic ldap constructor function to define and build the abstract 297 * data types required to support ldap operations. 298 */ 299 300 /*ARGSUSED0*/ 301 nss_backend_t * 302 _nss_ldap_protocols_constr(const char *dummy1, const char *dummy2, 303 const char *dummy3) 304 { 305 306 return ((nss_backend_t *)_nss_ldap_constr(proto_ops, 307 sizeof (proto_ops)/sizeof (proto_ops[0]), _PROTOCOLS, 308 protocols_attrs, _nss_ldap_protocols2str)); 309 } 310