diff options
Diffstat (limited to 'nis/nss_nis/nis-service.c')
-rw-r--r-- | nis/nss_nis/nis-service.c | 133 |
1 files changed, 62 insertions, 71 deletions
diff --git a/nis/nss_nis/nis-service.c b/nis/nss_nis/nis-service.c index 40772ae743..cb728335f9 100644 --- a/nis/nss_nis/nis-service.c +++ b/nis/nss_nis/nis-service.c @@ -37,20 +37,7 @@ __libc_lock_define_initialized (static, lock) -struct response_t -{ - struct response_t *next; - char val[0]; -}; - -struct intern_t -{ - struct response_t *start; - struct response_t *next; -}; -typedef struct intern_t intern_t; - -static intern_t intern = { NULL, NULL }; +static intern_t intern; struct search_t { @@ -65,35 +52,6 @@ struct search_t }; static int -saveit (int instatus, char *inkey, int inkeylen, char *inval, - int invallen, char *indata) -{ - intern_t *intern = (intern_t *) indata; - - if (instatus != YP_TRUE) - return 1; - - if (inkey && inkeylen > 0 && inval && invallen > 0) - { - struct response_t *newp = malloc (sizeof (struct response_t) - + invallen + 1); - if (newp == NULL) - return 1; /* We have no error code for out of memory */ - - if (intern->start == NULL) - intern->start = newp; - else - intern->next->next = newp; - intern->next = newp; - - newp->next = NULL; - *((char *) mempcpy (newp->val, inval, invallen)) = '\0'; - } - - return 0; -} - -static int dosearch (int instatus, char *inkey, int inkeylen, char *inval, int invallen, char *indata) { @@ -152,35 +110,35 @@ dosearch (int instatus, char *inkey, int inkeylen, char *inval, return 0; } -static enum nss_status -internal_nis_endservent (intern_t * intern) +static void +internal_nis_endservent (void) { - while (intern->start != NULL) + struct response_t *curr = intern.next; + + while (curr != NULL) { - intern->next = intern->start; - intern->start = intern->start->next; - free (intern->next); + struct response_t *last = curr; + curr = curr->next; + free (last); } - return NSS_STATUS_SUCCESS; + intern.next = intern.start = NULL; } enum nss_status _nss_nis_endservent (void) { - enum nss_status status; - __libc_lock_lock (lock); - status = internal_nis_endservent (&intern); + internal_nis_endservent (); __libc_lock_unlock (lock); - return status; + return NSS_STATUS_SUCCESS; } static enum nss_status -internal_nis_setservent (intern_t *intern) +internal_nis_setservent (void) { char *domainname; struct ypall_callback ypcb; @@ -189,12 +147,18 @@ internal_nis_setservent (intern_t *intern) if (yp_get_default_domain (&domainname)) return NSS_STATUS_UNAVAIL; - (void) internal_nis_endservent (intern); + internal_nis_endservent (); - ypcb.foreach = saveit; - ypcb.data = (char *) intern; + ypcb.foreach = _nis_saveit; + ypcb.data = (char *) &intern; status = yperr2nss (yp_all (domainname, "services.byname", &ypcb)); - intern->next = intern->start; + + /* Mark the last buffer as full. */ + if (intern.next != NULL) + intern.next->size = intern.offset; + + intern.next = intern.start; + intern.offset = 0; return status; } @@ -206,7 +170,7 @@ _nss_nis_setservent (int stayopen) __libc_lock_lock (lock); - status = internal_nis_setservent (&intern); + status = internal_nis_setservent (); __libc_lock_unlock (lock); @@ -215,29 +179,56 @@ _nss_nis_setservent (int stayopen) static enum nss_status internal_nis_getservent_r (struct servent *serv, char *buffer, - size_t buflen, int *errnop, intern_t *data) + size_t buflen, int *errnop) { struct parser_data *pdata = (void *) buffer; int parse_res; char *p; - if (data->start == NULL) - internal_nis_setservent (data); + if (intern.start == NULL) + internal_nis_setservent (); - /* Get the next entry until we found a correct one. */ + /* Get the next entry until we found a correct one. */ do { - if (data->next == NULL) - return NSS_STATUS_NOTFOUND; + struct response_t *bucket = intern.next; - p = strncpy (buffer, data->next->val, buflen); - while (isspace (*p)) - ++p; + if (__builtin_expect (intern.offset >= bucket->size, 0)) + { + if (bucket->next == NULL) + return NSS_STATUS_NOTFOUND; + + /* We look at all the content in the current bucket. Go on + to the next. */ + bucket = intern.next = bucket->next; + intern.offset = 0; + } + + for (p = &bucket->mem[intern.offset]; isspace (*p); ++p) + ++intern.offset; + + size_t len = strlen (p) + 1; + if (__builtin_expect (len > buflen, 0)) + { + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + /* We unfortunately have to copy the data in the user-provided + buffer because that buffer might be around for a very long + time and the servent structure must remain valid. If we would + rely on the BUCKET memory the next 'setservent' or 'endservent' + call would destroy it. + + The important thing is that it is a single NUL-terminated + string. This is what the parsing routine expects. */ + p = memcpy (buffer, &bucket->mem[intern.offset], len); parse_res = _nss_files_parse_servent (p, serv, pdata, buflen, errnop); if (__builtin_expect (parse_res == -1, 0)) return NSS_STATUS_TRYAGAIN; - data->next = data->next->next; + + intern.offset += len; } while (!parse_res); @@ -252,7 +243,7 @@ _nss_nis_getservent_r (struct servent *serv, char *buffer, size_t buflen, __libc_lock_lock (lock); - status = internal_nis_getservent_r (serv, buffer, buflen, errnop, &intern); + status = internal_nis_getservent_r (serv, buffer, buflen, errnop); __libc_lock_unlock (lock); |