Jules Colding
2003-May-19 10:26 UTC
[syslinux] [PATCH] getpwnam() implementation in tftpd.c
Hi, This patch implements a minimal getpwnam() function in tftpd.c. The reason for the patch is that I needed tftpd to work in my embedded system, which are without libnss*. The patch has been tested, and works for me. Please consider it. Best regards, jules -- Jules Colding <JuBColding at yorkref.com> York Refrigeration diff -urN tftp-hpa-0.34.orig/tftpd/Makefile tftp-hpa-0.34/tftpd/Makefile --- tftp-hpa-0.34.orig/tftpd/Makefile 2001-11-27 11:18:11.000000000 +0100 +++ tftp-hpa-0.34/tftpd/Makefile 2003-05-17 21:18:08.000000000 +0200 @@ -4,6 +4,20 @@ -include ../MCONFIG include ../MRULES +# Setting this to something else that `true' will cause tftpd to directly +# use the system's password and group functions. Assuming you use GNU libc, +# when this is not `true', you will need to install the /etc/nsswitch.conf +# configuration file and the required libnss_* libraries. This generally +# makes your embedded system quite a bit larger... If you leave this on, +# tftpd will directly use the /etc/password, /etc/group files (and your +# system will be smaller as well). +USE_PRIVATE_PWD_GRP = false + +ifeq ($(strip $(USE_PRIVATE_PWD_GRP)),true) + CFLAGS += -DUSE_PRIVATE_PWD_GRP +endif + + OBJS = tftpd.$(O) tftpsubs.$(O) recvfrom.$(O) misc.$(O) $(TFTPDOBJS) all: tftpd$(X) tftpd.8 diff -urN tftp-hpa-0.34.orig/tftpd/tftpd.c tftp-hpa-0.34/tftpd/tftpd.c --- tftp-hpa-0.34.orig/tftpd/tftpd.c 2003-04-12 08:54:58.000000000 +0200 +++ tftp-hpa-0.34/tftpd/tftpd.c 2003-05-17 21:17:41.000000000 +0200 @@ -35,6 +35,25 @@ * SUCH DAMAGE. */ +/* __getpwent() - This function has originally been copied from the + * file __getpwent.c which is part of the libc-8086/pwd package for ELKS, + * Copyright (C) 1995, 1996 Nat Friedman <ndf at linux.mit.edu>. + * + * The present code has been copied from busybox-0.60.5. + * + * The code was added to this file by Jules Colding <JuBColding at yorkref.com>. + */ + +/* getpwnam() - This function has originally been copied from the + * file getpwnam.c which is part of the libc-8086/pwd package for ELKS, + * Copyright (C) 1995, 1996 Nat Friedman <ndf at linux.mit.edu>. + * + * The present code has been copied from busybox-0.60.5. + * + * The code was added to this file by Jules Colding <JuBColding at yorkref.com>. + */ + + #include "config.h" /* Must be included first */ #include "tftpd.h" @@ -58,7 +77,6 @@ #include <signal.h> #include <netdb.h> #include <ctype.h> -#include <pwd.h> #include <limits.h> #include <syslog.h> @@ -137,6 +155,135 @@ { NULL, NULL } }; +#ifndef USE_PRIVATE_PWD_GRP +#include <pwd.h> +#else +#include <sys/types.h> +#include <features.h> +#include <stdio.h> + +/* The passwd structure. */ +struct passwd +{ + char *pw_name; /* Username. */ + char *pw_passwd; /* Password. */ + uid_t pw_uid; /* User ID. */ + gid_t pw_gid; /* Group ID. */ + char *pw_gecos; /* Real name. */ + char *pw_dir; /* Home directory. */ + char *pw_shell; /* Shell program. */ +}; + +/* to prevent a compiler warning */ +struct passwd *__getpwent(int pwd_fd); +struct passwd *getpwnam(const char *name); + +#define PWD_BUFFER_SIZE 256 +struct passwd *__getpwent(int pwd_fd) +{ + static char line_buff[PWD_BUFFER_SIZE]; + static struct passwd passwd; + char *field_begin; + char *endptr; + char *gid_ptr=NULL; + char *uid_ptr=NULL; + int line_len; + int i; + + /* We use the restart label to handle malformatted lines */ + restart: + /* Read the passwd line into the static buffer using a minimal of + syscalls. */ + if ((line_len = read(pwd_fd, line_buff, PWD_BUFFER_SIZE)) <= 0) + return NULL; + field_begin = strchr(line_buff, '\n'); + if (field_begin != NULL) + lseek(pwd_fd, (long) (1 + field_begin - (line_buff + line_len)), + SEEK_CUR); + else { /* The line is too long - skip it. :-\ */ + + do { + if ((line_len = read(pwd_fd, line_buff, PWD_BUFFER_SIZE)) <= 0) + return NULL; + } while (!(field_begin = strchr(line_buff, '\n'))); + lseek(pwd_fd, (long) (field_begin - line_buff) - line_len + 1, + SEEK_CUR); + goto restart; + } + if (*line_buff == '#' || *line_buff == ' ' || *line_buff == '\n' || + *line_buff == '\t') + goto restart; + *field_begin = '\0'; + + /* We've read the line; now parse it. */ + field_begin = line_buff; + for (i = 0; i < 7; i++) { + switch (i) { + case 0: + passwd.pw_name = field_begin; + break; + case 1: + passwd.pw_passwd = field_begin; + break; + case 2: + uid_ptr = field_begin; + break; + case 3: + gid_ptr = field_begin; + break; + case 4: + passwd.pw_gecos = field_begin; + break; + case 5: + passwd.pw_dir = field_begin; + break; + case 6: + passwd.pw_shell = field_begin; + break; + } + if (i < 6) { + field_begin = strchr(field_begin, ':'); + if (field_begin == NULL) + goto restart; + *field_begin++ = '\0'; + } + } + passwd.pw_gid = (gid_t) strtoul(gid_ptr, &endptr, 10); + if (*endptr != '\0') + goto restart; + + passwd.pw_uid = (uid_t) strtoul(uid_ptr, &endptr, 10); + if (*endptr != '\0') + goto restart; + + return &passwd; +} + +struct passwd *getpwnam(const char *name) +{ + int passwd_fd; + struct passwd *passwd; + + if (name == NULL) { + errno = EINVAL; + return NULL; + } + + if ((passwd_fd = open("/etc/passwd", O_RDONLY)) < 0) + return NULL; + + while ((passwd = __getpwent(passwd_fd)) != NULL) + if (!strcmp(passwd->pw_name, name)) { + close(passwd_fd); + return passwd; + } + + close(passwd_fd); + return NULL; +} +#endif /* USE_PRIVATE_PWD_GRP */ + + /* Simple handler for SIGHUP */ static volatile sig_atomic_t caught_sighup = 0; static void handle_sighup(int sig) @@ -247,6 +394,7 @@ } } + int main(int argc, char **argv) {