1313
1414static __thread DIR * tcbdir = NULL ;
1515
16- int _nss_tcb_setspent (void )
16+ enum nss_status _nss_tcb_setspent (void )
1717{
1818 if (!tcbdir ) {
1919 tcbdir = opendir (TCB_DIR );
2020 if (!tcbdir )
2121 return NSS_STATUS_UNAVAIL ;
2222
23- return 1 ;
23+ return NSS_STATUS_SUCCESS ;
2424 }
2525
2626 rewinddir (tcbdir );
27- return 1 ;
27+ return NSS_STATUS_SUCCESS ;
2828}
2929
30- int _nss_tcb_endspent (void )
30+ enum nss_status _nss_tcb_endspent (void )
3131{
3232 if (tcbdir ) {
3333 closedir (tcbdir );
3434 tcbdir = NULL ;
3535 }
36- return 1 ;
36+ return NSS_STATUS_SUCCESS ;
3737}
3838
3939/******************************************************************************
@@ -91,57 +91,84 @@ static FILE *tcb_safe_open(const char *file, const char *name)
9191 return f ;
9292}
9393
94- int _nss_tcb_getspnam_r (const char * name , struct spwd * __result_buf ,
95- char * __buffer , size_t __buflen , struct spwd * * __result )
94+ enum nss_status _nss_tcb_getspnam_r (const char * name ,
95+ struct spwd * __result_buf , char * __buffer , size_t __buflen , int * __errnop )
9696{
9797 FILE * f ;
9898 char * file ;
9999 int retval , saved_errno ;
100+ struct spwd * * result_buf_ptr = NULL ;
100101
101102 /* Disallow potentially-malicious user names */
102103 if (!is_valid_username (name )) {
103- errno = ENOENT ;
104+ /* we don't serve an entry here */
105+ * __errnop = ENOENT ;
104106 return NSS_STATUS_NOTFOUND ;
105107 }
106108
107- if (asprintf (& file , TCB_FMT , name ) < 0 )
109+ if (asprintf (& file , TCB_FMT , name ) < 0 ) {
110+ /* retry, as malloc or another resource has failed */
111+ * __errnop = EAGAIN ;
108112 return NSS_STATUS_TRYAGAIN ;
113+ }
114+
109115 f = tcb_safe_open (file , name );
110116 free (file );
111- if (!f )
112- return errno == ENOENT ? NSS_STATUS_NOTFOUND : NSS_STATUS_UNAVAIL ;
117+ if (!f ) {
118+ /* $user/shadow not existing */
119+ * __errnop = ENOENT ;
120+ return NSS_STATUS_UNAVAIL ;
121+ }
113122
114- retval = fgetspent_r (f , __result_buf , __buffer , __buflen , __result );
123+ retval = fgetspent_r (f , __result_buf , __buffer ,
124+ __buflen , result_buf_ptr );
115125 saved_errno = errno ;
116126 fclose (f );
117127 errno = saved_errno ;
118- if (!retval )
119- return NSS_STATUS_SUCCESS ;
120128
121- switch (saved_errno ) {
129+ /* real error number is retval from fgetspent_r() */
130+ switch (retval ) {
122131 case 0 :
123- return NSS_STATUS_SUCCESS ;
132+ if (* result_buf_ptr )
133+ return NSS_STATUS_SUCCESS ;
134+
135+ /* else: no error, but entry not found;
136+ handled by fall-through to case ENOENT */
124137
125138 case ENOENT :
139+ /* if the file would not exist, we would have already
140+ bailed out with ENOENT/NSS_STATUS_UNAVAIL immediately
141+ after the call to tcb_safe_open() */
142+ * __errnop = ENOENT ;
126143 return NSS_STATUS_NOTFOUND ;
127144
145+ case EAGAIN :
146+ /* ressources are temporary not available */
147+ * __errnop = EAGAIN ;
148+ return NSS_STATUS_TRYAGAIN ;
149+
128150 case ERANGE :
151+ /* __buffer too small */
152+ * __errnop = ERANGE ;
129153 return NSS_STATUS_TRYAGAIN ;
130154
131155 default :
156+ /* something serious, but we can't help it */
157+ * __errnop = retval ;
132158 return NSS_STATUS_UNAVAIL ;
133159 }
134160}
135161
136- int _nss_tcb_getspent_r (struct spwd * __result_buf ,
137- char * __buffer , size_t __buflen , struct spwd * * __result )
162+ enum nss_status _nss_tcb_getspent_r (struct spwd * __result_buf ,
163+ char * __buffer , size_t __buflen , int * __errnop )
138164{
139165 struct dirent * result ;
140166 off_t currpos ;
141167 int retval , saved_errno ;
142168
143169 if (!tcbdir ) {
144- errno = ENOENT ;
170+ /* tcbdir does not exist */
171+ * __errnop = ENOENT ;
145172 return NSS_STATUS_UNAVAIL ;
146173 }
147174
@@ -154,21 +181,26 @@ int _nss_tcb_getspent_r(struct spwd *__result_buf,
154181 closedir (tcbdir );
155182 errno = saved_errno ;
156183 tcbdir = NULL ;
184+ /* cannot iterate tcbdir */
185+ * __errnop = ENOENT ;
157186 return NSS_STATUS_UNAVAIL ;
158187 }
159188 if (!result ) {
160189 closedir (tcbdir );
161- errno = ENOENT ;
190+ errno = saved_errno ;
162191 tcbdir = NULL ;
192+ /* we have no more entries in tcbdir */
193+ * __errnop = ENOENT ;
163194 return NSS_STATUS_NOTFOUND ;
164195 }
165196 errno = saved_errno ;
166197 } while (!strcmp (result -> d_name , "." ) ||
167198 !strcmp (result -> d_name , ".." ) || result -> d_name [0 ] == ':' );
168199
169200 retval = _nss_tcb_getspnam_r (result -> d_name , __result_buf , __buffer ,
170- __buflen , __result );
201+ __buflen , __errnop );
171202
203+ /* __errnop has already been set by _nss_tcb_getspnam_r() */
172204 switch (retval ) {
173205 case NSS_STATUS_SUCCESS :
174206 return NSS_STATUS_SUCCESS ;
0 commit comments