Changeset View
Changeset View
Standalone View
Standalone View
usr.sbin/nscd/agents/passwd.c
| Show All 22 Lines | ||||||||||
| * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||||||||
| * SUCH DAMAGE. | * SUCH DAMAGE. | |||||||||
| * | * | |||||||||
| */ | */ | |||||||||
| #include <sys/types.h> | #include <sys/types.h> | |||||||||
| #include <assert.h> | #include <assert.h> | |||||||||
| #include <errno.h> | ||||||||||
| #include <nsswitch.h> | #include <nsswitch.h> | |||||||||
| #include <pwd.h> | #include <pwd.h> | |||||||||
| #include <stdlib.h> | #include <stdlib.h> | |||||||||
| #include <string.h> | #include <string.h> | |||||||||
| #include "../debug.h" | #include "../debug.h" | |||||||||
| #include "passwd.h" | #include "passwd.h" | |||||||||
| #define PASSWD_STORAGE_INITIAL (1<<10) | ||||||||||
| #define PASSWD_STORAGE_MAX (1<<20) | ||||||||||
| typedef union key { | ||||||||||
| char *login; | ||||||||||
| uid_t uid; | ||||||||||
| } u_key; | ||||||||||
| static int passwd_marshal_func(struct passwd *, char *, size_t *); | static int passwd_marshal_func(struct passwd *, char *, size_t *); | |||||||||
| static int passwd_lookup_func(const char *, size_t, char **, size_t *); | static int passwd_lookup_func(const char *, size_t, char **, size_t *); | |||||||||
| static void *passwd_mp_init_func(void); | static void *passwd_mp_init_func(void); | |||||||||
| static int passwd_mp_lookup_func(char **, size_t *, void *); | static int passwd_mp_lookup_func(char **, size_t *, void *); | |||||||||
| static void passwd_mp_destroy_func(void *mdata); | static void passwd_mp_destroy_func(void *mdata); | |||||||||
| static char *getpw(int (*)(u_key, struct passwd *, char *, size_t, | ||||||||||
| struct passwd **), u_key, size_t *); | ||||||||||
| static int wrap_getpwnam_r(u_key, struct passwd *, char *, size_t, | ||||||||||
| struct passwd **); | ||||||||||
| static int wrap_getpwuid_r(u_key, struct passwd *, char *, size_t, | ||||||||||
| struct passwd **); | ||||||||||
| static int wrap_getpwent_r(u_key, struct passwd *, char *, size_t, | ||||||||||
| struct passwd **); | ||||||||||
| static char * | ||||||||||
| getpw(int (*fn)(u_key, struct passwd *, char *, size_t, struct passwd **), | ||||||||||
| u_key ukey, size_t *buffer_size) | ||||||||||
| { | ||||||||||
| int return_value; | ||||||||||
| struct passwd passwd, *result; | ||||||||||
| char *passwd_storage = NULL, *buffer; | ||||||||||
| size_t passwd_storage_size = PASSWD_STORAGE_INITIAL; | ||||||||||
| do { | ||||||||||
| passwd_storage = | ||||||||||
| realloc(passwd_storage, passwd_storage_size); | ||||||||||
markj: Please remove the extra newline before each return statement. It's inconsistent with the code… | ||||||||||
| if (passwd_storage == NULL) { | ||||||||||
| return (NULL); | ||||||||||
| } | ||||||||||
| return_value = fn(ukey, &passwd, passwd_storage, | ||||||||||
| passwd_storage_size, &result); | ||||||||||
| passwd_storage_size <<= 1; | ||||||||||
| } while (result == NULL && | ||||||||||
| return_value == ERANGE && | ||||||||||
| passwd_storage_size < PASSWD_STORAGE_MAX); | ||||||||||
| if (return_value != 0 || result == NULL) { | ||||||||||
| free(passwd_storage); | ||||||||||
| errno = return_value; | ||||||||||
| return (NULL); | ||||||||||
| } | ||||||||||
Not Done Inline ActionsIt'd be a bit more efficient to use realloc() in these loops. markj: It'd be a bit more efficient to use realloc() in these loops. | ||||||||||
| *buffer_size = 0; | ||||||||||
| passwd_marshal_func(&passwd, NULL, buffer_size); | ||||||||||
| buffer = malloc(*buffer_size); | ||||||||||
| assert(buffer != NULL); | ||||||||||
| passwd_marshal_func(&passwd, buffer, buffer_size); | ||||||||||
| free(passwd_storage); | ||||||||||
Not Done Inline ActionsThis assignment to errno should happen right before returning from this function. It may get clobbered by free(), for example. markj: This assignment to `errno` should happen right before returning from this function. It may get… | ||||||||||
| errno = return_value; | ||||||||||
| return (buffer); | ||||||||||
| } | ||||||||||
| static int | static int | |||||||||
| wrap_getpwnam_r(u_key ukey, struct passwd *pwd, char *buffer, size_t bufsize, | ||||||||||
| struct passwd **res) | ||||||||||
| { | ||||||||||
| return (getpwnam_r(ukey.login, pwd, buffer, bufsize, res)); | ||||||||||
| } | ||||||||||
| static int | ||||||||||
| wrap_getpwuid_r(u_key ukey, struct passwd *pwd, char *buffer, size_t bufsize, | ||||||||||
| struct passwd **res) | ||||||||||
| { | ||||||||||
| return (getpwuid_r(ukey.uid, pwd, buffer, bufsize, res)); | ||||||||||
| } | ||||||||||
| static int | ||||||||||
| wrap_getpwent_r(u_key ukey __unused, struct passwd *pwd, char *buffer, | ||||||||||
| size_t bufsize, struct passwd **res) | ||||||||||
| { | ||||||||||
| return (getpwent_r(pwd, buffer, bufsize, res)); | ||||||||||
| } | ||||||||||
| static int | ||||||||||
| passwd_marshal_func(struct passwd *pwd, char *buffer, size_t *buffer_size) | passwd_marshal_func(struct passwd *pwd, char *buffer, size_t *buffer_size) | |||||||||
| { | { | |||||||||
| char *p; | char *p; | |||||||||
| struct passwd new_pwd; | struct passwd new_pwd; | |||||||||
| size_t desired_size, size; | size_t desired_size, size; | |||||||||
| TRACE_IN(passwd_marshal_func); | TRACE_IN(passwd_marshal_func); | |||||||||
| desired_size = sizeof(struct passwd) + sizeof(char *) + | desired_size = sizeof(struct passwd) + sizeof(char *) + | |||||||||
| ▲ Show 20 Lines • Show All 69 Lines • ▼ Show 20 Lines | passwd_marshal_func(struct passwd *pwd, char *buffer, size_t *buffer_size) | |||||||||
| return (NS_SUCCESS); | return (NS_SUCCESS); | |||||||||
| } | } | |||||||||
| static int | static int | |||||||||
| passwd_lookup_func(const char *key, size_t key_size, char **buffer, | passwd_lookup_func(const char *key, size_t key_size, char **buffer, | |||||||||
| size_t *buffer_size) | size_t *buffer_size) | |||||||||
| { | { | |||||||||
| enum nss_lookup_type lookup_type; | enum nss_lookup_type lookup_type; | |||||||||
| char *login; | u_key ukey; | |||||||||
| size_t size; | size_t size; | |||||||||
| uid_t uid; | int pw_errno; | |||||||||
| struct passwd *result; | ||||||||||
| TRACE_IN(passwd_lookup_func); | TRACE_IN(passwd_lookup_func); | |||||||||
| assert(buffer != NULL); | assert(buffer != NULL); | |||||||||
| assert(buffer_size != NULL); | assert(buffer_size != NULL); | |||||||||
| *buffer_size = 0; | ||||||||||
| if (key_size < sizeof(enum nss_lookup_type)) { | if (key_size < sizeof(enum nss_lookup_type)) { | |||||||||
| TRACE_OUT(passwd_lookup_func); | TRACE_OUT(passwd_lookup_func); | |||||||||
| return (NS_UNAVAIL); | return (NS_UNAVAIL); | |||||||||
| } | } | |||||||||
| memcpy(&lookup_type, key, sizeof(enum nss_lookup_type)); | memcpy(&lookup_type, key, sizeof(enum nss_lookup_type)); | |||||||||
| switch (lookup_type) { | switch (lookup_type) { | |||||||||
| case nss_lt_name: | case nss_lt_name: | |||||||||
| size = key_size - sizeof(enum nss_lookup_type) + 1; | if (key_size < sizeof(enum nss_lookup_type) + 2) { | |||||||||
| login = calloc(1, size); | TRACE_OUT(passwd_lookup_func); | |||||||||
| assert(login != NULL); | return (NS_UNAVAIL); | |||||||||
| memcpy(login, key + sizeof(enum nss_lookup_type), size - 1); | } | |||||||||
| size = key_size - sizeof(enum nss_lookup_type); | ||||||||||
| ukey.login = malloc(size); | ||||||||||
| assert(ukey.login != NULL); | ||||||||||
| memcpy(ukey.login, key + sizeof(enum nss_lookup_type), size); | ||||||||||
| ukey.login[size - 1] = 0; | ||||||||||
Not Done Inline Actions
markj: | ||||||||||
| TRACE_STR(ukey.login); | ||||||||||
| errno = 0; | ||||||||||
| *buffer = getpw(wrap_getpwnam_r, ukey, buffer_size); | ||||||||||
| pw_errno = errno; | ||||||||||
markjUnsubmitted Not Done Inline ActionsA suggestion which would simplify this patch a bit: don't use errno to pass error numbers between these internal subroutines. Instead, add an extra parameter of type int * to getpw(), and modify getpw() to use it to return an error number instead of (ab)using errno. markj: A suggestion which would simplify this patch a bit: don't use `errno` to pass error numbers… | ||||||||||
| free(ukey.login); | ||||||||||
| break; | break; | |||||||||
| case nss_lt_id: | case nss_lt_id: | |||||||||
| if (key_size < sizeof(enum nss_lookup_type) + | if (key_size < sizeof(enum nss_lookup_type) + | |||||||||
| sizeof(uid_t)) { | sizeof(uid_t)) { | |||||||||
| TRACE_OUT(passwd_lookup_func); | TRACE_OUT(passwd_lookup_func); | |||||||||
| return (NS_UNAVAIL); | return (NS_UNAVAIL); | |||||||||
| } | } | |||||||||
| memcpy(&uid, key + sizeof(enum nss_lookup_type), sizeof(uid_t)); | memcpy(&ukey.uid, key + sizeof(enum nss_lookup_type), | |||||||||
| sizeof(uid_t)); | ||||||||||
| errno = 0; | ||||||||||
| *buffer = getpw(wrap_getpwuid_r, ukey, buffer_size); | ||||||||||
| pw_errno = errno; | ||||||||||
| break; | break; | |||||||||
| default: | default: | |||||||||
| TRACE_OUT(passwd_lookup_func); | TRACE_OUT(passwd_lookup_func); | |||||||||
| return (NS_UNAVAIL); | return (NS_UNAVAIL); | |||||||||
| } | } | |||||||||
| switch (lookup_type) { | ||||||||||
| case nss_lt_name: | ||||||||||
| result = getpwnam(login); | ||||||||||
| free(login); | ||||||||||
| break; | ||||||||||
| case nss_lt_id: | ||||||||||
| result = getpwuid(uid); | ||||||||||
| break; | ||||||||||
| default: | ||||||||||
| /* SHOULD NOT BE REACHED */ | ||||||||||
| break; | ||||||||||
| } | ||||||||||
| if (result != NULL) { | ||||||||||
| passwd_marshal_func(result, NULL, buffer_size); | ||||||||||
| *buffer = malloc(*buffer_size); | ||||||||||
| assert(*buffer != NULL); | ||||||||||
| passwd_marshal_func(result, *buffer, buffer_size); | ||||||||||
| } | ||||||||||
| TRACE_OUT(passwd_lookup_func); | TRACE_OUT(passwd_lookup_func); | |||||||||
| return (result == NULL ? NS_NOTFOUND : NS_SUCCESS); | return (*buffer == NULL ? | |||||||||
| (pw_errno == 0 ? NS_NOTFOUND : NS_UNAVAIL) : | ||||||||||
| NS_SUCCESS); | ||||||||||
| } | } | |||||||||
| static void * | static void * | |||||||||
| passwd_mp_init_func(void) | passwd_mp_init_func(void) | |||||||||
| { | { | |||||||||
| TRACE_IN(passwd_mp_init_func); | TRACE_IN(passwd_mp_init_func); | |||||||||
| setpwent(); | setpwent(); | |||||||||
| TRACE_OUT(passwd_mp_init_func); | TRACE_OUT(passwd_mp_init_func); | |||||||||
| return (NULL); | return (NULL); | |||||||||
| } | } | |||||||||
| static int | static int | |||||||||
| passwd_mp_lookup_func(char **buffer, size_t *buffer_size, void *mdata) | passwd_mp_lookup_func(char **buffer, size_t *buffer_size, void *mdata) | |||||||||
| { | { | |||||||||
| struct passwd *result; | u_key ukey; | |||||||||
| TRACE_IN(passwd_mp_lookup_func); | TRACE_IN(passwd_mp_lookup_func); | |||||||||
Not Done Inline ActionsThere should be a newline after variable declarations, and here there's an extra newline before the declaration. markj: There should be a newline after variable declarations, and here there's an extra newline before… | ||||||||||
| result = getpwent(); | assert(buffer != NULL); | |||||||||
| if (result != NULL) { | assert(buffer_size != NULL); | |||||||||
| passwd_marshal_func(result, NULL, buffer_size); | *buffer_size = 0; | |||||||||
| *buffer = malloc(*buffer_size); | errno = 0; | |||||||||
| assert(*buffer != NULL); | ukey.uid = 0; | |||||||||
| passwd_marshal_func(result, *buffer, buffer_size); | *buffer = getpw(wrap_getpwent_r, ukey, buffer_size); | |||||||||
| } | ||||||||||
| TRACE_OUT(passwd_mp_lookup_func); | TRACE_OUT(passwd_mp_lookup_func); | |||||||||
| return (result == NULL ? NS_NOTFOUND : NS_SUCCESS); | return (*buffer == NULL ? | |||||||||
| (errno == 0 ? NS_NOTFOUND : NS_UNAVAIL) : | ||||||||||
| NS_SUCCESS); | ||||||||||
| } | } | |||||||||
| static void | static void | |||||||||
| passwd_mp_destroy_func(void *mdata) | passwd_mp_destroy_func(void *mdata) | |||||||||
| { | { | |||||||||
| TRACE_IN(passwd_mp_destroy_func); | TRACE_IN(passwd_mp_destroy_func); | |||||||||
| TRACE_OUT(passwd_mp_destroy_func); | TRACE_OUT(passwd_mp_destroy_func); | |||||||||
| } | } | |||||||||
| Show All 40 Lines | ||||||||||
Please remove the extra newline before each return statement. It's inconsistent with the code styles used elsewhere in nscd (and in FreeBSD generally).