/* * * cache.c * * NIS map cache maintance code * * Author: Landon Fuller * * Copyright (c) 2000-2001 InfoSpace, Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by InfoSpace, Inc. * and its contributors. * 4. Neither the name of InfoSpace, Inc nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #include "../../../autoconf.h" #include #include #ifdef HAVE_STRINGS_H #include #else #include #endif #include #include #include #include #include #include "yp.h" #include "ldap.h" #include "cache.h" extern struct ldaprefs ldaprefs; static char *user_attributes [] = { "uid", "userpassword", "uidnumber", "gidnumber", "gecos", "homedirectory", "loginshell", NULL }; static char *group_attributes [] = { "cn", "userpassword", "gidnumber", "memberuid", NULL }; static char *nis_attributes [] = { "cn", "nismapentry", "nismapname", NULL }; static char *fix_password(char **values) { char **valptr; char *pwd = NULL; char *buffer; for (valptr = values; *valptr != NULL; valptr++) { if(!strncasecmp(*valptr, CRYPT, CRYPT_SIZE)) { pwd = *valptr; break; } } if (pwd == NULL) { pwd = "x"; } else { pwd += CRYPT_SIZE; } buffer = safe_strdup(pwd); return(buffer); } static void fill_pwinfo(struct pwinfo *pwinfo) { pwinfo->uid = NULL; pwinfo->userpassword = NULL; pwinfo->uidnumber = NULL; pwinfo->gidnumber = NULL; pwinfo->gecos = NULL; pwinfo->homedirectory = NULL; pwinfo->loginshell = NULL; pwinfo->size = 0; } static void fill_gwinfo(struct gwinfo *gwinfo) { gwinfo->cn = NULL; gwinfo->userpassword = NULL; gwinfo->gidnumber = NULL; gwinfo->memberuid = NULL; gwinfo->size = 0; } static void fill_nisinfo(struct nisinfo *nisinfo) { nisinfo->cn = NULL; nisinfo->nismapentry = NULL; nisinfo->nismapname = NULL; } static int check_pwinfo(struct pwinfo *pwinfo) { if (!pwinfo->uid) { return (YP_YPERR); } if (!pwinfo->userpassword) { return (YP_YPERR); } if (!pwinfo->uidnumber) { return (YP_YPERR); } if (!pwinfo->gidnumber) { return (YP_YPERR); } if (!pwinfo->gecos) { pwinfo->gecos = safe_strdup(""); } if (!pwinfo->homedirectory) { return (YP_YPERR); } if (!pwinfo->loginshell) { return (YP_YPERR); } return (YP_TRUE); } static int check_gwinfo(struct gwinfo *gwinfo) { if (!gwinfo->cn) { return (YP_YPERR); } if (!gwinfo->userpassword) { return (YP_YPERR); } if (!gwinfo->gidnumber) { return (YP_YPERR); } if (!gwinfo->memberuid) { gwinfo->memberuid = safe_strdup(""); } return (YP_TRUE); } static int check_nisinfo(struct nisinfo *nisinfo) { if (!nisinfo->cn) { return (YP_YPERR); } if (!nisinfo->nismapentry) { return (YP_YPERR); } if (!nisinfo->nismapname) { return (YP_YPERR); } return (YP_TRUE); } static void clean_pwinfo(struct pwinfo *pwinfo) { if(pwinfo->uid) free(pwinfo->uid); if(pwinfo->userpassword) free(pwinfo->userpassword); if(pwinfo->uidnumber) free(pwinfo->uidnumber); if(pwinfo->gidnumber) free(pwinfo->gidnumber); if(pwinfo->gecos) free(pwinfo->gecos); if(pwinfo->homedirectory) free(pwinfo->homedirectory); if(pwinfo->loginshell) free(pwinfo->loginshell); free(pwinfo); } static void clean_gwinfo(struct gwinfo *gwinfo) { if (gwinfo->cn) free(gwinfo->cn); if (gwinfo->userpassword) free(gwinfo->userpassword); if (gwinfo->gidnumber) free(gwinfo->gidnumber); if (gwinfo->memberuid) free(gwinfo->memberuid); free(gwinfo); } static void clean_nisinfo(struct nisinfo *nisinfo) { if(nisinfo->cn) free(nisinfo->cn); if(nisinfo->nismapentry) free(nisinfo->nismapentry); if(nisinfo->nismapname) free(nisinfo->nismapname); free(nisinfo); } int assemble_passwd(valdat *val, LDAPMessage *user, struct pwinfo *pwinfo) { ypstat rval; char *attr; BerElement *ber = NULL; rval = YP_YPERR; fill_pwinfo(pwinfo); for (attr = ldap_first_attribute (ldaprefs.ldap, user, &ber); attr; attr = ldap_next_attribute (ldaprefs.ldap, user, ber)) { char **values; values = ldap_get_values (ldaprefs.ldap, user, attr); if (values) { if(!strcasecmp(attr, "uid")) { pwinfo->uid = safe_strdup(values[0]); pwinfo->size += strlen(values[0]); } else if(!strcasecmp(attr, "userpassword")) { pwinfo->userpassword = safe_strdup("*"); pwinfo->size += strlen("*"); } else if(!strcasecmp(attr, "uidnumber")) { pwinfo->uidnumber = safe_strdup(values[0]); pwinfo->size += strlen(values[0]); } else if(!strcasecmp(attr, "gidnumber")) { pwinfo->gidnumber = safe_strdup(values[0]); pwinfo->size += strlen(values[0]); } else if(!strcasecmp(attr, "gecos")) { pwinfo->gecos = safe_strdup(values[0]); pwinfo->size += strlen(values[0]); } else if(!strcasecmp(attr, "homedirectory")) { pwinfo->homedirectory = safe_strdup(values[0]); pwinfo->size += strlen(values[0]); } else if(!strcasecmp(attr, "loginshell")) { pwinfo->loginshell = safe_strdup(values[0]); pwinfo->size += strlen(values[0]); } ldap_value_free(values); } } if (check_pwinfo(pwinfo) == YP_TRUE) { val->valdat_len = pwinfo->size + PWLINE_SIZE; val->valdat_val = safe_malloc(val->valdat_len + 1); sprintf(val->valdat_val, PWLINE, pwinfo->uid, pwinfo->userpassword, pwinfo->uidnumber, pwinfo->gidnumber, pwinfo->gecos, pwinfo->homedirectory, pwinfo->loginshell); rval = YP_TRUE; } else { rval = YP_NOKEY; } return (rval); } int assemble_master_passwd(valdat *val, LDAPMessage *user, struct pwinfo *pwinfo) { ypstat rval; char *attr; BerElement *ber = NULL; rval = YP_YPERR; fill_pwinfo(pwinfo); for (attr = ldap_first_attribute (ldaprefs.ldap, user, &ber); attr; attr = ldap_next_attribute (ldaprefs.ldap, user, ber)) { char **values; values = ldap_get_values (ldaprefs.ldap, user, attr); if (values) { if(!strcasecmp(attr, "uid")) { pwinfo->uid = safe_strdup(values[0]); pwinfo->size += strlen(values[0]); } else if(!strcasecmp(attr, "userpassword")) { pwinfo->userpassword = fix_password(values); pwinfo->size += strlen(pwinfo->userpassword); } else if(!strcasecmp(attr, "uidnumber")) { pwinfo->uidnumber = safe_strdup(values[0]); pwinfo->size += strlen(values[0]); } else if(!strcasecmp(attr, "gidnumber")) { pwinfo->gidnumber = safe_strdup(values[0]); pwinfo->size += strlen(values[0]); } else if(!strcasecmp(attr, "gecos")) { pwinfo->gecos = safe_strdup(values[0]); pwinfo->size += strlen(values[0]); } else if(!strcasecmp(attr, "homedirectory")) { pwinfo->homedirectory = safe_strdup(values[0]); pwinfo->size += strlen(values[0]); } else if(!strcasecmp(attr, "loginshell")) { pwinfo->loginshell = safe_strdup(values[0]); pwinfo->size += strlen(values[0]); } ldap_value_free(values); } } if (check_pwinfo(pwinfo) == YP_TRUE) { val->valdat_len = pwinfo->size + MPWLINE_SIZE; val->valdat_val = safe_malloc(val->valdat_len + 1); sprintf(val->valdat_val, MPWLINE, pwinfo->uid, pwinfo->userpassword, pwinfo->uidnumber, pwinfo->gidnumber, pwinfo->gecos, pwinfo->homedirectory, pwinfo->loginshell); rval = YP_TRUE; } else { rval = YP_NOKEY; } return (rval); } int assemble_group(valdat *val, LDAPMessage *group, struct gwinfo *gwinfo) { ypstat rval; char *attr; BerElement *ber = NULL; rval = YP_YPERR; fill_gwinfo(gwinfo); for (attr = ldap_first_attribute (ldaprefs.ldap, group, &ber); attr; attr = ldap_next_attribute (ldaprefs.ldap, group, ber)) { char **values; values = ldap_get_values (ldaprefs.ldap, group, attr); if (values) { if(!strcasecmp(attr, "cn")) { gwinfo->cn = safe_strdup(values[0]); gwinfo->size += strlen(values[0]); } else if(!strcasecmp(attr, "userpassword")) { gwinfo->userpassword = fix_password(values); gwinfo->size += strlen(gwinfo->userpassword); } else if(!strcasecmp(attr, "gidnumber")) { gwinfo->gidnumber = safe_strdup(values[0]); gwinfo->size += strlen(values[0]); } else if(!strcasecmp(attr, "memberUid")) { gwinfo->memberuid = safe_strdup(values[0]); gwinfo->size += strlen(values[0]); } ldap_value_free(values); } } if (check_gwinfo(gwinfo) == YP_TRUE) { val->valdat_len = gwinfo->size + GWLINE_SIZE; val->valdat_val = safe_malloc(val->valdat_len + 1); sprintf(val->valdat_val, GWLINE, gwinfo->cn, gwinfo->userpassword, gwinfo->gidnumber, gwinfo->memberuid); rval = YP_TRUE; } else { rval = YP_NOKEY; } return (rval); } int assemble_nis(valdat *val, LDAPMessage *record, struct nisinfo *nisinfo) { ypstat rval; char *attr; BerElement *ber = NULL; rval = YP_YPERR; fill_nisinfo(nisinfo); for (attr = ldap_first_attribute (ldaprefs.ldap, record, &ber); attr; attr = ldap_next_attribute (ldaprefs.ldap, record, ber)) { char **values; values = ldap_get_values (ldaprefs.ldap, record, attr); if (values) { if(!strcasecmp(attr, "cn")) { nisinfo->cn = safe_strdup(values[0]); } else if(!strcasecmp(attr, "nismapentry")) { nisinfo->nismapentry = safe_strdup(values[0]); } else if(!strcasecmp(attr, "nismapname")) { nisinfo->nismapname = safe_strdup(values[0]); } ldap_value_free(values); } } if (check_nisinfo(nisinfo) == YP_TRUE) { val->valdat_len = strlen(nisinfo->nismapentry); val->valdat_val = safe_strdup(nisinfo->nismapentry); rval = YP_TRUE; } else { rval = YP_NOKEY; } return (rval); } ypstat check_unique(struct mapcache *mapcache, char *key) { struct mapentry *mapentry_current; ypstat rval; rval = YP_YPERR; if(mapcache != NULL) { mapentry_current = mapcache->mapentry; for(mapentry_current = mapcache->mapentry; mapentry_current; mapentry_current = mapentry_current->next) { if (!strcmp(mapentry_current->key, key)) { return (YP_TRUE); } } rval = YP_NOKEY; } return (rval); } struct mapcache *create_cache (ypmaplist *maps) { LDAPMessage *ldapreturn, *record; struct ypmaplist *maplist_current; struct mapentry *mapentry_current; struct mapcache *mapcache_current, *mapcache_head; struct pwinfo *pwinfo; struct gwinfo *gwinfo; struct nisinfo *nisinfo; char *base, *filter; valdat *val; int rval; (void *) mapcache_current = (void *) mapcache_head = (void *) ldapreturn = (void *) record = NULL; val = safe_malloc(sizeof(valdat)); for(maplist_current = maps; maplist_current; maplist_current = maplist_current->next) { mapcache_current = safe_malloc(sizeof(struct mapcache)); mapcache_current->map = (mapname *) safe_strdup(maplist_current->map); mapcache_current->mapentry = NULL; mapcache_current->sem = safe_malloc(sizeof(sem_t)); sem_init(mapcache_current->sem, 0, 1); printf("Building cache for: %s\n", maplist_current->map); if (!strcmp((char *) mapcache_current->map, "passwd.byname")) { /* XXX Add preferences for filter and basedn */ base = safe_malloc(strlen(ldaprefs.basedn) + strlen("ou=People,") + 1); sprintf(base, "%s%s", "ou=People,", ldaprefs.basedn); filter = safe_strdup("(objectClass=posixAccount)"); if(ldap_search_s(ldaprefs.ldap, base, LDAP_SCOPE_ONELEVEL, filter, user_attributes, 0, &ldapreturn) != -1) { for (record = ldap_first_entry(ldaprefs.ldap, ldapreturn); record; record = ldap_next_entry(ldaprefs.ldap, record)) { pwinfo = safe_malloc(sizeof(struct pwinfo)); rval = assemble_passwd(val, record, pwinfo); if(rval == YP_TRUE); { if(check_unique(mapcache_current, pwinfo->uid) == YP_NOKEY) { mapentry_current = safe_malloc(sizeof(struct mapentry)); mapentry_current->key = safe_strdup(pwinfo->uid); mapentry_current->val = val->valdat_val; mapentry_current->next = mapcache_current->mapentry; mapcache_current->mapentry = mapentry_current; } } clean_pwinfo(pwinfo); } } ldap_msgfree(ldapreturn); free(filter); free(base); } else if (!strcmp((char *) mapcache_current->map, "passwd.byuid")) { /* XXX Add preferences for filter and basedn */ base = safe_malloc(strlen(ldaprefs.basedn) + strlen("ou=People,") + 1); sprintf(base, "%s%s", "ou=People,", ldaprefs.basedn); filter = safe_strdup("(objectClass=posixAccount)"); if(ldap_search_s(ldaprefs.ldap, base, LDAP_SCOPE_ONELEVEL, filter, user_attributes, 0, &ldapreturn) != -1) { for (record = ldap_first_entry(ldaprefs.ldap, ldapreturn); record; record = ldap_next_entry(ldaprefs.ldap, record)) { pwinfo = safe_malloc(sizeof(struct pwinfo)); rval = assemble_passwd(val, record, pwinfo); if(rval == YP_TRUE); { if(check_unique(mapcache_current, pwinfo->uidnumber) == YP_NOKEY) { mapentry_current = safe_malloc(sizeof(struct mapentry)); mapentry_current->key = safe_strdup(pwinfo->uidnumber); mapentry_current->val = val->valdat_val; mapentry_current->next = mapcache_current->mapentry; mapcache_current->mapentry = mapentry_current; } } clean_pwinfo(pwinfo); } } ldap_msgfree(ldapreturn); free(filter); free(base); } else if (!strcmp((char *) mapcache_current->map, "group.byname")) { /* XXX Add preferences for filter and basedn */ base = safe_malloc(strlen(ldaprefs.basedn) + strlen("ou=Group,") + 1); sprintf(base, "%s%s", "ou=Group,", ldaprefs.basedn); filter = safe_strdup("(objectClass=posixGroup)"); if(ldap_search_s(ldaprefs.ldap, base, LDAP_SCOPE_ONELEVEL, filter, group_attributes, 0, &ldapreturn) != -1) { for (record = ldap_first_entry(ldaprefs.ldap, ldapreturn); record; record = ldap_next_entry(ldaprefs.ldap, record)) { gwinfo = safe_malloc(sizeof(struct gwinfo)); rval = assemble_group(val, record, gwinfo); if(rval == YP_TRUE); { if(check_unique(mapcache_current, gwinfo->cn) == YP_NOKEY) { mapentry_current = safe_malloc(sizeof(struct mapentry)); mapentry_current->key = safe_strdup(gwinfo->cn); mapentry_current->val = val->valdat_val; mapentry_current->next = mapcache_current->mapentry; mapcache_current->mapentry = mapentry_current; } } clean_gwinfo(gwinfo); } } ldap_msgfree(ldapreturn); free(filter); free(base); } else if (!strcmp((char *) mapcache_current->map, "group.bygid")) { /* XXX Add preferences for filter and basedn */ base = safe_malloc(strlen(ldaprefs.basedn) + strlen("ou=Group,") + 1); sprintf(base, "%s%s", "ou=Group,", ldaprefs.basedn); filter = safe_strdup("(objectClass=posixGroup)"); if(ldap_search_s(ldaprefs.ldap, base, LDAP_SCOPE_ONELEVEL, filter, group_attributes, 0, &ldapreturn) != -1) { for (record = ldap_first_entry(ldaprefs.ldap, ldapreturn); record; record = ldap_next_entry(ldaprefs.ldap, record)) { gwinfo = safe_malloc(sizeof(struct gwinfo)); rval = assemble_group(val, record, gwinfo); if(rval == YP_TRUE); { if(check_unique(mapcache_current, gwinfo->cn) == YP_NOKEY) { mapentry_current = safe_malloc(sizeof(struct mapentry)); mapentry_current->key = safe_strdup(gwinfo->gidnumber); mapentry_current->val = val->valdat_val; mapentry_current->next = mapcache_current->mapentry; mapcache_current->mapentry = mapentry_current; } } clean_gwinfo(gwinfo); } } ldap_msgfree(ldapreturn); free(filter); free(base); } else { /* XXX Add preferences for filter and basedn */ base = safe_malloc(strlen(ldaprefs.basedn) + strlen("ou=NisMapName,") + strlen((char *) mapcache_current->map) + 1); sprintf(base, "nisMapName=%s,%s", (char *) mapcache_current->map, ldaprefs.basedn); filter = safe_strdup("(objectClass=nisObject)"); if(ldap_search_s(ldaprefs.ldap, base, LDAP_SCOPE_ONELEVEL, filter, nis_attributes, 0, &ldapreturn) != -1) { for (record = ldap_first_entry(ldaprefs.ldap, ldapreturn); record; record = ldap_next_entry(ldaprefs.ldap, record)) { nisinfo = safe_malloc(sizeof(struct nisinfo)); rval = assemble_nis(val, record, nisinfo); if(rval == YP_TRUE); { if(check_unique(mapcache_current, nisinfo->cn) == YP_NOKEY) { mapentry_current = safe_malloc(sizeof(struct mapentry)); mapentry_current->key = safe_strdup(nisinfo->cn); mapentry_current->val = val->valdat_val; mapentry_current->next = mapcache_current->mapentry; mapcache_current->mapentry = mapentry_current; } } clean_nisinfo(nisinfo); } } ldap_msgfree(ldapreturn); free(filter); free(base); } mapcache_current->time = time(NULL); mapcache_current->next = mapcache_head; mapcache_head = mapcache_current; } return (mapcache_head); } void maintain_cache (void) { } static struct mapcache *getcache(mapname *map) { struct mapcache *mapcache_current; mapcache_current = ldaprefs.mapcache; while(mapcache_current) { if (!strcmp((char *)mapcache_current->map, (char *)map)) { return (mapcache_current); } mapcache_current = mapcache_current->next; } return (NULL); } ypstat yp_get_record(keydat *key, mapname *map, valdat *val) { struct mapcache *mapcache_current; struct mapentry *mapentry_current; ypstat rval; char *tempkey; tempkey = safe_malloc(key->keydat_len + 1); bcopy(key->keydat_val, tempkey, key->keydat_len); tempkey[key->keydat_len] = '\0'; rval = YP_YPERR; mapcache_current = getcache(map); if(mapcache_current != NULL) { if (!strcmp((char *)mapcache_current->map, (char *) map)) { if(mapcache_current->mapentry == NULL) { free(tempkey); return (YP_NOMAP); } mapentry_current = mapcache_current->mapentry; while(mapentry_current) { if (!strcmp(mapentry_current->key, (char *)tempkey)) { val->valdat_val = safe_strdup(mapentry_current->val); val->valdat_len = strlen(mapentry_current->val); key->keydat_val = safe_strdup(mapentry_current->key); key->keydat_len = strlen(mapentry_current->key); free(tempkey); return (YP_TRUE); } mapentry_current = mapentry_current->next; } rval = YP_NOKEY; } } else { rval = YP_NOMAP; } free(tempkey); return (rval); } ypstat yp_first_record(keydat *key, mapname *map, valdat *val) { ypstat rval; struct mapcache *mapcache_current; rval = YP_YPERR; mapcache_current = getcache(map); if(mapcache_current != NULL) { if(mapcache_current->mapentry != NULL) { val->valdat_val = safe_strdup(mapcache_current->mapentry->val); val->valdat_len = strlen(mapcache_current->mapentry->val); key->keydat_val = safe_strdup(mapcache_current->mapentry->key); key->keydat_len = strlen(mapcache_current->mapentry->key); rval = YP_TRUE; } else { rval = YP_NOMAP; } } else { rval = YP_NOMAP; } return (rval); } ypstat yp_next_record(keydat *key, mapname *map, valdat *val) { struct mapcache *mapcache_current; struct mapentry *mapentry_current; ypstat rval; char *tempkey; /* NIS clients will iterate through the entire map, calling only * ypproc_nextbykey. Thus, the first call will have no key and * a keylen of 0, so return the result of yp_first_record */ if (key->keydat_len == 0) { rval = yp_first_record(key, map, val); return (rval); } tempkey = safe_malloc(key->keydat_len + 1); bcopy(key->keydat_val, tempkey, key->keydat_len); tempkey[key->keydat_len] = '\0'; rval = YP_YPERR; mapcache_current = getcache(map); if(mapcache_current != NULL) { if(mapcache_current->mapentry == NULL) { return (YP_NOMAP); } if (!strcmp((char *)mapcache_current->map, (char *) map)) { mapentry_current = mapcache_current->mapentry; while(mapentry_current) { if (!strcmp(mapentry_current->key, (char *)tempkey)) { free(tempkey); if (mapentry_current->next != NULL) { val->valdat_val = safe_strdup(mapentry_current->next->val); val->valdat_len = strlen(mapentry_current->next->val); key->keydat_val = safe_strdup(mapentry_current->next->key); key->keydat_len = strlen(mapentry_current->next->key); return (YP_TRUE); } else { key->keydat_len = 0; return (YP_NOKEY); } } mapentry_current = mapentry_current->next; } rval = YP_NOKEY; } } else { rval = YP_NOMAP; } free(tempkey); return (rval); }