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