static int internal_function __internal_setnetgrent_reuse (const char *group, struct __netgrent *datap, int *errnop) { union { enum nss_status (*f) (const char *, struct __netgrent *); void *ptr; } fct; enum nss_status status = NSS_STATUS_UNAVAIL; struct name_list *new_elem; /* Free data from previous service. */ endnetgrent_hook (datap); /* Cycle through all the services and run their setnetgrent functions. */ int no_more = setup (&fct.ptr, &datap->nip); while (! no_more) { assert (datap->data == NULL); /* Ignore status, we force check in `__nss_next2'. */ status = DL_CALL_FCT (*fct.f, (group, datap)); service_user *old_nip = datap->nip; no_more = __nss_next2 (&datap->nip, "setnetgrent", NULL, &fct.ptr, status, 0); if (status == NSS_STATUS_SUCCESS && ! no_more) { enum nss_status (*endfct) (struct __netgrent *); endfct = __nss_lookup_function (old_nip, "endnetgrent"); if (endfct != NULL) (void) DL_CALL_FCT (*endfct, (datap)); } } /* Add the current group to the list of known groups. */ size_t group_len = strlen (group) + 1; new_elem = (struct name_list *) malloc (sizeof (struct name_list) + group_len); if (new_elem == NULL) { *errnop = errno; status = NSS_STATUS_TRYAGAIN; } else { new_elem->next = datap->known_groups; memcpy (new_elem->name, group, group_len); datap->known_groups = new_elem; } return status == NSS_STATUS_SUCCESS; }
int internal_function __gconv (__gconv_t cd, const unsigned char **inbuf, const unsigned char *inbufend, unsigned char **outbuf, unsigned char *outbufend, size_t *irreversible) { size_t last_step; int result; if (cd == (__gconv_t) -1L) return __GCONV_ILLEGAL_DESCRIPTOR; last_step = cd->__nsteps - 1; assert (irreversible != NULL); *irreversible = 0; cd->__data[last_step].__outbuf = outbuf != NULL ? *outbuf : NULL; cd->__data[last_step].__outbufend = outbufend; if (inbuf == NULL || *inbuf == NULL) /* We just flush. */ result = DL_CALL_FCT (cd->__steps->__fct, (cd->__steps, cd->__data, NULL, NULL, NULL, irreversible, cd->__data[last_step].__outbuf == NULL ? 2 : 1, 0)); else { const unsigned char *last_start; assert (outbuf != NULL && *outbuf != NULL); do { last_start = *inbuf; result = DL_CALL_FCT (cd->__steps->__fct, (cd->__steps, cd->__data, inbuf, inbufend, NULL, irreversible, 0, 0)); } while (result == __GCONV_EMPTY_INPUT && last_start != *inbuf && *inbuf + cd->__steps->__min_needed_from <= inbufend); } if (outbuf != NULL && *outbuf != NULL) *outbuf = cd->__data[last_step].__outbuf; return result; }
FILE * fopen( char const * fn, char const * mode ) { static Foolie_t foo; FILE * fyle; if( ! foo.f ) { foo.v = dlsym( RTLD_NEXT, "fopen" ); if( ! foo.v ) { puts( "not found!" ); exit( 1 ); } printf( "Real routine is at %p.\n", foo.v ); } #if USE_PROFILING fyle = DL_CALL_FCT( foo.f, ( fn, mode ) ); #else /* USE_PROFILING */ fyle = foo.f( fn, mode ); #endif /* USE_PROFILING */ printf( "Your fopen( '%s' ) %s.\n", fn, fyle ? "succeeded" : "FAILED" ); return( fyle ); }
static int internal_function find_module (const char *directory, const char *filename, struct __gconv_step *result) { size_t dirlen = strlen (directory); size_t fnamelen = strlen (filename) + 1; char fullname[dirlen + fnamelen]; int status = __GCONV_NOCONV; memcpy (__mempcpy (fullname, directory, dirlen), filename, fnamelen); result->__shlib_handle = __gconv_find_shlib (fullname); if (result->__shlib_handle != NULL) { status = __GCONV_OK; result->__modname = NULL; result->__fct = result->__shlib_handle->fct; result->__init_fct = result->__shlib_handle->init_fct; result->__end_fct = result->__shlib_handle->end_fct; /* These settings can be overridden by the init function. */ result->__btowc_fct = NULL; result->__data = NULL; /* Call the init function. */ if (result->__init_fct != NULL) status = DL_CALL_FCT (result->__init_fct, (result)); } return status; }
static int do_length (struct _IO_codecvt *codecvt, __mbstate_t *statep, const char *from_start, const char *from_end, _IO_size_t max) { int result; #ifdef _LIBC const unsigned char *cp = (const unsigned char *) from_start; wchar_t to_buf[max]; struct __gconv_step *gs = codecvt->__cd_in.__cd.__steps; size_t dummy; codecvt->__cd_in.__cd.__data[0].__outbuf = (unsigned char *) to_buf; codecvt->__cd_in.__cd.__data[0].__outbufend = (unsigned char *) &to_buf[max]; codecvt->__cd_in.__cd.__data[0].__statep = statep; __gconv_fct fct = gs->__fct; #ifdef PTR_DEMANGLE if (gs->__shlib_handle != NULL) PTR_DEMANGLE (fct); #endif DL_CALL_FCT (fct, (gs, codecvt->__cd_in.__cd.__data, &cp, (const unsigned char *) from_end, NULL, &dummy, 0, 0)); result = cp - (const unsigned char *) from_start; #else # ifdef _GLIBCPP_USE_WCHAR_T const char *from_start_copy = (const char *) from_start; size_t from_len = from_end - from_start; wchar_t to_buf[max]; size_t res; char *to_start = (char *) to_buf; res = iconv (codecvt->__cd_in, &from_start_copy, &from_len, &to_start, &max); result = from_start_copy - (char *) from_start; # else /* Decide what to do. */ result = 0; # endif #endif return result; }
size_t __mbrtowc (wchar_t *pwc, const char *s, size_t n, mbstate_t *ps) { wchar_t buf[1]; struct __gconv_step_data data; int status; size_t result; size_t dummy; const unsigned char *inbuf; char *outbuf = (char *) (pwc ?: buf); /* Set information for this step. */ data.__invocation_counter = 0; data.__internal_use = 1; data.__flags = __GCONV_IS_LAST; data.__statep = ps ?: &state; data.__trans = NULL; /* A first special case is if S is NULL. This means put PS in the initial state. */ if (s == NULL) { outbuf = (char *) buf; s = ""; n = 1; } /* Tell where we want the result. */ data.__outbuf = outbuf; data.__outbufend = outbuf + sizeof (wchar_t); /* Make sure we use the correct function. */ update_conversion_ptrs (); /* Do a normal conversion. */ inbuf = (const unsigned char *) s; status = DL_CALL_FCT (__wcsmbs_gconv_fcts.towc->__fct, (__wcsmbs_gconv_fcts.towc, &data, &inbuf, inbuf + n, NULL, &dummy, 0, 1)); /* There must not be any problems with the conversion but illegal input characters. The output buffer must be large enough, otherwise the definition of MB_CUR_MAX is not correct. All the other possible errors also must not happen. */ assert (status == __GCONV_OK || status == __GCONV_EMPTY_INPUT || status == __GCONV_ILLEGAL_INPUT || status == __GCONV_INCOMPLETE_INPUT || status == __GCONV_FULL_OUTPUT); if (status == __GCONV_OK || status == __GCONV_EMPTY_INPUT || status == __GCONV_FULL_OUTPUT) { if (data.__outbuf != (unsigned char *) outbuf && *(wchar_t *) outbuf == L'\0') { /* The converted character is the NUL character. */ assert (__mbsinit (data.__statep)); result = 0; } else result = inbuf - (const unsigned char *) s; } else if (status == __GCONV_INCOMPLETE_INPUT) result = (size_t) -2; else { result = (size_t) -1; __set_errno (EILSEQ); } return result; }
int __gconv_transliterate (struct __gconv_step *step, struct __gconv_step_data *step_data, const unsigned char *inbufstart, const unsigned char **inbufp, const unsigned char *inbufend, unsigned char **outbufstart, size_t *irreversible) { /* Find out about the locale's transliteration. */ uint_fast32_t size; const uint32_t *from_idx; const uint32_t *from_tbl; const uint32_t *to_idx; const uint32_t *to_tbl; const uint32_t *winbuf; const uint32_t *winbufend; uint_fast32_t low; uint_fast32_t high; /* The input buffer. There are actually 4-byte values. */ winbuf = (const uint32_t *) *inbufp; winbufend = (const uint32_t *) inbufend; __gconv_fct fct = step->__fct; #ifdef PTR_DEMANGLE if (step->__shlib_handle != NULL) PTR_DEMANGLE (fct); #endif /* If there is no transliteration information in the locale don't do anything and return the error. */ size = _NL_CURRENT_WORD (LC_CTYPE, _NL_CTYPE_TRANSLIT_TAB_SIZE); if (size == 0) goto no_rules; /* Get the rest of the values. */ from_idx = (const uint32_t *) _NL_CURRENT (LC_CTYPE, _NL_CTYPE_TRANSLIT_FROM_IDX); from_tbl = (const uint32_t *) _NL_CURRENT (LC_CTYPE, _NL_CTYPE_TRANSLIT_FROM_TBL); to_idx = (const uint32_t *) _NL_CURRENT (LC_CTYPE, _NL_CTYPE_TRANSLIT_TO_IDX); to_tbl = (const uint32_t *) _NL_CURRENT (LC_CTYPE, _NL_CTYPE_TRANSLIT_TO_TBL); /* Test whether there is enough input. */ if (winbuf + 1 > winbufend) return (winbuf == winbufend ? __GCONV_EMPTY_INPUT : __GCONV_INCOMPLETE_INPUT); /* The array starting at FROM_IDX contains indeces to the string table in FROM_TBL. The indeces are sorted wrt to the strings. I.e., we are doing binary search. */ low = 0; high = size; while (low < high) { uint_fast32_t med = (low + high) / 2; uint32_t idx; int cnt; /* Compare the string at this index with the string at the current position in the input buffer. */ idx = from_idx[med]; cnt = 0; do { if (from_tbl[idx + cnt] != winbuf[cnt]) /* Does not match. */ break; ++cnt; } while (from_tbl[idx + cnt] != L'\0' && winbuf + cnt < winbufend); if (cnt > 0 && from_tbl[idx + cnt] == L'\0') { /* Found a matching input sequence. Now try to convert the possible replacements. */ uint32_t idx2 = to_idx[med]; do { /* Determine length of replacement. */ uint_fast32_t len = 0; int res; const unsigned char *toinptr; unsigned char *outptr; while (to_tbl[idx2 + len] != L'\0') ++len; /* Try this input text. */ toinptr = (const unsigned char *) &to_tbl[idx2]; outptr = *outbufstart; res = DL_CALL_FCT (fct, (step, step_data, &toinptr, (const unsigned char *) &to_tbl[idx2 + len], &outptr, NULL, 0, 0)); if (res != __GCONV_ILLEGAL_INPUT) { /* If the conversion succeeds we have to increment the input buffer. */ if (res == __GCONV_EMPTY_INPUT) { *inbufp += cnt * sizeof (uint32_t); ++*irreversible; res = __GCONV_OK; } /* Do not increment the output pointer if we could not store the entire output. */ if (res != __GCONV_FULL_OUTPUT) *outbufstart = outptr; return res; } /* Next replacement. */ idx2 += len + 1; } while (to_tbl[idx2] != L'\0'); /* Nothing found, continue searching. */ } else if (cnt > 0) /* This means that the input buffer contents matches a prefix of an entry. Since we cannot match it unless we get more input, we will tell the caller about it. */ return __GCONV_INCOMPLETE_INPUT; if (winbuf + cnt >= winbufend || from_tbl[idx + cnt] < winbuf[cnt]) low = med + 1; else high = med; } no_rules: /* Maybe the character is supposed to be ignored. */ if (_NL_CURRENT_WORD (LC_CTYPE, _NL_CTYPE_TRANSLIT_IGNORE_LEN) != 0) { int n = _NL_CURRENT_WORD (LC_CTYPE, _NL_CTYPE_TRANSLIT_IGNORE_LEN); const uint32_t *ranges = (const uint32_t *) _NL_CURRENT (LC_CTYPE, _NL_CTYPE_TRANSLIT_IGNORE); const uint32_t wc = *(const uint32_t *) (*inbufp); int i; /* Test whether there is enough input. */ if (winbuf + 1 > winbufend) return (winbuf == winbufend ? __GCONV_EMPTY_INPUT : __GCONV_INCOMPLETE_INPUT); for (i = 0; i < n; ranges += 3, ++i) if (ranges[0] <= wc && wc <= ranges[1] && (wc - ranges[0]) % ranges[2] == 0) { /* Matches the range. Ignore it. */ *inbufp += 4; ++*irreversible; return __GCONV_OK; } else if (wc < ranges[0]) /* There cannot be any other matching range since they are sorted. */ break; } /* One last chance: use the default replacement. */ if (_NL_CURRENT_WORD (LC_CTYPE, _NL_CTYPE_TRANSLIT_DEFAULT_MISSING_LEN) != 0) { const uint32_t *default_missing = (const uint32_t *) _NL_CURRENT (LC_CTYPE, _NL_CTYPE_TRANSLIT_DEFAULT_MISSING); const unsigned char *toinptr = (const unsigned char *) default_missing; uint32_t len = _NL_CURRENT_WORD (LC_CTYPE, _NL_CTYPE_TRANSLIT_DEFAULT_MISSING_LEN); unsigned char *outptr; int res; /* Test whether there is enough input. */ if (winbuf + 1 > winbufend) return (winbuf == winbufend ? __GCONV_EMPTY_INPUT : __GCONV_INCOMPLETE_INPUT); outptr = *outbufstart; res = DL_CALL_FCT (fct, (step, step_data, &toinptr, (const unsigned char *) (default_missing + len), &outptr, NULL, 0, 0)); if (res != __GCONV_ILLEGAL_INPUT) { /* If the conversion succeeds we have to increment the input buffer. */ if (res == __GCONV_EMPTY_INPUT) { /* This worked but is not reversible. */ ++*irreversible; *inbufp += 4; res = __GCONV_OK; } *outbufstart = outptr; return res; } } /* Haven't found a match. */ return __GCONV_ILLEGAL_INPUT; }
static int internal_getgrouplist (const char *user, gid_t group, long int *size, gid_t **groupsp, long int limit) { #ifdef USE_NSCD if (__nss_not_use_nscd_group > 0 && ++__nss_not_use_nscd_group > NSS_NSCD_RETRY) __nss_not_use_nscd_group = 0; if (!__nss_not_use_nscd_group && !__nss_database_custom[NSS_DBSIDX_group]) { int n = __nscd_getgrouplist (user, group, size, groupsp, limit); if (n >= 0) return n; /* nscd is not usable. */ __nss_not_use_nscd_group = 1; } #endif enum nss_status status = NSS_STATUS_UNAVAIL; int no_more = 0; /* Never store more than the starting *SIZE number of elements. */ assert (*size > 0); (*groupsp)[0] = group; /* Start is one, because we have the first group as parameter. */ long int start = 1; if (__nss_initgroups_database == NULL) { if (__nss_database_lookup ("initgroups", NULL, "", &__nss_initgroups_database) < 0) { if (__nss_group_database == NULL) no_more = __nss_database_lookup ("group", NULL, "compat files", &__nss_group_database); __nss_initgroups_database = __nss_group_database; } else use_initgroups_entry = true; } else /* __nss_initgroups_database might have been set through __nss_configure_lookup in which case use_initgroups_entry was not set here. */ use_initgroups_entry = __nss_initgroups_database != __nss_group_database; service_user *nip = __nss_initgroups_database; while (! no_more) { long int prev_start = start; initgroups_dyn_function fct = __nss_lookup_function (nip, "initgroups_dyn"); if (fct == NULL) status = compat_call (nip, user, group, &start, size, groupsp, limit, &errno); else status = DL_CALL_FCT (fct, (user, group, &start, size, groupsp, limit, &errno)); /* Remove duplicates. */ long int cnt = prev_start; while (cnt < start) { long int inner; for (inner = 0; inner < prev_start; ++inner) if ((*groupsp)[inner] == (*groupsp)[cnt]) break; if (inner < prev_start) (*groupsp)[cnt] = (*groupsp)[--start]; else ++cnt; } /* This is really only for debugging. */ if (NSS_STATUS_TRYAGAIN > status || status > NSS_STATUS_RETURN) __libc_fatal ("illegal status in internal_getgrouplist"); /* For compatibility reason we will continue to look for more entries using the next service even though data has already been found if the nsswitch.conf file contained only a 'groups' line and no 'initgroups' line. If the latter is available we always respect the status. This means that the default for successful lookups is to return. */ if ((use_initgroups_entry || status != NSS_STATUS_SUCCESS) && nss_next_action (nip, status) == NSS_ACTION_RETURN) break; if (nip->next == NULL) no_more = -1; else nip = nip->next; } return start; }
size_t __wcrtomb (char *s, wchar_t wc, mbstate_t *ps) { char buf[MB_CUR_MAX]; struct __gconv_step_data data; int status; size_t result; size_t dummy; const struct gconv_fcts *fcts; /* Set information for this step. */ data.__invocation_counter = 0; data.__internal_use = 1; data.__flags = __GCONV_IS_LAST; data.__statep = ps ?: &state; data.__trans = NULL; /* A first special case is if S is NULL. This means put PS in the initial state. */ if (s == NULL) { s = buf; wc = L'\0'; } /* Tell where we want to have the result. */ data.__outbuf = (unsigned char *) s; data.__outbufend = (unsigned char *) s + MB_CUR_MAX; /* Get the conversion functions. */ fcts = get_gconv_fcts (_NL_CURRENT_DATA (LC_CTYPE)); __gconv_fct fct = fcts->tomb->__fct; #ifdef PTR_DEMANGLE if (fcts->tomb->__shlib_handle != NULL) PTR_DEMANGLE (fct); #endif /* If WC is the NUL character we write into the output buffer the byte sequence necessary for PS to get into the initial state, followed by a NUL byte. */ if (wc == L'\0') { status = DL_CALL_FCT (fct, (fcts->tomb, &data, NULL, NULL, NULL, &dummy, 1, 1)); if (status == __GCONV_OK || status == __GCONV_EMPTY_INPUT) *data.__outbuf++ = '\0'; } else { /* Do a normal conversion. */ const unsigned char *inbuf = (const unsigned char *) &wc; status = DL_CALL_FCT (fct, (fcts->tomb, &data, &inbuf, inbuf + sizeof (wchar_t), NULL, &dummy, 0, 1)); } /* There must not be any problems with the conversion but illegal input characters. The output buffer must be large enough, otherwise the definition of MB_CUR_MAX is not correct. All the other possible errors also must not happen. */ assert (status == __GCONV_OK || status == __GCONV_EMPTY_INPUT || status == __GCONV_ILLEGAL_INPUT || status == __GCONV_INCOMPLETE_INPUT || status == __GCONV_FULL_OUTPUT); if (status == __GCONV_OK || status == __GCONV_EMPTY_INPUT || status == __GCONV_FULL_OUTPUT) result = data.__outbuf - (unsigned char *) s; else { result = (size_t) -1; __set_errno (EILSEQ); } return result; }
static enum __codecvt_result do_in (struct _IO_codecvt *codecvt, __mbstate_t *statep, const char *from_start, const char *from_end, const char **from_stop, wchar_t *to_start, wchar_t *to_end, wchar_t **to_stop) { enum __codecvt_result result; #ifdef _LIBC struct __gconv_step *gs = codecvt->__cd_in.__cd.__steps; int status; size_t dummy; const unsigned char *from_start_copy = (unsigned char *) from_start; codecvt->__cd_in.__cd.__data[0].__outbuf = (unsigned char *) to_start; codecvt->__cd_in.__cd.__data[0].__outbufend = (unsigned char *) to_end; codecvt->__cd_in.__cd.__data[0].__statep = statep; __gconv_fct fct = gs->__fct; #ifdef PTR_DEMANGLE if (gs->__shlib_handle != NULL) PTR_DEMANGLE (fct); #endif status = DL_CALL_FCT (fct, (gs, codecvt->__cd_in.__cd.__data, &from_start_copy, (const unsigned char *) from_end, NULL, &dummy, 0, 0)); *from_stop = (const char *) from_start_copy; *to_stop = (wchar_t *) codecvt->__cd_in.__cd.__data[0].__outbuf; switch (status) { case __GCONV_OK: case __GCONV_EMPTY_INPUT: result = __codecvt_ok; break; case __GCONV_FULL_OUTPUT: case __GCONV_INCOMPLETE_INPUT: result = __codecvt_partial; break; default: result = __codecvt_error; break; } #else # ifdef _GLIBCPP_USE_WCHAR_T size_t res; const char *from_start_copy = (const char *) from_start; size_t from_len = from_end - from_start; char *to_start_copy = (char *) from_start; size_t to_len = to_end - to_start; res = iconv (codecvt->__cd_in, &from_start_copy, &from_len, &to_start_copy, &to_len); if (res == 0) result = __codecvt_ok; else if (to_len == 0) result = __codecvt_partial; else if (from_len < codecvt->__codecvt_do_max_length (codecvt)) result = __codecvt_partial; else result = __codecvt_error; # else /* Decide what to do. */ result = __codecvt_error; # endif #endif return result; }
enum nss_status _nss_nonlocal_setspent(int stayopen) { enum nss_status status; const struct walk_nss w = { .lookup = &__nss_shadow_nonlocal_lookup, .fct_name = "setspent", .status = &status }; const __typeof__(&_nss_nonlocal_setspent) self = NULL; #define args (stayopen) #include "walk_nss.h" #undef args if (status != NSS_STATUS_SUCCESS) return status; if (spent_fct_start == NULL) __nss_shadow_nonlocal_lookup(&spent_startp, spent_fct_name, &spent_fct_start); spent_nip = spent_startp; spent_fct.ptr = spent_fct_start; return NSS_STATUS_SUCCESS; } enum nss_status _nss_nonlocal_endspent(void) { enum nss_status status; const struct walk_nss w = { .lookup = &__nss_shadow_nonlocal_lookup, .fct_name = "endspent", .status = &status }; const __typeof__(&_nss_nonlocal_endspent) self = NULL; spent_nip = NULL; #define args () #include "walk_nss.h" #undef args return status; } enum nss_status _nss_nonlocal_getspent_r(struct spwd *pwd, char *buffer, size_t buflen, int *errnop) { enum nss_status status; if (spent_nip == NULL) { status = _nss_nonlocal_setspent(0); if (status != NSS_STATUS_SUCCESS) return status; } do { if (spent_fct.ptr == NULL) status = NSS_STATUS_UNAVAIL; else status = DL_CALL_FCT(spent_fct.l, (pwd, buffer, buflen, errnop)); if (status == NSS_STATUS_TRYAGAIN && *errnop == ERANGE) return status; if (status == NSS_STATUS_SUCCESS) return NSS_STATUS_SUCCESS; } while (__nss_next(&spent_nip, spent_fct_name, &spent_fct.ptr, status, 0) == 0); spent_nip = NULL; return NSS_STATUS_NOTFOUND; } enum nss_status _nss_nonlocal_getspnam_r(const char *name, struct spwd *pwd, char *buffer, size_t buflen, int *errnop) { enum nss_status status; const struct walk_nss w = { .lookup = __nss_shadow_nonlocal_lookup, .fct_name = "getspnam_r", .status = &status, .errnop = errnop }; const __typeof__(&_nss_nonlocal_getspnam_r) self = NULL; #define args (name, pwd, buffer, buflen, errnop) #include "walk_nss.h" #undef args if (status != NSS_STATUS_SUCCESS) return status; if (strcmp(name, pwd->sp_namp) != 0) { syslog(LOG_ERR, "nss_nonlocal: discarding shadow %s from lookup for shadow %s\n", pwd->sp_namp, name); return NSS_STATUS_NOTFOUND; } return NSS_STATUS_SUCCESS; }
int internal_function __internal_getnetgrent_r (char **hostp, char **userp, char **domainp, struct __netgrent *datap, char *buffer, size_t buflen, int *errnop) { enum nss_status (*fct) (struct __netgrent *, char *, size_t, int *); /* Initialize status to return if no more functions are found. */ enum nss_status status = NSS_STATUS_NOTFOUND; /* Run through available functions, starting with the same function last run. We will repeat each function as long as it succeeds, and then go on to the next service action. */ int no_more = datap->nip == NULL; if (! no_more) { #ifdef USE_NSCD /* This bogus function pointer is a special marker left by __nscd_setnetgrent to tell us to use the data it left before considering any modules. */ if (datap->nip == (service_user *) -1l) fct = nscd_getnetgrent; else #endif { fct = __nss_lookup_function (datap->nip, "getnetgrent_r"); no_more = fct == NULL; } while (! no_more) { status = DL_CALL_FCT (*fct, (datap, buffer, buflen, &errno)); if (status == NSS_STATUS_RETURN /* The service returned a NOTFOUND, but there are more groups that we need to resolve before we give up. */ || (status == NSS_STATUS_NOTFOUND && datap->needed_groups != NULL)) { /* This was the last one for this group. Look at next group if available. */ int found = 0; while (datap->needed_groups != NULL && ! found) { struct name_list *tmp = datap->needed_groups; datap->needed_groups = datap->needed_groups->next; tmp->next = datap->known_groups; datap->known_groups = tmp; found = __internal_setnetgrent_reuse (datap->known_groups->name, datap, errnop); } if (found && datap->nip != NULL) { fct = __nss_lookup_function (datap->nip, "getnetgrent_r"); if (fct != NULL) continue; } } else if (status == NSS_STATUS_SUCCESS && datap->type == group_val) { /* The last entry was a name of another netgroup. */ struct name_list *namep; /* Ignore if we've seen the name before. */ for (namep = datap->known_groups; namep != NULL; namep = namep->next) if (strcmp (datap->val.group, namep->name) == 0) break; if (namep == NULL) for (namep = datap->needed_groups; namep != NULL; namep = namep->next) if (strcmp (datap->val.group, namep->name) == 0) break; if (namep != NULL) /* Really ignore. */ continue; size_t group_len = strlen (datap->val.group) + 1; namep = (struct name_list *) malloc (sizeof (struct name_list) + group_len); if (namep == NULL) /* We are out of memory. */ status = NSS_STATUS_RETURN; else { namep->next = datap->needed_groups; memcpy (namep->name, datap->val.group, group_len); datap->needed_groups = namep; /* And get the next entry. */ continue; } } break; } } if (status == NSS_STATUS_SUCCESS) { *hostp = (char *) datap->val.triple.host; *userp = (char *) datap->val.triple.user; *domainp = (char *) datap->val.triple.domain; } return status == NSS_STATUS_SUCCESS ? 1 : 0; }
void query_forward(netresolve_query_t query, char **settings) { const char *node = netresolve_backend_get_nodename(query); int family = netresolve_backend_get_family(query); struct priv_nss priv = { 0 }; initialize(&priv, query, settings); if (!priv.dl_handle) { netresolve_backend_failed(query); return; } if (priv.getaddrinfo) { const char *service = netresolve_backend_get_servname(query); struct addrinfo hints = netresolve_backend_get_addrinfo_hints(query); int status; struct addrinfo *result; int32_t ttl; status = DL_CALL_FCT(priv.getaddrinfo, (NULL, node, service, &hints, &result, &ttl)); netresolve_backend_apply_addrinfo(query, status, result, ttl); if (status == 0) freeaddrinfo(result); } else if (node && priv.gethostbyname4_r && family == AF_UNSPEC) { char buffer[SIZE] = { 0 }; enum nss_status status; /* The libnss_files.so plugin checks the gaih_addrtuple pointer for being * NULL and fails badly otherwise. Whether such behavior is correct * remains a question. */ struct gaih_addrtuple *result = NULL; int errnop, h_errnop; int32_t ttl = 0; /* Without this, libnss_files won't resolve using multiple records * in /etc/hosts, e.g. won't return both IPv4 and IPv6 for "localhost" * even when /etc/hosts is configured correctly. * * See relevant files in glibc sources: * - nss_files/files-hosts.c * - resolv/res_hconf.h */ extern struct { int initialized; int unused1; int unused2[4]; int num_trimdomains; const char *trimdomain[4]; unsigned int flags; } _res_hconf; _res_hconf.flags = 0x10; status = DL_CALL_FCT(priv.gethostbyname4_r, (node, &result, buffer, sizeof buffer, &errnop, &h_errnop, &ttl)); netresolve_backend_apply_addrtuple(query, status, result, ttl); } else if (node && (priv.gethostbyname3_r || priv.gethostbyname2_r)) { char buffer4[SIZE] = { 0 }; char buffer6[SIZE] = { 0 }; int status4 = NSS_STATUS_NOTFOUND, status6 = NSS_STATUS_NOTFOUND; struct hostent he4, he6; int errnop, h_errnop; int32_t ttl4 = 0; int32_t ttl6 = 0; char *canonname4 = NULL; char *canonname6 = NULL; if (priv.gethostbyname3_r) { if (family == AF_INET || family == AF_UNSPEC) status4 = DL_CALL_FCT(priv.gethostbyname3_r, (node, AF_INET, &he4, buffer4, sizeof buffer4, &errnop, &h_errnop, &ttl4, &canonname4)); if (family == AF_INET6 || family == AF_UNSPEC) status6 = DL_CALL_FCT(priv.gethostbyname3_r, (node, AF_INET6, &he6, buffer6, sizeof buffer6, &errnop, &h_errnop, &ttl6, &canonname6)); } else { if (family == AF_INET || family == AF_UNSPEC) status4 = DL_CALL_FCT(priv.gethostbyname2_r, (node, AF_INET, &he4, buffer4, sizeof buffer4, &errnop, &h_errnop)); if (family == AF_INET6 || family == AF_UNSPEC) status6 = DL_CALL_FCT(priv.gethostbyname2_r, (node, AF_INET6, &he6, buffer6, sizeof buffer6, &errnop, &h_errnop)); } if (combine_statuses(status4, status6) == NSS_STATUS_SUCCESS) { if (status6 == NSS_STATUS_SUCCESS && canonname6) netresolve_backend_set_canonical_name(query, canonname6); else if (status4 == NSS_STATUS_SUCCESS && canonname4) netresolve_backend_set_canonical_name(query, canonname4); if (status6 == NSS_STATUS_SUCCESS) netresolve_backend_apply_hostent(query, &he6, 0, 0, 0, 0, 0, ttl4); if (status4 == NSS_STATUS_SUCCESS) netresolve_backend_apply_hostent(query, &he4, 0, 0, 0, 0, 0, ttl6); netresolve_backend_finished(query); } else netresolve_backend_failed(query); } else if (node && priv.gethostbyname_r) { char buffer[SIZE]; int errnop, h_errnop; struct hostent he; enum nss_status status; status = DL_CALL_FCT(priv.gethostbyname_r, (node, &he, buffer, sizeof buffer, &errnop, &h_errnop)); if (status == NSS_STATUS_SUCCESS) { netresolve_backend_apply_hostent(query, &he, 0, 0, 0, 0, 0, 0); netresolve_backend_finished(query); } else netresolve_backend_failed(query); } else { debug("no suitable backend found"); netresolve_backend_failed(query); } finalize(&priv); }
int FUNCTION_NAME (struct __gconv_step *step, struct __gconv_step_data *data, const unsigned char **inptrp, const unsigned char *inend, unsigned char **outbufstart, size_t *irreversible, int do_flush, int consume_incomplete) { struct __gconv_step *next_step = step + 1; struct __gconv_step_data *next_data = data + 1; __gconv_fct fct = NULL; int status; if ((data->__flags & __GCONV_IS_LAST) == 0) { fct = next_step->__fct; #ifdef PTR_DEMANGLE if (next_step->__shlib_handle != NULL) PTR_DEMANGLE (fct); #endif } /* If the function is called with no input this means we have to reset to the initial state. The possibly partly converted input is dropped. */ if (__builtin_expect (do_flush, 0)) { /* This should never happen during error handling. */ assert (outbufstart == NULL); status = __GCONV_OK; #ifdef EMIT_SHIFT_TO_INIT if (do_flush == 1) { /* We preserve the initial values of the pointer variables. */ unsigned char *outbuf = data->__outbuf; unsigned char *outstart = outbuf; unsigned char *outend = data->__outbufend; # ifdef PREPARE_LOOP PREPARE_LOOP # endif # ifdef SAVE_RESET_STATE SAVE_RESET_STATE (1); # endif /* Emit the escape sequence to reset the state. */ EMIT_SHIFT_TO_INIT; /* Call the steps down the chain if there are any but only if we successfully emitted the escape sequence. This should only fail if the output buffer is full. If the input is invalid it should be discarded since the user wants to start from a clean state. */ if (status == __GCONV_OK) { if (data->__flags & __GCONV_IS_LAST) /* Store information about how many bytes are available. */ data->__outbuf = outbuf; else { /* Write out all output which was produced. */ if (outbuf > outstart) { const unsigned char *outerr = outstart; int result; result = DL_CALL_FCT (fct, (next_step, next_data, &outerr, outbuf, NULL, irreversible, 0, consume_incomplete)); if (result != __GCONV_EMPTY_INPUT) { if (__builtin_expect (outerr != outbuf, 0)) { /* We have a problem. Undo the conversion. */ outbuf = outstart; /* Restore the state. */ # ifdef SAVE_RESET_STATE SAVE_RESET_STATE (0); # endif } /* Change the status. */ status = result; } } if (status == __GCONV_OK) /* Now flush the remaining steps. */ status = DL_CALL_FCT (fct, (next_step, next_data, NULL, NULL, NULL, irreversible, 1, consume_incomplete)); } } } else #endif { /* Clear the state object. There might be bytes in there from previous calls with CONSUME_INCOMPLETE == 1. But don't emit escape sequences. */ memset (data->__statep, '\0', sizeof (*data->__statep)); if (! (data->__flags & __GCONV_IS_LAST)) /* Now flush the remaining steps. */ status = DL_CALL_FCT (fct, (next_step, next_data, NULL, NULL, NULL, irreversible, do_flush, consume_incomplete)); } } else { /* We preserve the initial values of the pointer variables. */ const unsigned char *inptr = *inptrp; unsigned char *outbuf = (__builtin_expect (outbufstart == NULL, 1) ? data->__outbuf : *outbufstart); unsigned char *outend = data->__outbufend; unsigned char *outstart; /* This variable is used to count the number of characters we actually converted. */ size_t lirreversible = 0; size_t *lirreversiblep = irreversible ? &lirreversible : NULL; /* The following assumes that encodings, which have a variable length what might unalign a buffer even though it is a aligned in the beginning, either don't have the minimal number of bytes as a divisor of the maximum length or have a minimum length of 1. This is true for all known and supported encodings. We use && instead of || to combine the subexpression for the FROM encoding and for the TO encoding, because usually one of them is INTERNAL, for which the subexpression evaluates to 1, but INTERNAL buffers are always aligned correctly. */ #define POSSIBLY_UNALIGNED \ (!defined _STRING_ARCH_unaligned \ && (((FROM_LOOP_MIN_NEEDED_FROM != 1 \ && FROM_LOOP_MAX_NEEDED_FROM % FROM_LOOP_MIN_NEEDED_FROM == 0) \ && (FROM_LOOP_MIN_NEEDED_TO != 1 \ && FROM_LOOP_MAX_NEEDED_TO % FROM_LOOP_MIN_NEEDED_TO == 0)) \ || ((TO_LOOP_MIN_NEEDED_FROM != 1 \ && TO_LOOP_MAX_NEEDED_FROM % TO_LOOP_MIN_NEEDED_FROM == 0) \ && (TO_LOOP_MIN_NEEDED_TO != 1 \ && TO_LOOP_MAX_NEEDED_TO % TO_LOOP_MIN_NEEDED_TO == 0)))) #if POSSIBLY_UNALIGNED int unaligned; # define GEN_unaligned(name) GEN_unaligned2 (name) # define GEN_unaligned2(name) name##_unaligned #else # define unaligned 0 #endif #ifdef PREPARE_LOOP PREPARE_LOOP #endif #if FROM_LOOP_MAX_NEEDED_FROM > 1 || TO_LOOP_MAX_NEEDED_FROM > 1 /* If the function is used to implement the mb*towc*() or wc*tomb*() functions we must test whether any bytes from the last call are stored in the `state' object. */ if (((FROM_LOOP_MAX_NEEDED_FROM > 1 && TO_LOOP_MAX_NEEDED_FROM > 1) || (FROM_LOOP_MAX_NEEDED_FROM > 1 && FROM_DIRECTION) || (TO_LOOP_MAX_NEEDED_FROM > 1 && !FROM_DIRECTION)) && consume_incomplete && (data->__statep->__count & 7) != 0) { /* Yep, we have some bytes left over. Process them now. But this must not happen while we are called from an error handler. */ assert (outbufstart == NULL); # if FROM_LOOP_MAX_NEEDED_FROM > 1 if (TO_LOOP_MAX_NEEDED_FROM == 1 || FROM_DIRECTION) status = SINGLE(FROM_LOOP) (step, data, inptrp, inend, &outbuf, outend, lirreversiblep EXTRA_LOOP_ARGS); # endif # if !ONE_DIRECTION # if FROM_LOOP_MAX_NEEDED_FROM > 1 && TO_LOOP_MAX_NEEDED_FROM > 1 else # endif # if TO_LOOP_MAX_NEEDED_FROM > 1 status = SINGLE(TO_LOOP) (step, data, inptrp, inend, &outbuf, outend, lirreversiblep EXTRA_LOOP_ARGS); # endif # endif if (__builtin_expect (status, __GCONV_OK) != __GCONV_OK) return status; } #endif #if POSSIBLY_UNALIGNED unaligned = ((FROM_DIRECTION && ((uintptr_t) inptr % FROM_LOOP_MIN_NEEDED_FROM != 0 || ((data->__flags & __GCONV_IS_LAST) && (uintptr_t) outbuf % FROM_LOOP_MIN_NEEDED_TO != 0))) || (!FROM_DIRECTION && (((data->__flags & __GCONV_IS_LAST) && (uintptr_t) outbuf % TO_LOOP_MIN_NEEDED_TO != 0) || (uintptr_t) inptr % TO_LOOP_MIN_NEEDED_FROM != 0))); #endif while (1) { struct __gconv_trans_data *trans; /* Remember the start value for this round. */ inptr = *inptrp; /* The outbuf buffer is empty. */ outstart = outbuf; #ifdef SAVE_RESET_STATE SAVE_RESET_STATE (1); #endif if (__builtin_expect (!unaligned, 1)) { if (FROM_DIRECTION) /* Run the conversion loop. */ status = FROM_LOOP (step, data, inptrp, inend, &outbuf, outend, lirreversiblep EXTRA_LOOP_ARGS); else /* Run the conversion loop. */ status = TO_LOOP (step, data, inptrp, inend, &outbuf, outend, lirreversiblep EXTRA_LOOP_ARGS); } #if POSSIBLY_UNALIGNED else { if (FROM_DIRECTION) /* Run the conversion loop. */ status = GEN_unaligned (FROM_LOOP) (step, data, inptrp, inend, &outbuf, outend, lirreversiblep EXTRA_LOOP_ARGS); else /* Run the conversion loop. */ status = GEN_unaligned (TO_LOOP) (step, data, inptrp, inend, &outbuf, outend, lirreversiblep EXTRA_LOOP_ARGS); } #endif /* If we were called as part of an error handling module we don't do anything else here. */ if (__builtin_expect (outbufstart != NULL, 0)) { *outbufstart = outbuf; return status; } /* Give the transliteration module the chance to store the original text and the result in case it needs a context. */ for (trans = data->__trans; trans != NULL; trans = trans->__next) if (trans->__trans_context_fct != NULL) DL_CALL_FCT (trans->__trans_context_fct, (trans->__data, inptr, *inptrp, outstart, outbuf)); /* We finished one use of the loops. */ ++data->__invocation_counter; /* If this is the last step leave the loop, there is nothing we can do. */ if (__builtin_expect (data->__flags & __GCONV_IS_LAST, 0)) { /* Store information about how many bytes are available. */ data->__outbuf = outbuf; /* Remember how many non-identical characters we converted in a irreversible way. */ *irreversible += lirreversible; break; } /* Write out all output which was produced. */ if (__builtin_expect (outbuf > outstart, 1)) { const unsigned char *outerr = data->__outbuf; int result; result = DL_CALL_FCT (fct, (next_step, next_data, &outerr, outbuf, NULL, irreversible, 0, consume_incomplete)); if (result != __GCONV_EMPTY_INPUT) { if (__builtin_expect (outerr != outbuf, 0)) { #ifdef RESET_INPUT_BUFFER RESET_INPUT_BUFFER; #else /* We have a problem in one of the functions below. Undo the conversion upto the error point. */ size_t nstatus; /* Reload the pointers. */ *inptrp = inptr; outbuf = outstart; /* Restore the state. */ # ifdef SAVE_RESET_STATE SAVE_RESET_STATE (0); # endif if (__builtin_expect (!unaligned, 1)) { if (FROM_DIRECTION) /* Run the conversion loop. */ nstatus = FROM_LOOP (step, data, inptrp, inend, &outbuf, outerr, lirreversiblep EXTRA_LOOP_ARGS); else /* Run the conversion loop. */ nstatus = TO_LOOP (step, data, inptrp, inend, &outbuf, outerr, lirreversiblep EXTRA_LOOP_ARGS); } # if POSSIBLY_UNALIGNED else { if (FROM_DIRECTION) /* Run the conversion loop. */ nstatus = GEN_unaligned (FROM_LOOP) (step, data, inptrp, inend, &outbuf, outerr, lirreversiblep EXTRA_LOOP_ARGS); else /* Run the conversion loop. */ nstatus = GEN_unaligned (TO_LOOP) (step, data, inptrp, inend, &outbuf, outerr, lirreversiblep EXTRA_LOOP_ARGS); } # endif /* We must run out of output buffer space in this rerun. */ assert (outbuf == outerr); assert (nstatus == __GCONV_FULL_OUTPUT); /* If we haven't consumed a single byte decrement the invocation counter. */ if (__builtin_expect (outbuf == outstart, 0)) --data->__invocation_counter; #endif /* reset input buffer */ } /* Change the status. */ status = result; } else /* All the output is consumed, we can make another run if everything was ok. */ if (status == __GCONV_FULL_OUTPUT) { status = __GCONV_OK; outbuf = data->__outbuf; } } if (status != __GCONV_OK) break; /* Reset the output buffer pointer for the next round. */ outbuf = data->__outbuf; } #ifdef END_LOOP END_LOOP #endif /* If we are supposed to consume all character store now all of the remaining characters in the `state' object. */ #if FROM_LOOP_MAX_NEEDED_FROM > 1 || TO_LOOP_MAX_NEEDED_FROM > 1 if (((FROM_LOOP_MAX_NEEDED_FROM > 1 && TO_LOOP_MAX_NEEDED_FROM > 1) || (FROM_LOOP_MAX_NEEDED_FROM > 1 && FROM_DIRECTION) || (TO_LOOP_MAX_NEEDED_FROM > 1 && !FROM_DIRECTION)) && __builtin_expect (consume_incomplete, 0) && status == __GCONV_INCOMPLETE_INPUT) { # ifdef STORE_REST mbstate_t *state = data->__statep; STORE_REST # else /* Make sure the remaining bytes fit into the state objects buffer. */ assert (inend - *inptrp < 4); size_t cnt; for (cnt = 0; *inptrp < inend; ++cnt) data->__statep->__value.__wchb[cnt] = *(*inptrp)++; data->__statep->__count &= ~7; data->__statep->__count |= cnt; # endif } #endif #undef unaligned #undef POSSIBLY_UNALIGNED } return status; }
wint_t __btowc (int c) { const struct gconv_fcts *fcts; /* If the parameter does not fit into one byte or it is the EOF value we can give the answer now. */ if (c < SCHAR_MIN || c > UCHAR_MAX || c == EOF) return WEOF; /* We know that only ASCII compatible encodings are used for the locale and that the wide character encoding is ISO 10646. */ if (isascii (c)) return (wint_t) c; /* Get the conversion functions. */ fcts = get_gconv_fcts (_NL_CURRENT_DATA (LC_CTYPE)); __gconv_btowc_fct btowc_fct = fcts->towc->__btowc_fct; #ifdef PTR_DEMANGLE if (fcts->towc->__shlib_handle != NULL) PTR_DEMANGLE (btowc_fct); #endif if (__builtin_expect (fcts->towc_nsteps == 1, 1) && __builtin_expect (btowc_fct != NULL, 1)) { /* Use the shortcut function. */ return DL_CALL_FCT (btowc_fct, (fcts->towc, (unsigned char) c)); } else { /* Fall back to the slow but generic method. */ wchar_t result; struct __gconv_step_data data; unsigned char inbuf[1]; const unsigned char *inptr = inbuf; size_t dummy; int status; /* Tell where we want the result. */ data.__outbuf = (unsigned char *) &result; data.__outbufend = data.__outbuf + sizeof (wchar_t); data.__invocation_counter = 0; data.__internal_use = 1; data.__flags = __GCONV_IS_LAST; data.__statep = &data.__state; /* Make sure we start in the initial state. */ memset (&data.__state, '\0', sizeof (mbstate_t)); /* Create the input string. */ inbuf[0] = c; __gconv_fct fct = fcts->towc->__fct; #ifdef PTR_DEMANGLE if (fcts->towc->__shlib_handle != NULL) PTR_DEMANGLE (fct); #endif status = DL_CALL_FCT (fct, (fcts->towc, &data, &inptr, inptr + 1, NULL, &dummy, 0, 1)); if (status != __GCONV_OK && status != __GCONV_FULL_OUTPUT && status != __GCONV_EMPTY_INPUT) /* The conversion failed. */ result = WEOF; return result; } }
size_t mbrtoc16 (char16_t *pc16, const char *s, size_t n, mbstate_t *ps) { if (ps == NULL) ps = &state; /* The standard text does not say that S being NULL means the state is reset even if the second half of a surrogate still have to be returned. In fact, the error code description indicates otherwise. Therefore always first try to return a second half. */ if (ps->__count & 0x80000000) { /* We have to return the second word for a surrogate. */ ps->__count &= 0x7fffffff; *pc16 = ps->__value.__wch; ps->__value.__wch = L'\0'; return (size_t) -3; } wchar_t wc; struct __gconv_step_data data; int status; size_t result; size_t dummy; const unsigned char *inbuf, *endbuf; unsigned char *outbuf = (unsigned char *) &wc; const struct gconv_fcts *fcts; /* Set information for this step. */ data.__invocation_counter = 0; data.__internal_use = 1; data.__flags = __GCONV_IS_LAST; data.__statep = ps; data.__trans = NULL; /* A first special case is if S is NULL. This means put PS in the initial state. */ if (s == NULL) { pc16 = NULL; s = ""; n = 1; } /* Tell where we want the result. */ data.__outbuf = outbuf; data.__outbufend = outbuf + sizeof (wchar_t); /* Get the conversion functions. */ fcts = get_gconv_fcts (_NL_CURRENT_DATA (LC_CTYPE)); /* Do a normal conversion. */ inbuf = (const unsigned char *) s; endbuf = inbuf + n; if (__glibc_unlikely (endbuf < inbuf)) { endbuf = (const unsigned char *) ~(uintptr_t) 0; if (endbuf == inbuf) goto ilseq; } __gconv_fct fct = fcts->towc->__fct; #ifdef PTR_DEMANGLE if (fcts->towc->__shlib_handle != NULL) PTR_DEMANGLE (fct); #endif status = DL_CALL_FCT (fct, (fcts->towc, &data, &inbuf, endbuf, NULL, &dummy, 0, 1)); /* There must not be any problems with the conversion but illegal input characters. The output buffer must be large enough, otherwise the definition of MB_CUR_MAX is not correct. All the other possible errors also must not happen. */ assert (status == __GCONV_OK || status == __GCONV_EMPTY_INPUT || status == __GCONV_ILLEGAL_INPUT || status == __GCONV_INCOMPLETE_INPUT || status == __GCONV_FULL_OUTPUT); if (status == __GCONV_OK || status == __GCONV_EMPTY_INPUT || status == __GCONV_FULL_OUTPUT) { result = inbuf - (const unsigned char *) s; if (wc < 0x10000) { if (pc16 != NULL) *pc16 = wc; if (data.__outbuf != outbuf && wc == L'\0') { /* The converted character is the NUL character. */ assert (__mbsinit (data.__statep)); result = 0; } } else { /* This is a surrogate. */ if (pc16 != NULL) *pc16 = 0xd7c0 + (wc >> 10); ps->__count |= 0x80000000; ps->__value.__wch = 0xdc00 + (wc & 0x3ff); } }
enum nss_status check_nonlocal_uid(const char *user, uid_t uid, int *errnop) { enum nss_status status; struct passwd pwbuf; char *buf; size_t buflen = sysconf(_SC_GETPW_R_SIZE_MAX); const struct walk_nss w = { .lookup = &__nss_passwd_lookup, .fct_name = "getpwuid_r", .status = &status, .errnop = errnop, .buf = &buf, .buflen = &buflen }; const __typeof__(&_nss_nonlocal_getpwuid_r) self = &_nss_nonlocal_getpwuid_r; #define args (uid, &pwbuf, buf, buflen, errnop) #include "walk_nss.h" #undef args if (status == NSS_STATUS_SUCCESS) { syslog(LOG_ERR, "nss_nonlocal: possible spoofing attack: non-local user %s has same UID as local user %s!\n", user, pwbuf.pw_name); free(buf); status = NSS_STATUS_NOTFOUND; } else if (status != NSS_STATUS_TRYAGAIN) { status = NSS_STATUS_SUCCESS; } return status; } enum nss_status check_nonlocal_passwd(const char *user, struct passwd *pwd, int *errnop) { enum nss_status status = NSS_STATUS_SUCCESS; int old_errno = errno; char *end; unsigned long uid; errno = 0; uid = strtoul(pwd->pw_name, &end, 10); if (errno == 0 && *end == '\0' && (uid_t)uid == uid) { errno = old_errno; status = check_nonlocal_uid(user, uid, errnop); } else { errno = old_errno; } if (status != NSS_STATUS_SUCCESS) return status; return check_nonlocal_uid(user, pwd->pw_uid, errnop); } enum nss_status check_nonlocal_user(const char *user, int *errnop) { enum nss_status status; struct passwd pwbuf; char *buf; size_t buflen = sysconf(_SC_GETPW_R_SIZE_MAX); const struct walk_nss w = { .lookup = __nss_passwd_lookup, .fct_name = "getpwnam_r", .status = &status, .errnop = errnop, .buf = &buf, .buflen = &buflen }; const __typeof__(&_nss_nonlocal_getpwnam_r) self = &_nss_nonlocal_getpwnam_r; #define args (user, &pwbuf, buf, buflen, errnop) #include "walk_nss.h" #undef args if (status == NSS_STATUS_SUCCESS) { free(buf); status = NSS_STATUS_NOTFOUND; } else if (status != NSS_STATUS_TRYAGAIN) { status = NSS_STATUS_SUCCESS; } return status; } enum nss_status get_nonlocal_passwd(const char *name, struct passwd *pwd, char **buffer, int *errnop) { enum nss_status status; size_t buflen = sysconf(_SC_GETPW_R_SIZE_MAX); const struct walk_nss w = { .lookup = __nss_passwd_nonlocal_lookup, .fct_name = "getpwnam_r", .status = &status, .errnop = errnop, .buf = buffer, .buflen = &buflen }; const __typeof__(&_nss_nonlocal_getpwnam_r) self = NULL; #define args (name, pwd, *buffer, buflen, errnop) #include "walk_nss.h" #undef args return status; } static bool pwent_initialized = false; static service_user *pwent_startp, *pwent_nip; static void *pwent_fct_start; static union { enum nss_status (*l)(struct passwd *pwd, char *buffer, size_t buflen, int *errnop); void *ptr; } pwent_fct; static const char *pwent_fct_name = "getpwent_r"; enum nss_status _nss_nonlocal_setpwent(int stayopen) { enum nss_status status; const struct walk_nss w = { .lookup = &__nss_passwd_nonlocal_lookup, .fct_name = "setpwent", .status = &status }; const __typeof__(&_nss_nonlocal_setpwent) self = NULL; #define args (stayopen) #include "walk_nss.h" #undef args if (status != NSS_STATUS_SUCCESS) return status; if (!pwent_initialized) { __nss_passwd_nonlocal_lookup(&pwent_startp, pwent_fct_name, &pwent_fct_start); __sync_synchronize(); pwent_initialized = true; } pwent_nip = pwent_startp; pwent_fct.ptr = pwent_fct_start; return NSS_STATUS_SUCCESS; } enum nss_status _nss_nonlocal_endpwent(void) { enum nss_status status; const struct walk_nss w = { .lookup = &__nss_passwd_nonlocal_lookup, .fct_name = "endpwent", .status = &status, .all_values = 1, }; const __typeof__(&_nss_nonlocal_endpwent) self = NULL; pwent_nip = NULL; #define args () #include "walk_nss.h" #undef args return status; } enum nss_status _nss_nonlocal_getpwent_r(struct passwd *pwd, char *buffer, size_t buflen, int *errnop) { enum nss_status status; char *nonlocal_ignore = getenv(NONLOCAL_IGNORE_ENV); if (nonlocal_ignore != NULL && nonlocal_ignore[0] != '\0') return NSS_STATUS_UNAVAIL; if (pwent_nip == NULL) { status = _nss_nonlocal_setpwent(0); if (status != NSS_STATUS_SUCCESS) return status; } do { if (pwent_fct.ptr == NULL) status = NSS_STATUS_UNAVAIL; else { int nonlocal_errno; do status = DL_CALL_FCT(pwent_fct.l, (pwd, buffer, buflen, errnop)); while (status == NSS_STATUS_SUCCESS && check_nonlocal_passwd(pwd->pw_name, pwd, &nonlocal_errno) != NSS_STATUS_SUCCESS); } if (status == NSS_STATUS_TRYAGAIN && *errnop == ERANGE) return status; if (status == NSS_STATUS_SUCCESS) return NSS_STATUS_SUCCESS; } while (__nss_next(&pwent_nip, pwent_fct_name, &pwent_fct.ptr, status, 0) == 0); pwent_nip = NULL; return NSS_STATUS_NOTFOUND; } enum nss_status _nss_nonlocal_getpwnam_r(const char *name, struct passwd *pwd, char *buffer, size_t buflen, int *errnop) { enum nss_status status; int group_errno; const struct walk_nss w = { .lookup = __nss_passwd_nonlocal_lookup, .fct_name = "getpwnam_r", .status = &status, .errnop = errnop }; const __typeof__(&_nss_nonlocal_getpwnam_r) self = NULL; char *nonlocal_ignore = getenv(NONLOCAL_IGNORE_ENV); if (nonlocal_ignore != NULL && nonlocal_ignore[0] != '\0') return NSS_STATUS_UNAVAIL; #define args (name, pwd, buffer, buflen, errnop) #include "walk_nss.h" #undef args if (status != NSS_STATUS_SUCCESS) return status; if (strcmp(name, pwd->pw_name) != 0) { syslog(LOG_ERR, "nss_nonlocal: discarding user %s from lookup for user %s\n", pwd->pw_name, name); return NSS_STATUS_NOTFOUND; } status = check_nonlocal_passwd(name, pwd, errnop); if (status != NSS_STATUS_SUCCESS) return status; if (check_nonlocal_gid(name, NULL, pwd->pw_gid, &group_errno) != NSS_STATUS_SUCCESS) pwd->pw_gid = 65534 /* nogroup */; return NSS_STATUS_SUCCESS; } enum nss_status _nss_nonlocal_getpwuid_r(uid_t uid, struct passwd *pwd, char *buffer, size_t buflen, int *errnop) { enum nss_status status; int group_errno; const struct walk_nss w = { .lookup = &__nss_passwd_nonlocal_lookup, .fct_name = "getpwuid_r", .status = &status, .errnop = errnop }; const __typeof__(&_nss_nonlocal_getpwuid_r) self = NULL; char *nonlocal_ignore = getenv(NONLOCAL_IGNORE_ENV); if (nonlocal_ignore != NULL && nonlocal_ignore[0] != '\0') return NSS_STATUS_UNAVAIL; #define args (uid, pwd, buffer, buflen, errnop) #include "walk_nss.h" #undef args if (status != NSS_STATUS_SUCCESS) return status; if (uid != pwd->pw_uid) { syslog(LOG_ERR, "nss_nonlocal: discarding uid %d from lookup for uid %d\n", pwd->pw_uid, uid); return NSS_STATUS_NOTFOUND; } status = check_nonlocal_passwd(pwd->pw_name, pwd, errnop); if (status != NSS_STATUS_SUCCESS) return status; if (check_nonlocal_gid(pwd->pw_name, NULL, pwd->pw_gid, &group_errno) != NSS_STATUS_SUCCESS) pwd->pw_gid = 65534 /* nogroup */; return NSS_STATUS_SUCCESS; }
int internal_function __gconv (__gconv_t cd, const unsigned char **inbuf, const unsigned char *inbufend, unsigned char **outbuf, unsigned char *outbufend, size_t *irreversible) { size_t last_step; int result; if (cd == (__gconv_t) -1L) return __GCONV_ILLEGAL_DESCRIPTOR; last_step = cd->__nsteps - 1; assert (irreversible != NULL); *irreversible = 0; cd->__data[last_step].__outbuf = outbuf != NULL ? *outbuf : NULL; cd->__data[last_step].__outbufend = outbufend; __gconv_fct fct = cd->__steps->__fct; #ifdef PTR_DEMANGLE if (cd->__steps->__shlib_handle != NULL) PTR_DEMANGLE (fct); #endif if (inbuf == NULL || *inbuf == NULL) { /* We just flush. */ result = DL_CALL_FCT (fct, (cd->__steps, cd->__data, NULL, NULL, NULL, irreversible, cd->__data[last_step].__outbuf == NULL ? 2 : 1, 0)); /* If the flush was successful clear the rest of the state. */ if (result == __GCONV_OK) for (size_t cnt = 0; cnt <= last_step; ++cnt) cd->__data[cnt].__invocation_counter = 0; } else { const unsigned char *last_start; assert (outbuf != NULL && *outbuf != NULL); do { last_start = *inbuf; result = DL_CALL_FCT (fct, (cd->__steps, cd->__data, inbuf, inbufend, NULL, irreversible, 0, 0)); } while (result == __GCONV_EMPTY_INPUT && last_start != *inbuf && *inbuf + cd->__steps->__min_needed_from <= inbufend); } if (outbuf != NULL && *outbuf != NULL) *outbuf = cd->__data[last_step].__outbuf; return result; }
/* Test whether given (host,user,domain) triple is in NETGROUP. */ int innetgr (const char *netgroup, const char *host, const char *user, const char *domain) { #ifdef USE_NSCD if (__nss_not_use_nscd_netgroup > 0 && ++__nss_not_use_nscd_netgroup > NSS_NSCD_RETRY) __nss_not_use_nscd_netgroup = 0; if (!__nss_not_use_nscd_netgroup && !__nss_database_custom[NSS_DBSIDX_netgroup]) { int result = __nscd_innetgr (netgroup, host, user, domain); if (result >= 0) return result; } #endif union { enum nss_status (*f) (const char *, struct __netgrent *); void *ptr; } setfct; void (*endfct) (struct __netgrent *); int (*getfct) (struct __netgrent *, char *, size_t, int *); struct __netgrent entry; int result = 0; const char *current_group = netgroup; memset (&entry, '\0', sizeof (entry)); /* Walk through the services until we found an answer or we shall not work further. We can do some optimization here. Since all services must provide the `setnetgrent' function we can do all the work during one walk through the service list. */ while (1) { int no_more = setup (&setfct.ptr, &entry.nip); while (! no_more) { assert (entry.data == NULL); /* Open netgroup. */ enum nss_status status = DL_CALL_FCT (*setfct.f, (current_group, &entry)); if (status == NSS_STATUS_SUCCESS && (getfct = __nss_lookup_function (entry.nip, "getnetgrent_r")) != NULL) { char buffer[1024]; while (DL_CALL_FCT (*getfct, (&entry, buffer, sizeof buffer, &errno)) == NSS_STATUS_SUCCESS) { if (entry.type == group_val) { /* Make sure we haven't seen the name before. */ struct name_list *namep; for (namep = entry.known_groups; namep != NULL; namep = namep->next) if (strcmp (entry.val.group, namep->name) == 0) break; if (namep == NULL) for (namep = entry.needed_groups; namep != NULL; namep = namep->next) if (strcmp (entry.val.group, namep->name) == 0) break; if (namep == NULL && strcmp (netgroup, entry.val.group) != 0) { size_t group_len = strlen (entry.val.group) + 1; namep = (struct name_list *) malloc (sizeof (*namep) + group_len); if (namep == NULL) { /* Out of memory, simply return. */ result = -1; break; } namep->next = entry.needed_groups; memcpy (namep->name, entry.val.group, group_len); entry.needed_groups = namep; } } else { if ((entry.val.triple.host == NULL || host == NULL || __strcasecmp (entry.val.triple.host, host) == 0) && (entry.val.triple.user == NULL || user == NULL || strcmp (entry.val.triple.user, user) == 0) && (entry.val.triple.domain == NULL || domain == NULL || __strcasecmp (entry.val.triple.domain, domain) == 0)) { result = 1; break; } } } /* If we found one service which does know the given netgroup we don't try further. */ status = NSS_STATUS_RETURN; } /* Free all resources of the service. */ endfct = __nss_lookup_function (entry.nip, "endnetgrent"); if (endfct != NULL) DL_CALL_FCT (*endfct, (&entry)); if (result != 0) break; /* Look for the next service. */ no_more = __nss_next2 (&entry.nip, "setnetgrent", NULL, &setfct.ptr, status, 0); } if (result == 0 && entry.needed_groups != NULL) { struct name_list *tmp = entry.needed_groups; entry.needed_groups = tmp->next; tmp->next = entry.known_groups; entry.known_groups = tmp; current_group = tmp->name; continue; } /* No way out. */ break; } /* Free the memory. */ free_memory (&entry); return result == 1; }
size_t attribute_hidden __mbsrtowcs_l (wchar_t *dst, const char **src, size_t len, mbstate_t *ps, locale_t l) { struct __gconv_step_data data; size_t result; int status; struct __gconv_step *towc; size_t non_reversible; const struct gconv_fcts *fcts; /* Tell where we want the result. */ data.__invocation_counter = 0; data.__internal_use = 1; data.__flags = __GCONV_IS_LAST; data.__statep = ps; /* Get the conversion functions. */ fcts = get_gconv_fcts (l->__locales[LC_CTYPE]); /* Get the structure with the function pointers. */ towc = fcts->towc; __gconv_fct fct = towc->__fct; #ifdef PTR_DEMANGLE if (towc->__shlib_handle != NULL) PTR_DEMANGLE (fct); #endif /* We have to handle DST == NULL special. */ if (dst == NULL) { mbstate_t temp_state; wchar_t buf[64]; /* Just an arbitrary size. */ const unsigned char *inbuf = (const unsigned char *) *src; const unsigned char *srcend = inbuf + strlen (*src) + 1; temp_state = *data.__statep; data.__statep = &temp_state; result = 0; data.__outbufend = (unsigned char *) buf + sizeof (buf); do { data.__outbuf = (unsigned char *) buf; status = DL_CALL_FCT (fct, (towc, &data, &inbuf, srcend, NULL, &non_reversible, 0, 1)); result += (wchar_t *) data.__outbuf - buf; } while (status == __GCONV_FULL_OUTPUT); if (status == __GCONV_OK || status == __GCONV_EMPTY_INPUT) { /* There better should be a NUL wide char at the end. */ assert (((wchar_t *) data.__outbuf)[-1] == L'\0'); /* Don't count the NUL character in. */ --result; } } else { /* This code is based on the safe assumption that all internal multi-byte encodings use the NUL byte only to mark the end of the string. */ const unsigned char *srcp = (const unsigned char *) *src; const unsigned char *srcend; data.__outbuf = (unsigned char *) dst; data.__outbufend = data.__outbuf + len * sizeof (wchar_t); status = __GCONV_FULL_OUTPUT; while (len > 0) { /* Pessimistic guess as to how much input we can use. In the worst case we need one input byte for one output wchar_t. */ srcend = srcp + __strnlen ((const char *) srcp, len) + 1; status = DL_CALL_FCT (fct, (towc, &data, &srcp, srcend, NULL, &non_reversible, 0, 1)); if ((status != __GCONV_EMPTY_INPUT && status != __GCONV_INCOMPLETE_INPUT) /* Not all input read. */ || srcp != srcend /* Reached the end of the input. */ || srcend[-1] == '\0') break; len = (wchar_t *) data.__outbufend - (wchar_t *) data.__outbuf; } /* Make the end if the input known to the caller. */ *src = (const char *) srcp; result = (wchar_t *) data.__outbuf - dst; /* We have to determine whether the last character converted is the NUL character. */ if ((status == __GCONV_OK || status == __GCONV_EMPTY_INPUT) && ((wchar_t *) dst)[result - 1] == L'\0') { assert (result > 0); assert (__mbsinit (data.__statep)); *src = NULL; --result; } } /* There must not be any problems with the conversion but illegal input characters. */ assert (status == __GCONV_OK || status == __GCONV_EMPTY_INPUT || status == __GCONV_ILLEGAL_INPUT || status == __GCONV_INCOMPLETE_INPUT || status == __GCONV_FULL_OUTPUT); if (status != __GCONV_OK && status != __GCONV_FULL_OUTPUT && status != __GCONV_EMPTY_INPUT && status != __GCONV_INCOMPLETE_INPUT) { result = (size_t) -1; __set_errno (EILSEQ); } return result; }