99#include <fcntl.h>
1010#include <dirent.h>
1111
12+ #include "attribute.h"
1213#include "tcb.h"
1314
1415static __thread DIR * tcbdir = NULL ;
1516
16- int _nss_tcb_setspent (void )
17+ enum nss_status _nss_tcb_setspent (void )
1718{
1819 if (!tcbdir ) {
1920 tcbdir = opendir (TCB_DIR );
2021 if (!tcbdir )
2122 return NSS_STATUS_UNAVAIL ;
2223
23- return 1 ;
24+ return NSS_STATUS_SUCCESS ;
2425 }
2526
2627 rewinddir (tcbdir );
27- return 1 ;
28+ return NSS_STATUS_SUCCESS ;
2829}
2930
30- int _nss_tcb_endspent (void )
31+ enum nss_status _nss_tcb_endspent (void )
3132{
3233 if (tcbdir ) {
3334 closedir (tcbdir );
3435 tcbdir = NULL ;
3536 }
36- return 1 ;
37+ return NSS_STATUS_SUCCESS ;
3738}
3839
3940/******************************************************************************
@@ -91,57 +92,85 @@ static FILE *tcb_safe_open(const char *file, const char *name)
9192 return f ;
9293}
9394
94- int _nss_tcb_getspnam_r (const char * name , struct spwd * __result_buf ,
95- char * __buffer , size_t __buflen , struct spwd * * __result )
95+ enum nss_status _nss_tcb_getspnam_r (const char * name ,
96+ struct spwd * __result_buf , char * __buffer , size_t __buflen , int * __errnop )
9697{
9798 FILE * f ;
9899 char * file ;
99100 int retval , saved_errno ;
101+ struct spwd * * result_buf_ptr = NULL ;
100102
101103 /* Disallow potentially-malicious user names */
102104 if (!is_valid_username (name )) {
103- errno = ENOENT ;
105+ /* we don't serve an entry here */
106+ * __errnop = ENOENT ;
104107 return NSS_STATUS_NOTFOUND ;
105108 }
106109
107- if (asprintf (& file , TCB_FMT , name ) < 0 )
110+ if (asprintf (& file , TCB_FMT , name ) < 0 ) {
111+ /* retry, as malloc or another resource has failed */
112+ * __errnop = EAGAIN ;
108113 return NSS_STATUS_TRYAGAIN ;
114+ }
115+
109116 f = tcb_safe_open (file , name );
110117 free (file );
111- if (!f )
112- return errno == ENOENT ? NSS_STATUS_NOTFOUND : NSS_STATUS_UNAVAIL ;
118+ if (!f ) {
119+ /* $user/shadow not existing */
120+ * __errnop = ENOENT ;
121+ return NSS_STATUS_UNAVAIL ;
122+ }
113123
114- retval = fgetspent_r (f , __result_buf , __buffer , __buflen , __result );
124+ retval = fgetspent_r (f , __result_buf , __buffer ,
125+ __buflen , result_buf_ptr );
115126 saved_errno = errno ;
116127 fclose (f );
117128 errno = saved_errno ;
118- if (!retval )
119- return NSS_STATUS_SUCCESS ;
120129
121- switch (saved_errno ) {
130+ /* real error number is retval from fgetspent_r() */
131+ switch (retval ) {
122132 case 0 :
123- return NSS_STATUS_SUCCESS ;
133+ if (* result_buf_ptr )
134+ return NSS_STATUS_SUCCESS ;
135+
136+ /* else: no error, but entry not found;
137+ is properly handled by case ENOENT */
138+ TCB_FALLTHROUGH
124139
125140 case ENOENT :
141+ /* if the file would not exist, we would have already
142+ bailed out with ENOENT/NSS_STATUS_UNAVAIL immediately
143+ after the call to tcb_safe_open() */
144+ * __errnop = ENOENT ;
126145 return NSS_STATUS_NOTFOUND ;
127146
147+ case EAGAIN :
148+ /* ressources are temporary not available */
149+ * __errnop = EAGAIN ;
150+ return NSS_STATUS_TRYAGAIN ;
151+
128152 case ERANGE :
153+ /* __buffer too small */
154+ * __errnop = ERANGE ;
129155 return NSS_STATUS_TRYAGAIN ;
130156
131157 default :
158+ /* something serious, but we can't help it */
159+ * __errnop = retval ;
132160 return NSS_STATUS_UNAVAIL ;
133161 }
134162}
135163
136- int _nss_tcb_getspent_r (struct spwd * __result_buf ,
137- char * __buffer , size_t __buflen , struct spwd * * __result )
164+ enum nss_status _nss_tcb_getspent_r (struct spwd * __result_buf ,
165+ char * __buffer , size_t __buflen , int * __errnop )
138166{
139167 struct dirent * result ;
140168 off_t currpos ;
141169 int retval , saved_errno ;
142170
143171 if (!tcbdir ) {
144- errno = ENOENT ;
172+ /* tcbdir does not exist */
173+ * __errnop = ENOENT ;
145174 return NSS_STATUS_UNAVAIL ;
146175 }
147176
@@ -154,21 +183,26 @@ int _nss_tcb_getspent_r(struct spwd *__result_buf,
154183 closedir (tcbdir );
155184 errno = saved_errno ;
156185 tcbdir = NULL ;
186+ /* cannot iterate tcbdir */
187+ * __errnop = ENOENT ;
157188 return NSS_STATUS_UNAVAIL ;
158189 }
159190 if (!result ) {
160191 closedir (tcbdir );
161- errno = ENOENT ;
192+ errno = saved_errno ;
162193 tcbdir = NULL ;
194+ /* we have no more entries in tcbdir */
195+ * __errnop = ENOENT ;
163196 return NSS_STATUS_NOTFOUND ;
164197 }
165198 errno = saved_errno ;
166199 } while (!strcmp (result -> d_name , "." ) ||
167200 !strcmp (result -> d_name , ".." ) || result -> d_name [0 ] == ':' );
168201
169202 retval = _nss_tcb_getspnam_r (result -> d_name , __result_buf , __buffer ,
170- __buflen , __result );
203+ __buflen , __errnop );
171204
205+ /* __errnop has already been set by _nss_tcb_getspnam_r() */
172206 switch (retval ) {
173207 case NSS_STATUS_SUCCESS :
174208 return NSS_STATUS_SUCCESS ;
0 commit comments