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,80 @@ 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 ;
100100
101101 /* Disallow potentially-malicious user names */
102102 if (!is_valid_username (name )) {
103- errno = ENOENT ;
103+ /* we don't serve an entry here */
104+ * __errnop = ENOENT ;
104105 return NSS_STATUS_NOTFOUND ;
105106 }
106107
107- if (asprintf (& file , TCB_FMT , name ) < 0 )
108+ if (asprintf (& file , TCB_FMT , name ) < 0 ) {
109+ /* retry, as malloc or another resource has failed */
110+ * __errnop = EAGAIN ;
108111 return NSS_STATUS_TRYAGAIN ;
112+ }
113+
109114 f = tcb_safe_open (file , name );
110115 free (file );
111- if (!f )
112- return errno == ENOENT ? NSS_STATUS_NOTFOUND : NSS_STATUS_UNAVAIL ;
116+ if (!f ) {
117+ /* $user/shadow not existing nor readable */
118+ * __errnop = ENOENT ;
119+ return NSS_STATUS_UNAVAIL ;
120+ }
113121
114- retval = fgetspent_r (f , __result_buf , __buffer , __buflen , __result );
122+ retval = fgetspent_r (f , __result_buf , __buffer ,
123+ __buflen , & __result_buf );
115124 saved_errno = errno ;
116125 fclose (f );
117126 errno = saved_errno ;
118- if (!retval )
119- return NSS_STATUS_SUCCESS ;
120127
121- switch (saved_errno ) {
128+ /* real error number is retval from fgetspent_r(),
129+ by NSS spec errnop *MUST NOT* be set to 0 */
130+ if (retval )
131+ * __errnop = retval ;
132+
133+ switch (retval ) {
122134 case 0 :
135+ /* no error, entry found */
123136 return NSS_STATUS_SUCCESS ;
124137
125138 case ENOENT :
139+ /* if the file would not exist nor be readable, we would
140+ have already bailed out with ENOENT/NSS_STATUS_UNAVAIL
141+ immediately after the call to tcb_safe_open() */
126142 return NSS_STATUS_NOTFOUND ;
127143
144+ case EAGAIN :
145+ /* ressources are temporary not available */
146+ return NSS_STATUS_TRYAGAIN ;
147+
128148 case ERANGE :
149+ /* buffer too small */
129150 return NSS_STATUS_TRYAGAIN ;
130151
131152 default :
153+ /* something else, e.g. parser error, but we can't help it */
132154 return NSS_STATUS_UNAVAIL ;
133155 }
134156}
135157
136- int _nss_tcb_getspent_r (struct spwd * __result_buf ,
137- char * __buffer , size_t __buflen , struct spwd * * __result )
158+ enum nss_status _nss_tcb_getspent_r (struct spwd * __result_buf ,
159+ char * __buffer , size_t __buflen , int * __errnop )
138160{
139161 struct dirent * result ;
140162 off_t currpos ;
141163 int retval , saved_errno ;
142164
143165 if (!tcbdir ) {
144- errno = ENOENT ;
166+ /* tcbdir does not exist */
167+ * __errnop = ENOENT ;
145168 return NSS_STATUS_UNAVAIL ;
146169 }
147170
@@ -154,21 +177,26 @@ int _nss_tcb_getspent_r(struct spwd *__result_buf,
154177 closedir (tcbdir );
155178 errno = saved_errno ;
156179 tcbdir = NULL ;
180+ /* cannot iterate tcbdir */
181+ * __errnop = ENOENT ;
157182 return NSS_STATUS_UNAVAIL ;
158183 }
159184 if (!result ) {
160185 closedir (tcbdir );
161- errno = ENOENT ;
186+ errno = saved_errno ;
162187 tcbdir = NULL ;
188+ /* we have no more entries in tcbdir */
189+ * __errnop = ENOENT ;
163190 return NSS_STATUS_NOTFOUND ;
164191 }
165192 errno = saved_errno ;
166193 } while (!strcmp (result -> d_name , "." ) ||
167194 !strcmp (result -> d_name , ".." ) || result -> d_name [0 ] == ':' );
168195
169196 retval = _nss_tcb_getspnam_r (result -> d_name , __result_buf , __buffer ,
170- __buflen , __result );
197+ __buflen , __errnop );
171198
199+ /* errnop has already been set by _nss_tcb_getspnam_r() */
172200 switch (retval ) {
173201 case NSS_STATUS_SUCCESS :
174202 return NSS_STATUS_SUCCESS ;
0 commit comments