1 /* nssov.c - nss-ldap overlay for slapd */ 2 /* $OpenLDAP: pkg/ldap/contrib/slapd-modules/nssov/nssov.c,v 1.1.2.1 2008/07/08 18:53:57 quanah Exp $ */ 3 /* 4 * Copyright 2008 by Howard Chu, Symas Corp. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted only as authorized by the OpenLDAP 9 * Public License. 10 * 11 * A copy of this license is available in the file LICENSE in the 12 * top-level directory of the distribution or, alternatively, at 13 * <http://www.OpenLDAP.org/license.html>. 14 */ 15 /* 16 * This code references portions of the nss-ldapd package 17 * written by Arthur de Jong. The nss-ldapd code was forked 18 * from the nss-ldap library written by Luke Howard. 19 */ 20 21 #include "nssov.h" 22 23 #ifndef SLAPD_OVER_NSSOV 24 #define SLAPD_OVER_NSSOV SLAPD_MOD_DYNAMIC 25 #endif 26 27 #include "../slapd/config.h" /* not nss-ldapd config.h */ 28 29 #include "lutil.h" 30 31 #include <ac/errno.h> 32 #include <ac/unistd.h> 33 #include <fcntl.h> 34 #include <sys/stat.h> 35 36 /* buffer sizes for I/O */ 37 #define READBUFFER_MINSIZE 32 38 #define READBUFFER_MAXSIZE 64 39 #define WRITEBUFFER_MINSIZE 64 40 #define WRITEBUFFER_MAXSIZE 64*1024 41 42 /* Find the given attribute's value in the RDN of the DN */ 43 int nssov_find_rdnval(struct berval *dn, AttributeDescription *ad, struct berval *value) 44 { 45 struct berval rdn; 46 char *next; 47 48 BER_BVZERO(value); 49 dnRdn( dn, &rdn ); 50 do { 51 next = ber_bvchr( &rdn, '+' ); 52 if ( rdn.bv_val[ad->ad_cname.bv_len] == '=' && 53 !ber_bvcmp( &rdn, &ad->ad_cname )) { 54 if ( next ) 55 rdn.bv_len = next - rdn.bv_val; 56 value->bv_val = rdn.bv_val + ad->ad_cname.bv_len + 1; 57 value->bv_len = rdn.bv_len - ad->ad_cname.bv_len - 1; 58 break; 59 } 60 if ( !next ) 61 break; 62 next++; 63 rdn.bv_len -= next - rdn.bv_val; 64 rdn.bv_val = next; 65 } while (1); 66 } 67 68 /* create a search filter using a name that requires escaping */ 69 int nssov_filter_byname(nssov_mapinfo *mi,int key,struct berval *name,struct berval *buf) 70 { 71 char buf2[1024]; 72 struct berval bv2 = {sizeof(buf2),buf2}; 73 74 /* escape attribute */ 75 if (nssov_escape(name,&bv2)) 76 return -1; 77 /* build filter */ 78 if (bv2.bv_len + mi->mi_filter.bv_len + mi->mi_attrs[key].an_desc->ad_cname.bv_len + 6 > 79 buf->bv_len ) 80 return -1; 81 buf->bv_len = snprintf(buf->bv_val, buf->bv_len, "(&%s(%s=%s))", 82 mi->mi_filter.bv_val, mi->mi_attrs[key].an_desc->ad_cname.bv_val, 83 bv2.bv_val ); 84 return 0; 85 } 86 87 /* create a search filter using a string converted from an int */ 88 int nssov_filter_byid(nssov_mapinfo *mi,int key,struct berval *id,struct berval *buf) 89 { 90 /* build filter */ 91 if (id->bv_len + mi->mi_filter.bv_len + mi->mi_attrs[key].an_desc->ad_cname.bv_len + 6 > 92 buf->bv_len ) 93 return -1; 94 buf->bv_len = snprintf(buf->bv_val, buf->bv_len, "(&%s(%s=%s))", 95 mi->mi_filter.bv_val, mi->mi_attrs[key].an_desc->ad_cname.bv_val, 96 id->bv_val ); 97 return 0; 98 } 99 100 void get_userpassword(struct berval *attr,struct berval *pw) 101 { 102 int i; 103 /* go over the entries and return the remainder of the value if it 104 starts with {crypt} or crypt$ */ 105 for (i=0;!BER_BVISNULL(&attr[i]);i++) 106 { 107 if (strncasecmp(attr[i].bv_val,"{crypt}",7)==0) { 108 pw->bv_val = attr[i].bv_val + 7; 109 pw->bv_len = attr[i].bv_len - 7; 110 return; 111 } 112 if (strncasecmp(attr[i].bv_val,"crypt$",6)==0) { 113 pw->bv_val = attr[i].bv_val + 6; 114 pw->bv_len = attr[i].bv_len - 6; 115 return; 116 } 117 } 118 /* just return the first value completely */ 119 *pw = *attr; 120 /* TODO: support more password formats e.g. SMD5 121 (which is $1$ but in a different format) 122 (any code for this is more than welcome) */ 123 } 124 125 /* this writes a single address to the stream */ 126 int write_address(TFILE *fp,struct berval *addr) 127 { 128 int32_t tmpint32; 129 struct in_addr ipv4addr; 130 struct in6_addr ipv6addr; 131 /* try to parse the address as IPv4 first, fall back to IPv6 */ 132 if (inet_pton(AF_INET,addr->bv_val,&ipv4addr)>0) 133 { 134 /* write address type */ 135 WRITE_INT32(fp,AF_INET); 136 /* write the address length */ 137 WRITE_INT32(fp,sizeof(struct in_addr)); 138 /* write the address itself (in network byte order) */ 139 WRITE_TYPE(fp,ipv4addr,struct in_addr); 140 } 141 else if (inet_pton(AF_INET6,addr->bv_val,&ipv6addr)>0) 142 { 143 /* write address type */ 144 WRITE_INT32(fp,AF_INET6); 145 /* write the address length */ 146 WRITE_INT32(fp,sizeof(struct in6_addr)); 147 /* write the address itself (in network byte order) */ 148 WRITE_TYPE(fp,ipv6addr,struct in6_addr); 149 } 150 else 151 { 152 /* failure, log but write simple invalid address 153 (otherwise the address list is messed up) */ 154 /* TODO: have error message in correct format */ 155 Debug(LDAP_DEBUG_ANY,"nssov: unparseable address: %s",addr->bv_val,0,0); 156 /* write an illegal address type */ 157 WRITE_INT32(fp,-1); 158 /* write an empty address */ 159 WRITE_INT32(fp,0); 160 } 161 /* we're done */ 162 return 0; 163 } 164 165 int read_address(TFILE *fp,char *addr,int *addrlen,int *af) 166 { 167 int32_t tmpint32; 168 int len; 169 /* read address family */ 170 READ_INT32(fp,*af); 171 if ((*af!=AF_INET)&&(*af!=AF_INET6)) 172 { 173 Debug(LDAP_DEBUG_ANY,"nssov: incorrect address family specified: %d",*af,0,0); 174 return -1; 175 } 176 /* read address length */ 177 READ_INT32(fp,len); 178 if ((len>*addrlen)||(len<=0)) 179 { 180 Debug(LDAP_DEBUG_ANY,"nssov: address length incorrect: %d",len,0,0); 181 return -1; 182 } 183 *addrlen=len; 184 /* read address */ 185 READ(fp,addr,len); 186 /* we're done */ 187 return 0; 188 } 189 190 int nssov_escape(struct berval *src,struct berval *dst) 191 { 192 size_t pos=0; 193 int i; 194 /* go over all characters in source string */ 195 for (i=0;i<src->bv_len;i++) 196 { 197 /* check if char will fit */ 198 if (pos>=(dst->bv_len-4)) 199 return -1; 200 /* do escaping for some characters */ 201 switch (src->bv_val[i]) 202 { 203 case '*': 204 strcpy(dst->bv_val+pos,"\\2a"); 205 pos+=3; 206 break; 207 case '(': 208 strcpy(dst->bv_val+pos,"\\28"); 209 pos+=3; 210 break; 211 case ')': 212 strcpy(dst->bv_val+pos,"\\29"); 213 pos+=3; 214 break; 215 case '\\': 216 strcpy(dst->bv_val+pos,"\\5c"); 217 pos+=3; 218 break; 219 default: 220 /* just copy character */ 221 dst->bv_val[pos++]=src->bv_val[i]; 222 break; 223 } 224 } 225 /* terminate destination string */ 226 dst->bv_val[pos]='\0'; 227 dst->bv_len = pos; 228 return 0; 229 } 230 231 /* read the version information and action from the stream 232 this function returns the read action in location pointer to by action */ 233 static int read_header(TFILE *fp,int32_t *action) 234 { 235 int32_t tmpint32; 236 /* read the protocol version */ 237 READ_TYPE(fp,tmpint32,int32_t); 238 if (tmpint32 != (int32_t)NSLCD_VERSION) 239 { 240 Debug( LDAP_DEBUG_TRACE,"nssov: wrong nslcd version id (%d)",(int)tmpint32,0,0); 241 return -1; 242 } 243 /* read the request type */ 244 READ(fp,action,sizeof(int32_t)); 245 return 0; 246 } 247 248 /* read a request message, returns <0 in case of errors, 249 this function closes the socket */ 250 static void handleconnection(nssov_info *ni,int sock,Operation *op) 251 { 252 TFILE *fp; 253 int32_t action; 254 struct timeval readtimeout,writetimeout; 255 uid_t uid; 256 gid_t gid; 257 char authid[sizeof("gidNumber=4294967295+uidNumber=424967295,cn=peercred,cn=external,cn=auth")]; 258 259 /* log connection */ 260 if (lutil_getpeereid(sock,&uid,&gid)) 261 Debug( LDAP_DEBUG_TRACE,"nssov: connection from unknown client: %s",strerror(errno),0,0); 262 else 263 Debug( LDAP_DEBUG_TRACE,"nssov: connection from uid=%d gid=%d", 264 (int)uid,(int)gid,0); 265 266 /* Should do authid mapping too */ 267 op->o_dn.bv_len = sprintf(authid,"gidNumber=%d+uidNumber=%d,cn=peercred,cn=external,cn=auth", 268 (int)uid, (int)gid ); 269 op->o_dn.bv_val = authid; 270 op->o_ndn = op->o_dn; 271 272 /* set the timeouts */ 273 readtimeout.tv_sec=0; /* clients should send their request quickly */ 274 readtimeout.tv_usec=500000; 275 writetimeout.tv_sec=5; /* clients could be taking some time to process the results */ 276 writetimeout.tv_usec=0; 277 /* create a stream object */ 278 if ((fp=tio_fdopen(sock,&readtimeout,&writetimeout, 279 READBUFFER_MINSIZE,READBUFFER_MAXSIZE, 280 WRITEBUFFER_MINSIZE,WRITEBUFFER_MAXSIZE))==NULL) 281 { 282 Debug( LDAP_DEBUG_ANY,"nssov: cannot create stream for writing: %s",strerror(errno),0,0); 283 (void)close(sock); 284 return; 285 } 286 /* read request */ 287 if (read_header(fp,&action)) 288 { 289 (void)tio_close(fp); 290 return; 291 } 292 /* handle request */ 293 switch (action) 294 { 295 case NSLCD_ACTION_ALIAS_BYNAME: (void)nssov_alias_byname(ni,fp,op); break; 296 case NSLCD_ACTION_ALIAS_ALL: (void)nssov_alias_all(ni,fp,op); break; 297 case NSLCD_ACTION_ETHER_BYNAME: (void)nssov_ether_byname(ni,fp,op); break; 298 case NSLCD_ACTION_ETHER_BYETHER: (void)nssov_ether_byether(ni,fp,op); break; 299 case NSLCD_ACTION_ETHER_ALL: (void)nssov_ether_all(ni,fp,op); break; 300 case NSLCD_ACTION_GROUP_BYNAME: (void)nssov_group_byname(ni,fp,op); break; 301 case NSLCD_ACTION_GROUP_BYGID: (void)nssov_group_bygid(ni,fp,op); break; 302 case NSLCD_ACTION_GROUP_BYMEMBER: (void)nssov_group_bymember(ni,fp,op); break; 303 case NSLCD_ACTION_GROUP_ALL: (void)nssov_group_all(ni,fp,op); break; 304 case NSLCD_ACTION_HOST_BYNAME: (void)nssov_host_byname(ni,fp,op); break; 305 case NSLCD_ACTION_HOST_BYADDR: (void)nssov_host_byaddr(ni,fp,op); break; 306 case NSLCD_ACTION_HOST_ALL: (void)nssov_host_all(ni,fp,op); break; 307 case NSLCD_ACTION_NETGROUP_BYNAME: (void)nssov_netgroup_byname(ni,fp,op); break; 308 case NSLCD_ACTION_NETWORK_BYNAME: (void)nssov_network_byname(ni,fp,op); break; 309 case NSLCD_ACTION_NETWORK_BYADDR: (void)nssov_network_byaddr(ni,fp,op); break; 310 case NSLCD_ACTION_NETWORK_ALL: (void)nssov_network_all(ni,fp,op); break; 311 case NSLCD_ACTION_PASSWD_BYNAME: (void)nssov_passwd_byname(ni,fp,op); break; 312 case NSLCD_ACTION_PASSWD_BYUID: (void)nssov_passwd_byuid(ni,fp,op); break; 313 case NSLCD_ACTION_PASSWD_ALL: (void)nssov_passwd_all(ni,fp,op); break; 314 case NSLCD_ACTION_PROTOCOL_BYNAME: (void)nssov_protocol_byname(ni,fp,op); break; 315 case NSLCD_ACTION_PROTOCOL_BYNUMBER:(void)nssov_protocol_bynumber(ni,fp,op); break; 316 case NSLCD_ACTION_PROTOCOL_ALL: (void)nssov_protocol_all(ni,fp,op); break; 317 case NSLCD_ACTION_RPC_BYNAME: (void)nssov_rpc_byname(ni,fp,op); break; 318 case NSLCD_ACTION_RPC_BYNUMBER: (void)nssov_rpc_bynumber(ni,fp,op); break; 319 case NSLCD_ACTION_RPC_ALL: (void)nssov_rpc_all(ni,fp,op); break; 320 case NSLCD_ACTION_SERVICE_BYNAME: (void)nssov_service_byname(ni,fp,op); break; 321 case NSLCD_ACTION_SERVICE_BYNUMBER: (void)nssov_service_bynumber(ni,fp,op); break; 322 case NSLCD_ACTION_SERVICE_ALL: (void)nssov_service_all(ni,fp,op); break; 323 case NSLCD_ACTION_SHADOW_BYNAME: if (uid==0) (void)nssov_shadow_byname(ni,fp,op); break; 324 case NSLCD_ACTION_SHADOW_ALL: if (uid==0) (void)nssov_shadow_all(ni,fp,op); break; 325 default: 326 Debug( LDAP_DEBUG_ANY,"nssov: invalid request id: %d",(int)action,0,0); 327 break; 328 } 329 /* we're done with the request */ 330 (void)tio_close(fp); 331 return; 332 } 333 334 /* accept a connection on the socket */ 335 static void *acceptconn(void *ctx, void *arg) 336 { 337 nssov_info *ni = arg; 338 Connection conn = {0}; 339 OperationBuffer opbuf; 340 Operation *op; 341 int csock; 342 343 if ( slapd_shutdown ) 344 return NULL; 345 346 { 347 struct sockaddr_storage addr; 348 socklen_t alen; 349 int j; 350 351 /* accept a new connection */ 352 alen=(socklen_t)sizeof(struct sockaddr_storage); 353 csock=accept(ni->ni_socket,(struct sockaddr *)&addr,&alen); 354 connection_client_enable(ni->ni_conn); 355 if (csock<0) 356 { 357 if ((errno==EINTR)||(errno==EAGAIN)||(errno==EWOULDBLOCK)) 358 { 359 Debug( LDAP_DEBUG_TRACE,"nssov: accept() failed (ignored): %s",strerror(errno),0,0); 360 return; 361 } 362 Debug( LDAP_DEBUG_ANY,"nssov: accept() failed: %s",strerror(errno),0,0); 363 return; 364 } 365 /* make sure O_NONBLOCK is not inherited */ 366 if ((j=fcntl(csock,F_GETFL,0))<0) 367 { 368 Debug( LDAP_DEBUG_ANY,"nssov: fcntl(F_GETFL) failed: %s",strerror(errno),0,0); 369 if (close(csock)) 370 Debug( LDAP_DEBUG_ANY,"nssov: problem closing socket: %s",strerror(errno),0,0); 371 return; 372 } 373 if (fcntl(csock,F_SETFL,j&~O_NONBLOCK)<0) 374 { 375 Debug( LDAP_DEBUG_ANY,"nssov: fcntl(F_SETFL,~O_NONBLOCK) failed: %s",strerror(errno),0,0); 376 if (close(csock)) 377 Debug( LDAP_DEBUG_ANY,"nssov: problem closing socket: %s",strerror(errno),0,0); 378 return; 379 } 380 } 381 connection_fake_init( &conn, &opbuf, ctx ); 382 op=&opbuf.ob_op; 383 op->o_bd = ni->ni_db; 384 op->o_tag = LDAP_REQ_SEARCH; 385 386 /* handle the connection */ 387 handleconnection(ni,csock,op); 388 } 389 390 static slap_verbmasks nss_svcs[] = { 391 { BER_BVC("alias"), NM_alias }, 392 { BER_BVC("ether"), NM_ether }, 393 { BER_BVC("group"), NM_group }, 394 { BER_BVC("host"), NM_host }, 395 { BER_BVC("netgroup"), NM_netgroup }, 396 { BER_BVC("network"), NM_network }, 397 { BER_BVC("passwd"), NM_passwd }, 398 { BER_BVC("protocol"), NM_protocol }, 399 { BER_BVC("rpc"), NM_rpc }, 400 { BER_BVC("service"), NM_service }, 401 { BER_BVC("shadow"), NM_shadow }, 402 { BER_BVNULL, 0 } 403 }; 404 405 enum { 406 NSS_SSD=1, 407 NSS_MAP 408 }; 409 410 static ConfigDriver nss_cf_gen; 411 412 static ConfigTable nsscfg[] = { 413 { "nssov-ssd", "service> <url", 3, 3, 0, ARG_MAGIC|NSS_SSD, 414 nss_cf_gen, "(OLcfgCtAt:3.1 NAME 'olcNssSsd' " 415 "DESC 'URL for searches in a given service' " 416 "EQUALITY caseIgnoreMatch " 417 "SYNTAX OMsDirectoryString )", NULL, NULL }, 418 { "nssov-map", "service> <orig> <new", 4, 4, 0, ARG_MAGIC|NSS_MAP, 419 nss_cf_gen, "(OLcfgCtAt:3.2 NAME 'olcNssMap' " 420 "DESC 'Map <service> lookups of <orig> attr to <new> attr' " 421 "EQUALITY caseIgnoreMatch " 422 "SYNTAX OMsDirectoryString )", NULL, NULL }, 423 { NULL, NULL, 0,0,0, ARG_IGNORED } 424 }; 425 426 static ConfigOCs nssocs[] = { 427 { "( OLcfgCtOc:3.1 " 428 "NAME 'olcNssOvConfig' " 429 "DESC 'NSS lookup configuration' " 430 "SUP olcOverlayConfig " 431 "MAY ( olcNssSsd $ olcNssMap ) )", 432 Cft_Overlay, nsscfg }, 433 { NULL, 0, NULL } 434 }; 435 436 static int 437 nss_cf_gen(ConfigArgs *c) 438 { 439 slap_overinst *on = (slap_overinst *)c->bi; 440 nssov_info *ni = on->on_bi.bi_private; 441 nssov_mapinfo *mi; 442 int i, j, rc = 0; 443 444 if ( c->op == SLAP_CONFIG_EMIT ) { 445 switch(c->type) { 446 case NSS_SSD: 447 rc = 1; 448 for (i=NM_alias;i<NM_NONE;i++) { 449 struct berval scope; 450 struct berval ssd; 451 struct berval base; 452 453 mi = &ni->ni_maps[i]; 454 455 /* ignore all-default services */ 456 if ( mi->mi_scope == LDAP_SCOPE_DEFAULT && 457 bvmatch( &mi->mi_filter, &mi->mi_filter0 ) && 458 BER_BVISNULL( &mi->mi_base )) 459 continue; 460 461 if ( BER_BVISNULL( &mi->mi_base )) 462 base = ni->ni_db->be_nsuffix[0]; 463 else 464 base = mi->mi_base; 465 ldap_pvt_scope2bv(mi->mi_scope == LDAP_SCOPE_DEFAULT ? 466 LDAP_SCOPE_SUBTREE : mi->mi_scope, &scope); 467 ssd.bv_len = STRLENOF(" ldap:///???") + nss_svcs[i].word.bv_len + 468 base.bv_len + scope.bv_len + mi->mi_filter.bv_len; 469 ssd.bv_val = ch_malloc( ssd.bv_len + 1 ); 470 sprintf(ssd.bv_val, "%s ldap:///%s??%s?%s", nss_svcs[i].word.bv_val, 471 base.bv_val, scope.bv_val, mi->mi_filter.bv_val ); 472 ber_bvarray_add( &c->rvalue_vals, &ssd ); 473 rc = 0; 474 } 475 break; 476 case NSS_MAP: 477 rc = 1; 478 for (i=NM_alias;i<NM_NONE;i++) { 479 int j; 480 481 mi = &ni->ni_maps[i]; 482 for (j=0;!BER_BVISNULL(&mi->mi_attrkeys[j]);j++) { 483 if ( ber_bvstrcasecmp(&mi->mi_attrkeys[j], 484 &mi->mi_attrs[j].an_name)) { 485 struct berval map; 486 487 map.bv_len = nss_svcs[i].word.bv_len + 488 mi->mi_attrkeys[j].bv_len + 489 mi->mi_attrs->an_desc->ad_cname.bv_len + 2; 490 map.bv_val = ch_malloc(map.bv_len + 1); 491 sprintf(map.bv_val, "%s %s %s", nss_svcs[i].word.bv_val, 492 mi->mi_attrkeys[j].bv_val, mi->mi_attrs->an_desc->ad_cname.bv_val ); 493 ber_bvarray_add( &c->rvalue_vals, &map ); 494 rc = 0; 495 } 496 } 497 } 498 break; 499 } 500 return rc; 501 } else if ( c->op == LDAP_MOD_DELETE ) { 502 return 1; 503 } 504 switch( c->type ) { 505 case NSS_SSD: { 506 LDAPURLDesc *lud; 507 508 i = verb_to_mask(c->argv[1], nss_svcs); 509 if ( i == NM_NONE ) 510 return 1; 511 512 mi = &ni->ni_maps[i]; 513 rc = ldap_url_parse(c->argv[2], &lud); 514 if ( rc ) 515 return 1; 516 do { 517 struct berval base; 518 /* Must be LDAP scheme */ 519 if (strcasecmp(lud->lud_scheme,"ldap")) { 520 rc = 1; 521 break; 522 } 523 /* Host part, attrs, and extensions must be empty */ 524 if (( lud->lud_host && *lud->lud_host ) || 525 lud->lud_attrs || lud->lud_exts ) { 526 rc = 1; 527 break; 528 } 529 ber_str2bv( lud->lud_dn,0,0,&base); 530 rc = dnNormalize( 0,NULL,NULL,&base,&mi->mi_base,NULL); 531 if ( rc ) 532 break; 533 if ( lud->lud_filter ) { 534 /* steal this */ 535 ber_str2bv( lud->lud_filter,0,0,&mi->mi_filter); 536 lud->lud_filter = NULL; 537 } 538 mi->mi_scope = lud->lud_scope; 539 } while(0); 540 ldap_free_urldesc( lud ); 541 } 542 break; 543 case NSS_MAP: 544 i = verb_to_mask(c->argv[1], nss_svcs); 545 if ( i == NM_NONE ) 546 return 1; 547 rc = 1; 548 mi = &ni->ni_maps[i]; 549 for (j=0; !BER_BVISNULL(&mi->mi_attrkeys[j]); j++) { 550 if (!strcasecmp(c->argv[2],mi->mi_attrkeys[j].bv_val)) { 551 AttributeDescription *ad = NULL; 552 const char *text; 553 rc = slap_str2ad( c->argv[3], &ad, &text); 554 if ( rc == 0 ) { 555 mi->mi_attrs[j].an_desc = ad; 556 mi->mi_attrs[j].an_name = ad->ad_cname; 557 } 558 break; 559 } 560 } 561 break; 562 } 563 return rc; 564 } 565 566 static int 567 nssov_db_init( 568 BackendDB *be, 569 ConfigReply *cr ) 570 { 571 slap_overinst *on = (slap_overinst *)be->bd_info; 572 nssov_info *ni; 573 nssov_mapinfo *mi; 574 int i, j; 575 576 ni = ch_malloc( sizeof(nssov_info) ); 577 on->on_bi.bi_private = ni; 578 579 /* set up map keys */ 580 nssov_alias_init(ni); 581 nssov_ether_init(ni); 582 nssov_group_init(ni); 583 nssov_host_init(ni); 584 nssov_netgroup_init(ni); 585 nssov_network_init(ni); 586 nssov_passwd_init(ni); 587 nssov_protocol_init(ni); 588 nssov_rpc_init(ni); 589 nssov_service_init(ni); 590 nssov_shadow_init(ni); 591 592 ni->ni_db = be->bd_self; 593 594 return 0; 595 } 596 597 static int 598 nssov_db_destroy( 599 BackendDB *be, 600 ConfigReply *cr ) 601 { 602 } 603 604 static int 605 nssov_db_open( 606 BackendDB *be, 607 ConfigReply *cr ) 608 { 609 slap_overinst *on = (slap_overinst *)be->bd_info; 610 nssov_info *ni = on->on_bi.bi_private; 611 nssov_mapinfo *mi; 612 613 int i, sock; 614 struct sockaddr_un addr; 615 616 /* Set default bases */ 617 for (i=0; i<NM_NONE; i++) { 618 if ( BER_BVISNULL( &ni->ni_maps[i].mi_base )) { 619 ber_dupbv( &ni->ni_maps[i].mi_base, &be->be_nsuffix[0] ); 620 } 621 if ( ni->ni_maps[i].mi_scope == LDAP_SCOPE_DEFAULT ) 622 ni->ni_maps[i].mi_scope = LDAP_SCOPE_SUBTREE; 623 } 624 /* validate attribute maps */ 625 mi = ni->ni_maps; 626 for ( i=0; i<NM_NONE; i++,mi++) { 627 const char *text; 628 int j; 629 for (j=0; !BER_BVISNULL(&mi->mi_attrkeys[j]); j++) { 630 /* skip attrs we already validated */ 631 if ( mi->mi_attrs[j].an_desc ) continue; 632 if ( slap_bv2ad( &mi->mi_attrs[j].an_name, 633 &mi->mi_attrs[j].an_desc, &text )) { 634 Debug(LDAP_DEBUG_ANY,"nssov: invalid attr \"%s\": %s\n", 635 mi->mi_attrs[j].an_name.bv_val, text, 0 ); 636 return -1; 637 } 638 } 639 BER_BVZERO(&mi->mi_attrs[j].an_name); 640 mi->mi_attrs[j].an_desc = NULL; 641 } 642 643 if ( slapMode & SLAP_SERVER_MODE ) { 644 /* create a socket */ 645 if ( (sock=socket(PF_UNIX,SOCK_STREAM,0))<0 ) 646 { 647 Debug(LDAP_DEBUG_ANY,"nssov: cannot create socket: %s",strerror(errno),0,0); 648 return -1; 649 } 650 /* remove existing named socket */ 651 if (unlink(NSLCD_SOCKET)<0) 652 { 653 Debug( LDAP_DEBUG_TRACE,"nssov: unlink() of "NSLCD_SOCKET" failed (ignored): %s", 654 strerror(errno),0,0); 655 } 656 /* create socket address structure */ 657 memset(&addr,0,sizeof(struct sockaddr_un)); 658 addr.sun_family=AF_UNIX; 659 strncpy(addr.sun_path,NSLCD_SOCKET,sizeof(addr.sun_path)); 660 addr.sun_path[sizeof(addr.sun_path)-1]='\0'; 661 /* bind to the named socket */ 662 if (bind(sock,(struct sockaddr *)&addr,sizeof(struct sockaddr_un))) 663 { 664 Debug( LDAP_DEBUG_ANY,"nssov: bind() to "NSLCD_SOCKET" failed: %s", 665 strerror(errno),0,0); 666 if (close(sock)) 667 Debug( LDAP_DEBUG_ANY,"nssov: problem closing socket: %s",strerror(errno),0,0); 668 return -1; 669 } 670 /* close the file descriptor on exit */ 671 if (fcntl(sock,F_SETFD,FD_CLOEXEC)<0) 672 { 673 Debug( LDAP_DEBUG_ANY,"nssov: fcntl(F_SETFL,O_NONBLOCK) failed: %s",strerror(errno),0,0); 674 if (close(sock)) 675 Debug( LDAP_DEBUG_ANY,"nssov: problem closing socket: %s",strerror(errno),0,0); 676 return -1; 677 } 678 /* set permissions of socket so anybody can do requests */ 679 /* Note: we use chmod() here instead of fchmod() because 680 fchmod does not work on sockets 681 http://www.opengroup.org/onlinepubs/009695399/functions/fchmod.html 682 http://lkml.org/lkml/2005/5/16/11 */ 683 if (chmod(NSLCD_SOCKET,(mode_t)0666)) 684 { 685 Debug( LDAP_DEBUG_ANY,"nssov: chmod(0666) failed: %s",strerror(errno),0,0); 686 if (close(sock)) 687 Debug( LDAP_DEBUG_ANY,"nssov: problem closing socket: %s",strerror(errno),0,0); 688 return -1; 689 } 690 /* start listening for connections */ 691 if (listen(sock,SOMAXCONN)<0) 692 { 693 Debug( LDAP_DEBUG_ANY,"nssov: listen() failed: %s",strerror(errno),0,0); 694 if (close(sock)) 695 Debug( LDAP_DEBUG_ANY,"nssov: problem closing socket: %s",strerror(errno),0,0); 696 return -1; 697 } 698 ni->ni_socket = sock; 699 ni->ni_conn = connection_client_setup( sock, acceptconn, ni ); 700 } 701 702 return 0; 703 } 704 705 static int 706 nssov_db_close( 707 BackendDB *be, 708 ConfigReply *cr ) 709 { 710 slap_overinst *on = (slap_overinst *)be->bd_info; 711 nssov_info *ni = on->on_bi.bi_private; 712 713 /* close socket if it's still in use */ 714 if (ni->ni_socket >= 0); 715 { 716 if (close(ni->ni_socket)) 717 Debug( LDAP_DEBUG_ANY,"problem closing server socket (ignored): %s",strerror(errno),0,0); 718 ni->ni_socket = -1; 719 } 720 /* remove existing named socket */ 721 if (unlink(NSLCD_SOCKET)<0) 722 { 723 Debug( LDAP_DEBUG_TRACE,"unlink() of "NSLCD_SOCKET" failed (ignored): %s", 724 strerror(errno),0,0); 725 } 726 } 727 728 static slap_overinst nssov; 729 730 int 731 nssov_initialize( void ) 732 { 733 int rc; 734 735 nssov.on_bi.bi_type = "nssov"; 736 nssov.on_bi.bi_db_init = nssov_db_init; 737 nssov.on_bi.bi_db_destroy = nssov_db_destroy; 738 nssov.on_bi.bi_db_open = nssov_db_open; 739 nssov.on_bi.bi_db_close = nssov_db_close; 740 741 nssov.on_bi.bi_cf_ocs = nssocs; 742 743 rc = config_register_schema( nsscfg, nssocs ); 744 if ( rc ) return rc; 745 746 return overlay_register(&nssov); 747 } 748 749 #if SLAPD_OVER_NSSOV == SLAPD_MOD_DYNAMIC 750 int 751 init_module( int argc, char *argv[] ) 752 { 753 return nssov_initialize(); 754 } 755 #endif 756