enum nss_status _nss_nisplus_setnetgrent (const char *group, struct __netgrent *netgrp) { char buf[strlen (group) + 25]; if (group == NULL || group[0] == '\0') return NSS_STATUS_UNAVAIL; enum nss_status status = NSS_STATUS_SUCCESS; snprintf (buf, sizeof (buf), "[name=%s],netgroup.org_dir", group); netgrp->data = (char *) nis_list (buf, EXPAND_NAME, NULL, NULL); if (netgrp->data == NULL) { __set_errno (ENOMEM); status = NSS_STATUS_TRYAGAIN; } else if (niserr2nss (((nis_result *) netgrp->data)->status) != NSS_STATUS_SUCCESS) { status = niserr2nss (((nis_result *) netgrp->data)->status); internal_endnetgrent (netgrp); } else { netgrp->data_size = ((nis_result *) netgrp->data)->objects.objects_len; netgrp->position = 0; netgrp->first = 1; } return status; }
enum nss_status _nss_nisplus_getgrnam_r (const char *name, struct group *gr, char *buffer, size_t buflen, int *errnop) { int parse_res; if (grp_tablename_val == NULL) { enum nss_status status = _nss_grp_create_tablename (errnop); if (status != NSS_STATUS_SUCCESS) return status; } if (name == NULL) { *errnop = EINVAL; return NSS_STATUS_NOTFOUND; } nis_result *result; char buf[strlen (name) + 9 + grp_tablename_len]; int olderr = errno; snprintf (buf, sizeof (buf), "[name=%s],%s", name, grp_tablename_val); result = nis_list (buf, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL); if (result == NULL) { *errnop = ENOMEM; return NSS_STATUS_TRYAGAIN; } if (__glibc_unlikely (niserr2nss (result->status) != NSS_STATUS_SUCCESS)) { enum nss_status status = niserr2nss (result->status); nis_freeresult (result); return status; } parse_res = _nss_nisplus_parse_grent (result, gr, buffer, buflen, errnop); nis_freeresult (result); if (__glibc_unlikely (parse_res < 1)) { if (parse_res == -1) { *errnop = ERANGE; return NSS_STATUS_TRYAGAIN; } else { __set_errno (olderr); return NSS_STATUS_NOTFOUND; } } return NSS_STATUS_SUCCESS; }
enum nss_status _nss_nisplus_getpwuid_r (const uid_t uid, struct passwd *pw, char *buffer, size_t buflen, int *errnop) { if (pwd_tablename_val == NULL) { enum nss_status status = _nss_pwd_create_tablename (errnop); if (status != NSS_STATUS_SUCCESS) return status; } int parse_res; nis_result *result; char buf[8 + 3 * sizeof (unsigned long int) + pwd_tablename_len]; int olderr = errno; snprintf (buf, sizeof (buf), "[uid=%lu],%s", (unsigned long int) uid, pwd_tablename_val); result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS | USE_DGRAM, NULL, NULL); if (result == NULL) { *errnop = ENOMEM; return NSS_STATUS_TRYAGAIN; } if (niserr2nss (result->status) != NSS_STATUS_SUCCESS) { enum nss_status status = niserr2nss (result->status); errno = olderr; nis_freeresult (result); return status; } parse_res = _nss_nisplus_parse_pwent (result, pw, buffer, buflen, errnop); nis_freeresult (result); if (parse_res < 1) { if (parse_res == -1) { *errnop = ERANGE; return NSS_STATUS_TRYAGAIN; } else { errno = olderr; return NSS_STATUS_NOTFOUND; } } return NSS_STATUS_SUCCESS; }
enum nss_status _nss_nisplus_gethostton_r (const char *name, struct etherent *eth, char *buffer, size_t buflen, int *errnop) { if (tablename_val == NULL) { enum nss_status status = _nss_create_tablename (errnop); if (status != NSS_STATUS_SUCCESS) return status; } if (name == NULL) { *errnop = EINVAL; return NSS_STATUS_UNAVAIL; } char buf[strlen (name) + 9 + tablename_len]; int olderr = errno; snprintf (buf, sizeof (buf), "[name=%s],%s", name, tablename_val); nis_result *result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS | USE_DGRAM, NULL, NULL); if (result == NULL) { *errnop = ENOMEM; return NSS_STATUS_TRYAGAIN; } if (__glibc_unlikely (niserr2nss (result->status) != NSS_STATUS_SUCCESS)) { enum nss_status status = niserr2nss (result->status); nis_freeresult (result); return status; } int parse_res = _nss_nisplus_parse_etherent (result, eth, buffer, buflen, errnop); /* We do not need the lookup result anymore. */ nis_freeresult (result); if (__glibc_unlikely (parse_res < 1)) { __set_errno (olderr); if (parse_res == -1) return NSS_STATUS_TRYAGAIN; return NSS_STATUS_NOTFOUND; } return NSS_STATUS_SUCCESS; }
enum nss_status _nss_nisplus_getgrgid_r (const gid_t gid, struct group *gr, char *buffer, size_t buflen, int *errnop) { if (grp_tablename_val == NULL) { enum nss_status status = _nss_grp_create_tablename (errnop); if (status != NSS_STATUS_SUCCESS) return status; } int parse_res; nis_result *result; char buf[8 + 3 * sizeof (unsigned long int) + grp_tablename_len]; int olderr = errno; snprintf (buf, sizeof (buf), "[gid=%lu],%s", (unsigned long int) gid, grp_tablename_val); result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL); if (result == NULL) { *errnop = ENOMEM; return NSS_STATUS_TRYAGAIN; } if (__glibc_unlikely (niserr2nss (result->status) != NSS_STATUS_SUCCESS)) { enum nss_status status = niserr2nss (result->status); __set_errno (olderr); nis_freeresult (result); return status; } parse_res = _nss_nisplus_parse_grent (result, gr, buffer, buflen, errnop); nis_freeresult (result); if (__glibc_unlikely (parse_res < 1)) { __set_errno (olderr); if (parse_res == -1) { *errnop = ERANGE; return NSS_STATUS_TRYAGAIN; } else return NSS_STATUS_NOTFOUND; } return NSS_STATUS_SUCCESS; }
enum nss_status _nss_nisplus_getpwnam_r (const char *name, struct passwd *pw, char *buffer, size_t buflen, int *errnop) { int parse_res; if (tablename_val == NULL) { enum nss_status status = _nss_create_tablename (errnop); if (status != NSS_STATUS_SUCCESS) return status; } if (name == NULL) { *errnop = EINVAL; return NSS_STATUS_UNAVAIL; } else { nis_result *result; char buf[strlen (name) + 24 + tablename_len]; sprintf (buf, "[name=%s],%s", name, tablename_val); result = nis_list(buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL); if (niserr2nss (result->status) != NSS_STATUS_SUCCESS) { enum nss_status status = niserr2nss (result->status); nis_freeresult (result); return status; } parse_res = _nss_nisplus_parse_pwent (result, pw, buffer, buflen, errnop); nis_freeresult (result); if (parse_res < 1) { if (parse_res == -1) { *errnop = ERANGE; return NSS_STATUS_TRYAGAIN; } else return NSS_STATUS_NOTFOUND; } return NSS_STATUS_SUCCESS; } }
int nisplus_reload(mnt_map *m, char *map, void (*fn) ()) { int error = 0; struct nis_callback_data data; nis_result *result; char *org; /* if map does not have ".org_dir" then append it */ nis_name map_name; size_t l; org = strstr(map, NISPLUS_ORGDIR); if (org == NULL) org = NISPLUS_ORGDIR; else org = ""; /* make some room for the NIS map_name */ l = strlen(map) + sizeof(NISPLUS_ORGDIR); map_name = xmalloc(l); if (map_name == NULL) { plog(XLOG_ERROR, "Unable to create map_name %s: %s", map, strerror(ENOMEM)); return ENOMEM; } xsnprintf(map_name, l, "%s%s", map, org); data.ncd_m = m; data.ncd_map = map_name; data.ncd_fn = fn; dlog("NISplus reload for %s", map); result = nis_list(map_name, EXPAND_NAME | FOLLOW_LINKS | FOLLOW_PATH, (int (*)()) nisplus_callback, &data); /* free off the NIS map_name */ XFREE(map_name); if (result->status != NIS_SUCCESS && result->status != NIS_CBRESULTS) error = 1; if (error) plog(XLOG_ERROR, "error grabbing nisplus map of %s: %s", map, nis_sperrno(result->status)); nis_freeresult(result); return error; }
/* Check that someone else don't have the same auth information already */ static nis_error auth_exists(char *princname, char *auth_name, char *auth_type, char *domain) { char sname[NIS_MAXNAMELEN+MAXHOSTNAMELEN+64]; nis_result *res; nis_error status; char *foundprinc; (void) sprintf(sname, "[auth_name=%s,auth_type=%s],%s.%s", auth_name, auth_type, CRED_TABLE, domain); if (sname[strlen(sname)-1] != '.') strcat(sname, "."); /* Don't want FOLLOW_PATH here */ res = nis_list(sname, MASTER_ONLY+USE_DGRAM+NO_AUTHINFO+FOLLOW_LINKS, NULL, NULL); status = res->status; switch (res->status) { case NIS_NOTFOUND: break; case NIS_TRYAGAIN : (void) fprintf(stderr, "%s: NIS+ server busy, try again later.\n", program_name); exit(1); case NIS_PERMISSION : (void) fprintf(stderr, "%s: insufficient permission to look up old credentials.\n", program_name); exit(1); case NIS_SUCCESS: foundprinc = ENTRY_VAL(res->objects.objects_val, 0); if (nis_dir_cmp(foundprinc, princname) != SAME_NAME) { (void) fprintf(stderr, "%s: %s credentials with auth_name '%s' already belong to '%s'.\n", program_name, auth_type, auth_name, foundprinc); exit(1); } break; default: (void) fprintf(stderr, "%s: error looking at cred table, NIS+ error: %s\n", program_name, nis_sperrno(res->status)); exit(1); } nis_freeresult(res); return (status); }
int lookup_mount(const char *root, const char *name, int name_len, void *context) { struct lookup_context *ctxt = (struct lookup_context *) context; char tablename[strlen(name) + strlen(ctxt->mapname) + strlen(ctxt->domainname) + 20]; nis_result *result; int rv; debug(MODPREFIX "looking up %s", name); sprintf(tablename, "[key=%s],%s.org_dir.%s", name, ctxt->mapname, ctxt->domainname); result = nis_list(tablename, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL); if (result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS) { /* Try to get the "*" entry if there is one - note that we *don't* modify "name" so & -> the name we used, not "*" */ sprintf(tablename, "[key=*],%s.org_dir.%s", ctxt->mapname, ctxt->domainname); result = nis_list(tablename, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL); } if (result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS) { crit(MODPREFIX "lookup for %s failed: %s", name, nis_sperrno(result->status)); return 1; } debug(MODPREFIX "%s -> %s", name, NIS_RES_OBJECT(result)->EN_data.en_cols.en_cols_val[1].ec_value. ec_value_val); rv = ctxt->parse->parse_mount(root, name, name_len, NIS_RES_OBJECT(result)->EN_data.en_cols. en_cols_val[1].ec_value.ec_value_val, ctxt->parse->context); return rv; }
nis_name nis_local_principal (void) { static char __principal[NIS_MAXNAMELEN + 1]; if (__principal[0] == '\0') { char buf[NIS_MAXNAMELEN + 1]; nis_result *res; uid_t uid = geteuid (); if (uid != 0) { int len = snprintf (buf, NIS_MAXNAMELEN - 1, "[auth_name=%d,auth_type=LOCAL],cred.org_dir.%s", uid, nis_local_directory ()); if (len >= NIS_MAXNAMELEN - 1) nobody: /* XXX The buffer is too small. Can this happen??? */ return strcpy (__principal, "nobody"); if (buf[len - 1] != '.') { buf[len++] = '.'; buf[len] = '\0'; } res = nis_list (buf, USE_DGRAM + NO_AUTHINFO + FOLLOW_LINKS + FOLLOW_PATH, NULL, NULL); if (res == NULL) goto nobody; if (NIS_RES_STATUS (res) == NIS_SUCCESS) { if (res->objects.objects_len > 1) { /* More than one principal with same uid? something wrong with cred table. Should be unique. Warn user and continue. */ printf (_("\ LOCAL entry for UID %d in directory %s not unique\n"), uid, nis_local_directory ()); } strcpy (__principal, ENTRY_VAL (res->objects.objects_val, 0)); nis_freeresult (res); return __principal; }
/* * Try to locate a key using NIS+. */ int nisplus_search(mnt_map *m, char *map, char *key, char **val, time_t *tp) { nis_result *result; int error = 0; struct nisplus_search_callback_data data; nis_name index; char *org; /* if map does not have ".org_dir" then append it */ size_t l; org = strstr(map, NISPLUS_ORGDIR); if (org == NULL) org = NISPLUS_ORGDIR; else org = ""; /* make some room for the NIS index */ l = sizeof('[') /* for opening selection criteria */ + sizeof(NISPLUS_KEY) + strlen(key) + sizeof(']') /* for closing selection criteria */ + sizeof(',') /* + 1 for , separator */ + strlen(map) + sizeof(NISPLUS_ORGDIR); index = xmalloc(l); if (index == NULL) { plog(XLOG_ERROR, "Unable to create index %s: %s", map, strerror(ENOMEM)); return ENOMEM; } xsnprintf(index, l, "[%s%s],%s%s", NISPLUS_KEY, key, map, org); data.key = key; data.value = NULL; dlog("NISplus search for %s", index); result = nis_list(index, EXPAND_NAME | FOLLOW_LINKS | FOLLOW_PATH, (int (*)()) nisplus_search_callback, &data); /* free off the NIS index */ XFREE(index); if (result == NULL) { plog(XLOG_ERROR, "nisplus_search: %s: %s", map, strerror(ENOMEM)); return ENOMEM; } /* * Do something interesting with the return code */ switch (result->status) { case NIS_SUCCESS: case NIS_CBRESULTS: if (data.value == NULL) { nis_object *value = result->objects.objects_val; dlog("NISplus search found <nothing>"); dlog("NISplus search for %s: %s(%d)", map, nis_sperrno(result->status), result->status); if (value != NULL) data.value = strnsave(ENTRY_VAL(value, 1), ENTRY_LEN(value, 1)); } if (m->cfm && (m->cfm->cfm_flags & CFM_SUN_MAP_SYNTAX)) { *val = sun_entry2amd(key, data.value); XFREE(data.value); /* strnsave malloc'ed it above */ } else *val = data.value; if (*val) { error = 0; dlog("NISplus search found %s", *val); } else { error = ENOENT; dlog("NISplus search found nothing"); } *tp = 0; break; case NIS_NOSUCHNAME: dlog("NISplus search returned %d", result->status); error = ENOENT; break; default: plog(XLOG_ERROR, "nisplus_search: %s: %s", map, nis_sperrno(result->status)); error = EIO; break; } nis_freeresult(result); return error; }
enum nss_status _nss_nisplus_getntohost_r (const struct ether_addr *addr, struct etherent *eth, char *buffer, size_t buflen, int *errnop) { if (tablename_val == NULL) { __libc_lock_lock (lock); enum nss_status status = _nss_create_tablename (errnop); __libc_lock_unlock (lock); if (status != NSS_STATUS_SUCCESS) return status; } if (addr == NULL) { *errnop = EINVAL; return NSS_STATUS_UNAVAIL; } char buf[26 + tablename_len]; snprintf (buf, sizeof (buf), "[addr=%" PRIx8 ":%" PRIx8 ":%" PRIx8 ":%" PRIx8 ":%" PRIx8 ":%" PRIx8 "],%s", addr->ether_addr_octet[0], addr->ether_addr_octet[1], addr->ether_addr_octet[2], addr->ether_addr_octet[3], addr->ether_addr_octet[4], addr->ether_addr_octet[5], tablename_val); nis_result *result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS | USE_DGRAM, NULL, NULL); if (result == NULL) { *errnop = ENOMEM; return NSS_STATUS_TRYAGAIN; } if (__glibc_unlikely (niserr2nss (result->status) != NSS_STATUS_SUCCESS)) { enum nss_status status = niserr2nss (result->status); nis_freeresult (result); return status; } int parse_res = _nss_nisplus_parse_etherent (result, eth, buffer, buflen, errnop); /* We do not need the lookup result anymore. */ nis_freeresult (result); if (__glibc_unlikely (parse_res < 1)) { if (parse_res == -1) return NSS_STATUS_TRYAGAIN; return NSS_STATUS_NOTFOUND; } return NSS_STATUS_SUCCESS; }
static void fillnameddirtable(UNUSED(HashTable ht)) { if (!allusersadded) { #if defined(HAVE_NIS) || defined(HAVE_NIS_PLUS) FILE *pwf; char buf[BUFSIZ], *p, *d, *de; int skipping, oldct = nameddirtab->ct, usepwf = 1; # ifndef HAVE_NIS_PLUS char domain[YPMAXDOMAIN]; struct ypall_callback cb; /* Get potential matches from NIS and cull those without local accounts */ if (getdomainname(domain, YPMAXDOMAIN) == 0) { cb.foreach = (int (*)()) add_userdir; cb.data = NULL; yp_all(domain, PASSWD_MAP, &cb); } # else /* HAVE_NIS_PLUS */ /* Maybe we should turn this string into a #define'd constant...? */ nis_list("passwd.org_dir", EXPAND_NAME|ALL_RESULTS|FOLLOW_LINKS|FOLLOW_PATH, add_userdir, 0); # endif if (nameddirtab->ct == oldct) { /* Using NIS or NIS+ didn't add any user directories. This seems * fishy, so we fall back to using getpwent(). If we don't have * that, we only use the passwd file. */ #ifdef HAVE_GETPWENT struct passwd *pw; setpwent(); /* loop through the password file/database * * and add all entries returned. */ while ((pw = getpwent()) && !errflag) adduserdir(pw->pw_name, pw->pw_dir, ND_USERNAME, 1); endpwent(); usepwf = 0; #endif /* HAVE_GETPWENT */ } if (usepwf) { /* Don't forget the non-NIS matches from the flat passwd file */ if ((pwf = fopen(PASSWD_FILE, "r")) != NULL) { skipping = 0; while (fgets(buf, BUFSIZ, pwf) != NULL) { if (strchr(buf, '\n') != NULL) { if (!skipping) { if ((p = strchr(buf, ':')) != NULL) { *p++ = '\0'; if ((de = strrchr(p, ':'))) { *de = '\0'; if ((d = strrchr(p, ':'))) { if (*++d && buf[0]) adduserdir(buf, d, ND_USERNAME, 1); } } } } else skipping = 0; } else skipping = 1; } fclose(pwf); } } #else /* no NIS or NIS_PLUS */ #ifdef HAVE_GETPWENT struct passwd *pw; setpwent(); /* loop through the password file/database * * and add all entries returned. */ while ((pw = getpwent()) && !errflag) adduserdir(pw->pw_name, pw->pw_dir, ND_USERNAME, 1); endpwent(); #endif /* HAVE_GETPWENT */ #endif allusersadded = 1; } }
enum nss_status _nss_nisplus_getspnam_r (const char *name, struct spwd *sp, char *buffer, size_t buflen, int *errnop) { int parse_res; if (pwd_tablename_val == NULL) { enum nss_status status = _nss_pwd_create_tablename (errnop); if (status != NSS_STATUS_SUCCESS) return status; } if (name == NULL) { *errnop = EINVAL; return NSS_STATUS_NOTFOUND; } nis_result *result; char buf[strlen (name) + 9 + pwd_tablename_len]; int olderr = errno; snprintf (buf, sizeof (buf), "[name=%s],%s", name, pwd_tablename_val); result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL); if (result == NULL) { *errnop = ENOMEM; return NSS_STATUS_TRYAGAIN; } if (__builtin_expect (niserr2nss (result->status) != NSS_STATUS_SUCCESS, 0)) { enum nss_status status = niserr2nss (result->status); __set_errno (olderr); nis_freeresult (result); return status; } parse_res = _nss_nisplus_parse_spent (result, sp, buffer, buflen, errnop); nis_freeresult (result); if (__builtin_expect (parse_res < 1, 0)) { if (parse_res == -1) { *errnop = ERANGE; return NSS_STATUS_TRYAGAIN; } else { __set_errno (olderr); return NSS_STATUS_NOTFOUND; } } return NSS_STATUS_SUCCESS; }
enum nss_status _nss_nisplus_initgroups_dyn (const char *user, gid_t group, long int *start, long int *size, gid_t **groupsp, long int limit, int *errnop) { if (grp_tablename_val == NULL) { enum nss_status status = _nss_grp_create_tablename (errnop); if (status != NSS_STATUS_SUCCESS) return status; } nis_result *result; char buf[strlen (user) + 12 + grp_tablename_len]; snprintf (buf, sizeof (buf), "[members=%s],%s", user, grp_tablename_val); result = nis_list (buf, FOLLOW_LINKS | FOLLOW_PATH | ALL_RESULTS, NULL, NULL); if (result == NULL) { *errnop = ENOMEM; return NSS_STATUS_TRYAGAIN; } if (__builtin_expect (niserr2nss (result->status) != NSS_STATUS_SUCCESS, 0)) { enum nss_status status = niserr2nss (result->status); nis_freeresult (result); return status; } if (NIS_RES_NUMOBJ (result) == 0) { errout: nis_freeresult (result); return NSS_STATUS_NOTFOUND; } gid_t *groups = *groupsp; nis_object *obj = NIS_RES_OBJECT (result); for (unsigned int cnt = 0; cnt < NIS_RES_NUMOBJ (result); ++cnt, ++obj) { if (__type_of (obj) != NIS_ENTRY_OBJ || strcmp (obj->EN_data.en_type, "group_tbl") != 0 || obj->EN_data.en_cols.en_cols_len < 4) continue; char *numstr = NISOBJVAL (2, obj); size_t len = NISOBJLEN (2, obj); if (len == 0 || numstr[0] == '\0') continue; gid_t gid; char *endp; if (__builtin_expect (numstr[len - 1] != '\0', 0)) { char numstrbuf[len + 1]; memcpy (numstrbuf, numstr, len); numstrbuf[len] = '\0'; gid = strtoul (numstrbuf, &endp, 10); if (*endp) continue; } else { gid = strtoul (numstr, &endp, 10); if (*endp) continue; } if (gid == group) continue; /* Insert this group. */ if (*start == *size) { /* Need a bigger buffer. */ long int newsize; if (limit > 0 && *size == limit) /* We reached the maximum. */ break; if (limit <= 0) newsize = 2 * *size; else newsize = MIN (limit, 2 * *size); gid_t *newgroups = realloc (groups, newsize * sizeof (*groups)); if (newgroups == NULL) goto errout; *groupsp = groups = newgroups; *size = newsize; } groups[*start] = gid; *start += 1; } nis_freeresult (result); return NSS_STATUS_SUCCESS; }
static int nisplus_find(void *handle, uschar *filename, uschar *query, int length, uschar **result, uschar **errmsg, uint *do_cache) { int i; int ssize = 0; int offset = 0; int error_error = FAIL; uschar *field_name = NULL; nis_result *nrt = NULL; nis_result *nre = NULL; nis_object *tno, *eno; struct entry_obj *eo; struct table_obj *ta; uschar *p = query + length; uschar *yield = NULL; do_cache = do_cache; /* Placate picky compilers */ /* Search backwards for a colon to see if a result field name has been given. */ while (p > query && p[-1] != ':') p--; if (p > query) { field_name = p; p[-1] = 0; } else p = query + length; /* Now search backwards to find the comma that starts the table name. */ while (p > query && p[-1] != ',') p--; if (p <= query) { *errmsg = US"NIS+ query malformed"; error_error = DEFER; goto NISPLUS_EXIT; } /* Look up the data for the table, in order to get the field names, check that we got back a table, and set up pointers so the field names can be scanned. */ nrt = nis_lookup(CS p, EXPAND_NAME | NO_CACHE); if (nrt->status != NIS_SUCCESS) { *errmsg = string_sprintf("NIS+ error accessing %s table: %s", p, nis_sperrno(nrt->status)); if (nrt->status != NIS_NOTFOUND && nrt->status != NIS_NOSUCHTABLE) error_error = DEFER; goto NISPLUS_EXIT; } tno = nrt->objects.objects_val; if (tno->zo_data.zo_type != TABLE_OBJ) { *errmsg = string_sprintf("NIS+ error: %s is not a table", p); goto NISPLUS_EXIT; } ta = &(tno->zo_data.objdata_u.ta_data); /* Now look up the entry in the table, check that we got precisely one object and that it is a table entry. */ nre = nis_list(CS query, EXPAND_NAME, NULL, NULL); if (nre->status != NIS_SUCCESS) { *errmsg = string_sprintf("NIS+ error accessing entry %s: %s", query, nis_sperrno(nre->status)); goto NISPLUS_EXIT; } if (nre->objects.objects_len > 1) { *errmsg = string_sprintf("NIS+ returned more than one object for %s", query); goto NISPLUS_EXIT; } else if (nre->objects.objects_len < 1) { *errmsg = string_sprintf("NIS+ returned no data for %s", query); goto NISPLUS_EXIT; } eno = nre->objects.objects_val; if (eno->zo_data.zo_type != ENTRY_OBJ) { *errmsg = string_sprintf("NIS+ error: %s is not an entry", query); goto NISPLUS_EXIT; } /* Scan the columns in the entry and in the table. If a result field was given, look for that field; otherwise concatenate all the fields with their names. */ eo = &(eno->zo_data.objdata_u.en_data); for (i = 0; i < eo->en_cols.en_cols_len; i++) { table_col *tc = ta->ta_cols.ta_cols_val + i; entry_col *ec = eo->en_cols.en_cols_val + i; int len = ec->ec_value.ec_value_len; uschar *value = US ec->ec_value.ec_value_val; /* The value may be NULL for a zero-length field. Turn this into an empty string for consistency. Remove trailing whitespace and zero bytes. */ if (value == NULL) value = US""; else while (len > 0 && (value[len-1] == 0 || isspace(value[len-1]))) len--; /* Concatenate all fields if no specific one selected */ if (field_name == NULL) { yield = string_cat(yield, &ssize, &offset,US tc->tc_name, Ustrlen(tc->tc_name)); yield = string_cat(yield, &ssize, &offset, US"=", 1); /* Quote the value if it contains spaces or is empty */ if (value[0] == 0 || Ustrchr(value, ' ') != NULL) { int j; yield = string_cat(yield, &ssize, &offset, US"\"", 1); for (j = 0; j < len; j++) { if (value[j] == '\"' || value[j] == '\\') yield = string_cat(yield, &ssize, &offset, US"\\", 1); yield = string_cat(yield, &ssize, &offset, value+j, 1); } yield = string_cat(yield, &ssize, &offset, US"\"", 1); } else yield = string_cat(yield, &ssize, &offset, value, len); yield = string_cat(yield, &ssize, &offset, US" ", 1); } /* When the specified field is found, grab its data and finish */ else if (Ustrcmp(field_name, tc->tc_name) == 0) { yield = string_copyn(value, len); goto NISPLUS_EXIT; } } /* Error if a field name was specified and we didn't find it; if no field name, ensure the concatenated data is zero-terminated. */ if (field_name != NULL) *errmsg = string_sprintf("NIS+ field %s not found for %s", field_name, query); else { yield[offset] = 0; store_reset(yield + offset + 1); } /* Restore the colon in the query, and free result store before finishing. */ NISPLUS_EXIT: if (field_name != NULL) field_name[-1] = ':'; if (nrt != NULL) nis_freeresult(nrt); if (nre != NULL) nis_freeresult(nre); if (yield != NULL) { *result = yield; return OK; } return error_error; /* FAIL or DEFER */ }