1 | /* Copyright (C) 2000, 2002, 2004 Free Software Foundation, Inc. |
---|
2 | This file is part of the GNU C Library. |
---|
3 | |
---|
4 | The GNU C Library is free software; you can redistribute it and/or |
---|
5 | modify it under the terms of the GNU Lesser General Public |
---|
6 | License as published by the Free Software Foundation; either |
---|
7 | version 2.1 of the License, or (at your option) any later version. |
---|
8 | |
---|
9 | The GNU C Library is distributed in the hope that it will be useful, |
---|
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
---|
12 | Lesser General Public License for more details. |
---|
13 | |
---|
14 | You should have received a copy of the GNU Lesser General Public |
---|
15 | License along with the GNU C Library; if not, write to the Free |
---|
16 | Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
---|
17 | 02111-1307 USA. */ |
---|
18 | |
---|
19 | #include <errno.h> |
---|
20 | #include <netdb.h> |
---|
21 | #include "nsswitch.h" |
---|
22 | |
---|
23 | /* Set up NIP to run through the services. If ALL is zero, use NIP's |
---|
24 | current location if it's not nil. Return nonzero if there are no |
---|
25 | services (left). */ |
---|
26 | static int |
---|
27 | setup (const char *func_name, db_lookup_function lookup_fct, |
---|
28 | void **fctp, service_user **nip, service_user **startp, int all) |
---|
29 | { |
---|
30 | int no_more; |
---|
31 | if (*startp == NULL) |
---|
32 | { |
---|
33 | no_more = lookup_fct (nip, func_name, fctp); |
---|
34 | *startp = no_more ? (service_user *) -1l : *nip; |
---|
35 | } |
---|
36 | else if (*startp == (service_user *) -1l) |
---|
37 | /* No services at all. */ |
---|
38 | return 1; |
---|
39 | else |
---|
40 | { |
---|
41 | if (all || !*nip) |
---|
42 | /* Reset to the beginning of the service list. */ |
---|
43 | *nip = *startp; |
---|
44 | /* Look up the first function. */ |
---|
45 | no_more = __nss_lookup (nip, func_name, fctp); |
---|
46 | } |
---|
47 | return no_more; |
---|
48 | } |
---|
49 | |
---|
50 | void |
---|
51 | __nss_setent (const char *func_name, db_lookup_function lookup_fct, |
---|
52 | service_user **nip, service_user **startp, |
---|
53 | service_user **last_nip, int stayopen, int *stayopen_tmp, |
---|
54 | int res) |
---|
55 | { |
---|
56 | union |
---|
57 | { |
---|
58 | setent_function f; |
---|
59 | void *ptr; |
---|
60 | } fct; |
---|
61 | int no_more; |
---|
62 | |
---|
63 | if (res && __res_maybe_init (&_res, 0) == -1) |
---|
64 | { |
---|
65 | h_errno = (NETDB_INTERNAL); |
---|
66 | return; |
---|
67 | } |
---|
68 | |
---|
69 | /* Cycle through the services and run their `setXXent' functions until |
---|
70 | we find an available service. */ |
---|
71 | no_more = setup (func_name, lookup_fct, &fct.ptr, nip, |
---|
72 | startp, 1); |
---|
73 | while (! no_more) |
---|
74 | { |
---|
75 | int is_last_nip = *nip == *last_nip; |
---|
76 | enum nss_status status; |
---|
77 | |
---|
78 | if (stayopen_tmp) |
---|
79 | status = DL_CALL_FCT (fct.f, (*stayopen_tmp)); |
---|
80 | else |
---|
81 | status = DL_CALL_FCT (fct.f, (0)); |
---|
82 | |
---|
83 | no_more = __nss_next (nip, func_name, &fct.ptr, |
---|
84 | status, 0); |
---|
85 | if (is_last_nip) |
---|
86 | *last_nip = *nip; |
---|
87 | } |
---|
88 | |
---|
89 | if (stayopen_tmp) |
---|
90 | *stayopen_tmp = stayopen; |
---|
91 | } |
---|
92 | |
---|
93 | |
---|
94 | void |
---|
95 | __nss_endent (const char *func_name, db_lookup_function lookup_fct, |
---|
96 | service_user **nip, service_user **startp, |
---|
97 | service_user **last_nip, int res) |
---|
98 | { |
---|
99 | union |
---|
100 | { |
---|
101 | endent_function f; |
---|
102 | void *ptr; |
---|
103 | } fct; |
---|
104 | int no_more; |
---|
105 | |
---|
106 | if (res && __res_maybe_init (&_res, 0) == -1) |
---|
107 | { |
---|
108 | h_errno = (NETDB_INTERNAL); |
---|
109 | return; |
---|
110 | } |
---|
111 | |
---|
112 | /* Cycle through all the services and run their endXXent functions. */ |
---|
113 | no_more = setup (func_name, lookup_fct, &fct.ptr, nip, startp, 1); |
---|
114 | while (! no_more) |
---|
115 | { |
---|
116 | /* Ignore status, we force check in __NSS_NEXT. */ |
---|
117 | DL_CALL_FCT (fct.f, ()); |
---|
118 | |
---|
119 | if (*nip == *last_nip) |
---|
120 | /* We have processed all services which were used. */ |
---|
121 | break; |
---|
122 | |
---|
123 | no_more = __nss_next (nip, func_name, &fct.ptr, 0, 1); |
---|
124 | } |
---|
125 | *last_nip = *nip = NULL; |
---|
126 | } |
---|
127 | |
---|
128 | |
---|
129 | int |
---|
130 | __nss_getent_r (const char *getent_func_name, |
---|
131 | const char *setent_func_name, |
---|
132 | db_lookup_function lookup_fct, |
---|
133 | service_user **nip, service_user **startp, |
---|
134 | service_user **last_nip, int *stayopen_tmp, int res, |
---|
135 | void *resbuf, char *buffer, size_t buflen, |
---|
136 | void **result, int *h_errnop) |
---|
137 | { |
---|
138 | union |
---|
139 | { |
---|
140 | getent_function f; |
---|
141 | void *ptr; |
---|
142 | } fct; |
---|
143 | int no_more; |
---|
144 | enum nss_status status; |
---|
145 | |
---|
146 | if (res && __res_maybe_init (&_res, 0) == -1) |
---|
147 | { |
---|
148 | *h_errnop = NETDB_INTERNAL; |
---|
149 | *result = NULL; |
---|
150 | return errno; |
---|
151 | } |
---|
152 | |
---|
153 | /* Initialize status to return if no more functions are found. */ |
---|
154 | status = NSS_STATUS_NOTFOUND; |
---|
155 | |
---|
156 | /* Run through available functions, starting with the same function last |
---|
157 | run. We will repeat each function as long as it succeeds, and then go |
---|
158 | on to the next service action. */ |
---|
159 | no_more = setup (getent_func_name, lookup_fct, &fct.ptr, nip, |
---|
160 | startp, 0); |
---|
161 | while (! no_more) |
---|
162 | { |
---|
163 | int is_last_nip = *nip == *last_nip; |
---|
164 | |
---|
165 | status = DL_CALL_FCT (fct.f, |
---|
166 | (resbuf, buffer, buflen, &errno, &h_errno)); |
---|
167 | |
---|
168 | /* The the status is NSS_STATUS_TRYAGAIN and errno is ERANGE the |
---|
169 | provided buffer is too small. In this case we should give |
---|
170 | the user the possibility to enlarge the buffer and we should |
---|
171 | not simply go on with the next service (even if the TRYAGAIN |
---|
172 | action tells us so). */ |
---|
173 | if (status == NSS_STATUS_TRYAGAIN |
---|
174 | && (h_errnop == NULL || *h_errnop == NETDB_INTERNAL) |
---|
175 | && errno == ERANGE) |
---|
176 | break; |
---|
177 | |
---|
178 | do |
---|
179 | { |
---|
180 | no_more = __nss_next (nip, getent_func_name, &fct.ptr, |
---|
181 | status, 0); |
---|
182 | |
---|
183 | if (is_last_nip) |
---|
184 | *last_nip = *nip; |
---|
185 | |
---|
186 | if (! no_more) |
---|
187 | { |
---|
188 | /* Call the `setXXent' function. This wasn't done before. */ |
---|
189 | union |
---|
190 | { |
---|
191 | setent_function f; |
---|
192 | void *ptr; |
---|
193 | } sfct; |
---|
194 | |
---|
195 | no_more = __nss_lookup (nip, setent_func_name, |
---|
196 | &sfct.ptr); |
---|
197 | |
---|
198 | if (! no_more) |
---|
199 | { |
---|
200 | if (stayopen_tmp) |
---|
201 | status = DL_CALL_FCT (sfct.f, (*stayopen_tmp)); |
---|
202 | else |
---|
203 | status = DL_CALL_FCT (sfct.f, (0)); |
---|
204 | } |
---|
205 | else |
---|
206 | status = NSS_STATUS_NOTFOUND; |
---|
207 | } |
---|
208 | } |
---|
209 | while (! no_more && status != NSS_STATUS_SUCCESS); |
---|
210 | } |
---|
211 | |
---|
212 | *result = status == NSS_STATUS_SUCCESS ? resbuf : NULL; |
---|
213 | return (status == NSS_STATUS_SUCCESS ? 0 |
---|
214 | : status != NSS_STATUS_TRYAGAIN ? ENOENT |
---|
215 | /* h_errno functions only set errno if h_errno is NETDB_INTERNAL. */ |
---|
216 | : (h_errnop == NULL || *h_errnop == NETDB_INTERNAL) ? errno |
---|
217 | : EAGAIN); |
---|
218 | } |
---|