| OLD | NEW | 
| (Empty) |  | 
 |    1 #include <pthread.h> | 
 |    2 #include <byteswap.h> | 
 |    3 #include <string.h> | 
 |    4 #include <unistd.h> | 
 |    5 #include "pwf.h" | 
 |    6 #include "nscd.h" | 
 |    7  | 
 |    8 static char *itoa(char *p, uint32_t x) | 
 |    9 { | 
 |   10         // number of digits in a uint32_t + NUL | 
 |   11         p += 11; | 
 |   12         *--p = 0; | 
 |   13         do { | 
 |   14                 *--p = '0' + x % 10; | 
 |   15                 x /= 10; | 
 |   16         } while (x); | 
 |   17         return p; | 
 |   18 } | 
 |   19  | 
 |   20 int __getpw_a(const char *name, uid_t uid, struct passwd *pw, char **buf, size_t
      *size, struct passwd **res) | 
 |   21 { | 
 |   22         FILE *f; | 
 |   23         int cs; | 
 |   24         int rv = 0; | 
 |   25  | 
 |   26         *res = 0; | 
 |   27  | 
 |   28         pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); | 
 |   29  | 
 |   30         f = fopen("/etc/passwd", "rbe"); | 
 |   31         if (!f) { | 
 |   32                 rv = errno; | 
 |   33                 goto done; | 
 |   34         } | 
 |   35  | 
 |   36         while (!(rv = __getpwent_a(f, pw, buf, size, res)) && *res) { | 
 |   37                 if (name && !strcmp(name, (*res)->pw_name) | 
 |   38                 || !name && (*res)->pw_uid == uid) | 
 |   39                         break; | 
 |   40         } | 
 |   41         fclose(f); | 
 |   42  | 
 |   43         if (!*res && (rv == 0 || rv == ENOENT || rv == ENOTDIR)) { | 
 |   44                 int32_t req = name ? GETPWBYNAME : GETPWBYUID; | 
 |   45                 const char *key; | 
 |   46                 int32_t passwdbuf[PW_LEN] = {0}; | 
 |   47                 size_t len = 0; | 
 |   48                 char uidbuf[11] = {0}; | 
 |   49  | 
 |   50                 if (name) { | 
 |   51                         key = name; | 
 |   52                 } else { | 
 |   53                         /* uid outside of this range can't be queried with the | 
 |   54                          * nscd interface, but might happen if uid_t ever | 
 |   55                          * happens to be a larger type (this is not true as of | 
 |   56                          * now) | 
 |   57                          */ | 
 |   58                         if(uid < 0 || uid > UINT32_MAX) { | 
 |   59                                 rv = 0; | 
 |   60                                 goto done; | 
 |   61                         } | 
 |   62                         key = itoa(uidbuf, uid); | 
 |   63                 } | 
 |   64  | 
 |   65                 f = __nscd_query(req, key, passwdbuf, sizeof passwdbuf, (int[]){
     0}); | 
 |   66                 if (!f) { rv = errno; goto done; } | 
 |   67  | 
 |   68                 if(!passwdbuf[PWFOUND]) { rv = 0; goto cleanup_f; } | 
 |   69  | 
 |   70                 /* A zero length response from nscd is invalid. We ignore | 
 |   71                  * invalid responses and just report an error, rather than | 
 |   72                  * trying to do something with them. | 
 |   73                  */ | 
 |   74                 if (!passwdbuf[PWNAMELEN] || !passwdbuf[PWPASSWDLEN] | 
 |   75                 || !passwdbuf[PWGECOSLEN] || !passwdbuf[PWDIRLEN] | 
 |   76                 || !passwdbuf[PWSHELLLEN]) { | 
 |   77                         rv = EIO; | 
 |   78                         goto cleanup_f; | 
 |   79                 } | 
 |   80  | 
 |   81                 if ((passwdbuf[PWNAMELEN]|passwdbuf[PWPASSWDLEN] | 
 |   82                      |passwdbuf[PWGECOSLEN]|passwdbuf[PWDIRLEN] | 
 |   83                      |passwdbuf[PWSHELLLEN]) >= SIZE_MAX/8) { | 
 |   84                         rv = ENOMEM; | 
 |   85                         goto cleanup_f; | 
 |   86                 } | 
 |   87  | 
 |   88                 len = passwdbuf[PWNAMELEN] + passwdbuf[PWPASSWDLEN] | 
 |   89                     + passwdbuf[PWGECOSLEN] + passwdbuf[PWDIRLEN] | 
 |   90                     + passwdbuf[PWSHELLLEN]; | 
 |   91  | 
 |   92                 if (len > *size || !*buf) { | 
 |   93                         char *tmp = realloc(*buf, len); | 
 |   94                         if (!tmp) { | 
 |   95                                 rv = errno; | 
 |   96                                 goto cleanup_f; | 
 |   97                         } | 
 |   98                         *buf = tmp; | 
 |   99                         *size = len; | 
 |  100                 } | 
 |  101  | 
 |  102                 if (!fread(*buf, len, 1, f)) { | 
 |  103                         rv = ferror(f) ? errno : EIO; | 
 |  104                         goto cleanup_f; | 
 |  105                 } | 
 |  106  | 
 |  107                 pw->pw_name = *buf; | 
 |  108                 pw->pw_passwd = pw->pw_name + passwdbuf[PWNAMELEN]; | 
 |  109                 pw->pw_gecos = pw->pw_passwd + passwdbuf[PWPASSWDLEN]; | 
 |  110                 pw->pw_dir = pw->pw_gecos + passwdbuf[PWGECOSLEN]; | 
 |  111                 pw->pw_shell = pw->pw_dir + passwdbuf[PWDIRLEN]; | 
 |  112                 pw->pw_uid = passwdbuf[PWUID]; | 
 |  113                 pw->pw_gid = passwdbuf[PWGID]; | 
 |  114  | 
 |  115                 /* Don't assume that nscd made sure to null terminate strings. | 
 |  116                  * It's supposed to, but malicious nscd should be ignored | 
 |  117                  * rather than causing a crash. | 
 |  118                  */ | 
 |  119                 if (pw->pw_passwd[-1] || pw->pw_gecos[-1] || pw->pw_dir[-1] | 
 |  120                 || pw->pw_shell[passwdbuf[PWSHELLLEN]-1]) { | 
 |  121                         rv = EIO; | 
 |  122                         goto cleanup_f; | 
 |  123                 } | 
 |  124  | 
 |  125                 if (name && strcmp(name, pw->pw_name) | 
 |  126                 || !name && uid != pw->pw_uid) { | 
 |  127                         rv = EIO; | 
 |  128                         goto cleanup_f; | 
 |  129                 } | 
 |  130  | 
 |  131  | 
 |  132                 *res = pw; | 
 |  133 cleanup_f: | 
 |  134                 fclose(f); | 
 |  135                 goto done; | 
 |  136         } | 
 |  137  | 
 |  138 done: | 
 |  139         pthread_setcancelstate(cs, 0); | 
 |  140         if (rv) errno = rv; | 
 |  141         return rv; | 
 |  142 } | 
| OLD | NEW |