X-Git-Url: http://git.megacz.com/?p=nestedvm.git;a=blobdiff_plain;f=src%2Forg%2Fibex%2Fnestedvm%2Fsupport_aux.c;h=54181e9834bc77d6e4dfd192fa6ac1b9952f4536;hp=c3098993a3e54dd8959baf5ee771e063ffe65c72;hb=937f88333dca3f622bd9e2669e17e7473a447dd9;hpb=896193619af1e0534356ac622494ae77c7e42594 diff --git a/src/org/ibex/nestedvm/support_aux.c b/src/org/ibex/nestedvm/support_aux.c index c309899..54181e9 100644 --- a/src/org/ibex/nestedvm/support_aux.c +++ b/src/org/ibex/nestedvm/support_aux.c @@ -11,36 +11,19 @@ #include #include #include -#include #include +#include +#include +#include +#include + +#include int _syscall_set_errno(struct _reent *ptr, int err) { ptr->_errno = -err; return -1; } -extern int _stat_r(struct _reent *, const char *, struct stat *); -int _access_r(struct _reent *ptr, const char *pathname, int mode) { - struct stat statbuf; - if(_stat_r(ptr,pathname,&statbuf) < 0) return -1; - return 0; -} - -/* NestedVM doesn't, and probably never will, support this security related stuff */ -uid_t getuid() { return 0; } -gid_t getgid() { return 0; } -uid_t geteuid() { return 0; } -gid_t getegid() { return 0; } -int getgroups(int gidsetlen, gid_t *gidset) { - if(gidsetlen) *gidset = 0; - return 1; -} -mode_t umask(mode_t new) { return 0022; } -int _chmod_r(struct _reent *ptr, const char *f, mode_t mode) { return 0; } -int _fchmod_r(struct _reent *ptr, int fd, mode_t mode) { return 0; } -int _chown_r(struct _reent *ptr, const char *f, uid_t uid, gid_t gid) { return 0; } -int _fchown_r(struct _reent *ptr, int fd, uid_t uid, gid_t gid) { return 0; } - #define REENT_WRAPPER0R(f,rt) \ extern rt _##f##_r(struct _reent *ptr); \ rt f() { return _##f##_r(_REENT); } @@ -113,12 +96,28 @@ REENT_WRAPPER3(setpriority,int,int,int) REENT_WRAPPER3(connect,int,const struct sockaddr *,socklen_t) REENT_WRAPPER3(socket,int,int,int) REENT_WRAPPER3(_resolve_hostname,const char *,char*,size_t*) +REENT_WRAPPER3(_resolve_ip,int,char*,size_t) REENT_WRAPPER3(accept,int,struct sockaddr *,socklen_t*) REENT_WRAPPER5(getsockopt,int,int,int,void*,socklen_t*) REENT_WRAPPER5(setsockopt,int,int,int,const void*,socklen_t) REENT_WRAPPER3(bind,int,const struct sockaddr *,socklen_t) REENT_WRAPPER2(listen,int,int) REENT_WRAPPER2(shutdown,int,int) +REENT_WRAPPER6(sendto,int,const void*,size_t,int,const struct sockaddr*,socklen_t) +REENT_WRAPPER6(recvfrom,int,void*,size_t,int,struct sockaddr*,socklen_t*) +REENT_WRAPPER5(select,int,fd_set*,fd_set*,fd_set*,struct timeval*) +REENT_WRAPPER4(send,int,const void*,size_t,int) +REENT_WRAPPER4(recv,int,void*,size_t,int) +REENT_WRAPPER2(getgroups,int,gid_t*) +REENT_WRAPPER3(getsockname,int,struct sockaddr*,int*) +REENT_WRAPPER3(getpeername,int,struct sockaddr*,int*) +REENT_WRAPPER1(setuid,uid_t) +REENT_WRAPPER1(seteuid,uid_t) +REENT_WRAPPER1(setgid,gid_t) +REENT_WRAPPER1(setegid,gid_t) +REENT_WRAPPER2(setgroups,int,const gid_t *) +REENT_WRAPPER0R(setsid,pid_t) +REENT_WRAPPER1(fsync,int) extern int __execve_r(struct _reent *ptr, const char *path, char *const argv[], char *const envp[]); int _execve(const char *path, char *const argv[], char *const envp[]) { @@ -155,13 +154,21 @@ long _pathconf_r(struct _reent *ptr,const char *path, int name) { } } -void sync() { - /* do nothing*/ +int _sysctl_r(struct _reent *ptr, int *name, int namelen, void *oldp, size_t *oldlen, void *newp, size_t newlen) { + if(name[0] != CTL_USER) return _sysctl(name,namelen,oldp,oldlen,newp,newlen); + if(newp != NULL) { ptr->_errno = EPERM; return -1; } + if(namelen != 2) { ptr->_errno = EINVAL; return -1; } + + switch(name[1]) { + default: + fprintf(stderr,"WARNING: sysctl: Unknown name: %d\n",name[1]); + ptr->_errno = EINVAL; + return -1; + } } -int fsync(int fd) { - /* do nothing */ - return 0; +void sync() { + /* do nothing*/ } char *ttyname(int fd) { @@ -186,16 +193,6 @@ int sigaction(int sig, const struct sigaction *act, struct sigaction *oact) { return 0; } -int sigfillset(sigset_t *set) { - *set = ~((sigset_t)0); - return 0; -} - -int sigemptyset(sigset_t *set) { - *set = (sigset_t) 0; - return 0; -} - DIR *opendir(const char *path) { struct stat sb; int fd; @@ -279,6 +276,33 @@ void herror(const char *string) { fprintf(stderr,"%s: %s\n",string,hstrerror(h_errno)); } +extern int _resolve_ip(int addr, char *buf, size_t size); + +struct hostent *gethostbyaddr(const char *addr, int len, int type) { + static struct hostent hostent; + static char name[128]; + static char *aliases[1]; + static char *addr_list[1]; + static char addr_list_buf[4]; + int err,i; + + if(type != AF_INET || len != 4) return NULL; + memcpy(&i,addr,4); + memcpy(addr_list_buf,addr,4); + err = _resolve_ip(i,name,sizeof(name)); + if(err != 0) { h_errno = err; return NULL; } + + hostent.h_name = name; + hostent.h_aliases = aliases; + aliases[0] = NULL; + hostent.h_addrtype = AF_INET; + hostent.h_length = sizeof(struct in_addr); + hostent.h_addr_list = addr_list; + addr_list[0] = addr_list_buf; + + return &hostent; +} + extern int _resolve_hostname(const char *, char *buf, size_t *size); struct hostent *gethostbyname(const char *hostname) { @@ -311,6 +335,194 @@ struct hostent *gethostbyname(const char *hostname) { return &hostent; } +static struct passwd pw_passwd; +static struct group gr_group; +static FILE *passwd_fp; +static FILE *group_fp; +static char pw_name[1024]; +static char pw_password[1024]; +static char pw_gecos[1024]; +static char pw_dir[1024]; +static char pw_shell[1024]; +static char gr_name[1024]; +static char gr_passwd[1024]; +static char *gr_mem[1]; + +static int gr_parse_body(const char *buf) { + if(sscanf(buf,"%[^:]:%[^:]:%hu",gr_name,gr_passwd,&gr_group.gr_gid) < 3) return -1; + gr_group.gr_name = gr_name; + gr_group.gr_passwd = gr_passwd; + gr_group.gr_mem = gr_mem; + gr_mem[0] = NULL; + return 0; +} + +static int pw_parse_body(const char *buf) { + int pos; + if(sscanf(buf,"%[^:]:%[^:]:%d:%d:%[^:]:%[^:]:%s\n",pw_name,pw_password,&pw_passwd.pw_uid,&pw_passwd.pw_gid,pw_gecos,pw_dir,pw_shell) < 7) return -1; + pw_passwd.pw_name = pw_name; + pw_passwd.pw_passwd = pw_password; + pw_passwd.pw_gecos = pw_gecos; + pw_passwd.pw_dir = pw_dir; + pw_passwd.pw_shell = pw_shell; + pw_passwd.pw_comment = ""; + return 0; +} + +struct group *getgrnam(const char *name) { + FILE *fp; + char buf[1024]; + + if((fp=fopen("/etc/group","r"))==NULL) return NULL; + while(fgets(buf,sizeof(buf),fp)) { + if(buf[0] == '#') continue; + if(gr_parse_body(buf) < 0) { + fclose(fp); + return NULL; + } + if(strcmp(name,gr_name)==0) { + fclose(fp); + return &gr_group; + } + } + fclose(fp); + return NULL; +} + +struct group *getgrgid(gid_t gid) { + FILE *fp; + char buf[1024]; + + if((fp=fopen("/etc/group","r"))==NULL) return NULL; + while(fgets(buf,sizeof(buf),fp)) { + if(buf[0] == '#') continue; + if(gr_parse_body(buf) < 0) { + fclose(fp); + return NULL; + } + if(gid == gr_group.gr_gid) { + fclose(fp); + return &gr_group; + } + } + fclose(fp); + return NULL; +} + +struct group *getgrent() { + char buf[1024]; + if(group_fp == NULL) return NULL; + if(fgets(buf,sizeof(buf),group_fp) == NULL) return NULL; + if(buf[0] == '#') return getgrent(); + if(gr_parse_body(buf) < 0) return NULL; + return &gr_group; +} + +void setgrent() { + if(group_fp != NULL) fclose(group_fp); + group_fp = fopen("/etc/group","r"); +} + +void endgrent() { + if(group_fp != NULL) fclose(group_fp); + group_fp = NULL; +} + +struct passwd *getpwnam(const char *name) { + FILE *fp; + char buf[1024]; + + if((fp=fopen("/etc/passwd","r"))==NULL) return NULL; + while(fgets(buf,sizeof(buf),fp)) { + if(buf[0] == '#') continue; + if(pw_parse_body(buf) < 0) { + fclose(fp); + return NULL; + } + if(strcmp(name,pw_name)==0) { + fclose(fp); + return &pw_passwd; + } + } + fclose(fp); + return NULL; +} + +struct passwd *getpwuid(uid_t uid) { + FILE *fp; + char buf[1024]; + + if((fp=fopen("/etc/passwd","r"))==NULL) return NULL; + while(fgets(buf,sizeof(buf),fp)) { + if(buf[0] == '#') continue; + if(pw_parse_body(buf) < 0) { + fclose(fp); + return NULL; + } + if(uid == pw_passwd.pw_uid) { + fclose(fp); + return &pw_passwd; + } + } + fclose(fp); + return NULL; +} + +struct passwd *getpwent() { + char buf[1024]; + if(passwd_fp == NULL) return NULL; + if(fgets(buf,sizeof(buf),passwd_fp) == NULL) return NULL; + if(buf[0] == '#') return getpwent(); + if(pw_parse_body(buf) < 0) return NULL; + return &pw_passwd; +} + +void setpwent() { + if(passwd_fp != NULL) fclose(passwd_fp); + passwd_fp = fopen("/etc/group","r"); +} + +void endpwent() { + if(passwd_fp != NULL) fclose(passwd_fp); + passwd_fp = NULL; +} + +char *getpass(const char *prompt) { + static char buf[1024]; + int len = 0; + fputs(prompt,stderr); + fflush(stdout); + if(fgets(buf,sizeof(buf),stdin)!=NULL) { + len = strlen(buf); + if(buf[len-1] == '\n') len--; + } + fputc('\n',stderr); + buf[len] = '\0'; + return buf; +} + +/* Argh... newlib's asprintf is totally broken... */ +int vasprintf(char **ret, const char *fmt, va_list ap) { + int n; + char *p; + *ret = malloc(128); /* just guess for now */ + if(!*ret) return -1; + n = vsnprintf(*ret,128,fmt,ap); + if(n < 128) { + return n; + } else { + p = realloc(*ret,n+1); + if(!p) { free(*ret); return -1; } + return vsprintf(*ret = p,fmt,ap); + } +} + +// FIXME: This needs to be in a header +char *getlogin() { + return getenv("USER"); +} + + /* * Other People's Code */ @@ -425,6 +637,105 @@ const char *path; return(bname); } +/* FreeBSD's uname */ +int +uname(name) +struct utsname *name; +{ + int mib[2], rval; + size_t len; + char *p; + int oerrno; + + rval = 0; + + mib[0] = CTL_KERN; + mib[1] = KERN_OSTYPE; + len = sizeof(name->sysname); + oerrno = errno; + if (sysctl(mib, 2, &name->sysname, &len, NULL, 0) == -1) { + if(errno == ENOMEM) + errno = oerrno; + else + rval = -1; + } + name->sysname[sizeof(name->sysname) - 1] = '\0'; + + mib[0] = CTL_KERN; + mib[1] = KERN_HOSTNAME; + len = sizeof(name->nodename); + oerrno = errno; + if (sysctl(mib, 2, &name->nodename, &len, NULL, 0) == -1) { + if(errno == ENOMEM) + errno = oerrno; + else + rval = -1; + } + name->nodename[sizeof(name->nodename) - 1] = '\0'; + + mib[0] = CTL_KERN; + mib[1] = KERN_OSRELEASE; + len = sizeof(name->release); + oerrno = errno; + if (sysctl(mib, 2, &name->release, &len, NULL, 0) == -1) { + if(errno == ENOMEM) + errno = oerrno; + else + rval = -1; + } + name->release[sizeof(name->release) - 1] = '\0'; + + /* The version may have newlines in it, turn them into spaces. */ + mib[0] = CTL_KERN; + mib[1] = KERN_VERSION; + len = sizeof(name->version); + oerrno = errno; + if (sysctl(mib, 2, &name->version, &len, NULL, 0) == -1) { + if (errno == ENOMEM) + errno = oerrno; + else + rval = -1; + } + name->version[sizeof(name->version) - 1] = '\0'; + for (p = name->version; len--; ++p) { + if (*p == '\n' || *p == '\t') { + if (len > 1) + *p = ' '; + else + *p = '\0'; + } + } + + mib[0] = CTL_HW; + mib[1] = HW_MACHINE; + len = sizeof(name->machine); + oerrno = errno; + if (sysctl(mib, 2, &name->machine, &len, NULL, 0) == -1) { + if (errno == ENOMEM) + errno = oerrno; + else + rval = -1; + } + name->machine[sizeof(name->machine) - 1] = '\0'; + return (rval); +} + +/* FreeBSD's gethostname */ +int +gethostname(name, namelen) +char *name; +int namelen; +{ + int mib[2]; + size_t size; + + mib[0] = CTL_KERN; + mib[1] = KERN_HOSTNAME; + size = namelen; + if (sysctl(mib, 2, name, &size, NULL, 0) == -1) + return (-1); + return (0); +} /* FreeBSD's daemon() - modified for nestedvm */ int @@ -442,8 +753,8 @@ int nochdir, noclose; _exit(0); } - /*if (setsid() == -1) - return (-1);*/ + if (setsid() == -1) + return (-1); if (!nochdir) (void)chdir("/"); @@ -457,3 +768,184 @@ int nochdir, noclose; } return (0); } + +/* FreeBSD's inet_addr/inet_aton */ + +/* +* Check whether "cp" is a valid ASCII representation + * of an Internet address and convert to a binary address. + * Returns 1 if the address is valid, 0 if not. + * This replaces inet_addr, the return value from which + * cannot distinguish between failure and a local broadcast address. + */ +int +inet_aton(cp, addr) +register const char *cp; +struct in_addr *addr; +{ + u_long parts[4]; + in_addr_t val; + char *c; + char *endptr; + int gotend, n; + + c = (char *)cp; + n = 0; + /* + * Run through the string, grabbing numbers until + * the end of the string, or some error + */ + gotend = 0; + while (!gotend) { + errno = 0; + val = strtoul(c, &endptr, 0); + + if (errno == ERANGE) /* Fail completely if it overflowed. */ + return (0); + + /* + * If the whole string is invalid, endptr will equal + * c.. this way we can make sure someone hasn't + * gone '.12' or something which would get past + * the next check. + */ + if (endptr == c) + return (0); + parts[n] = val; + c = endptr; + + /* Check the next character past the previous number's end */ + switch (*c) { + case '.' : + /* Make sure we only do 3 dots .. */ + if (n == 3) /* Whoops. Quit. */ + return (0); + n++; + c++; + break; + + case '\0': + gotend = 1; + break; + + default: + if (isspace((unsigned char)*c)) { + gotend = 1; + break; + } else + return (0); /* Invalid character, so fail */ + } + + } + + /* + * Concoct the address according to + * the number of parts specified. + */ + + switch (n) { + case 0: /* a -- 32 bits */ + /* + * Nothing is necessary here. Overflow checking was + * already done in strtoul(). + */ + break; + case 1: /* a.b -- 8.24 bits */ + if (val > 0xffffff || parts[0] > 0xff) + return (0); + val |= parts[0] << 24; + break; + + case 2: /* a.b.c -- 8.8.16 bits */ + if (val > 0xffff || parts[0] > 0xff || parts[1] > 0xff) + return (0); + val |= (parts[0] << 24) | (parts[1] << 16); + break; + + case 3: /* a.b.c.d -- 8.8.8.8 bits */ + if (val > 0xff || parts[0] > 0xff || parts[1] > 0xff || + parts[2] > 0xff) + return (0); + val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); + break; + } + + if (addr != NULL) + addr->s_addr = htonl(val); + return (1); +} + +/* + * ASCII internet address interpretation routine. + * The value returned is in network order. + */ +in_addr_t /* XXX should be struct in_addr :( */ +inet_addr(cp) +register const char *cp; +{ + struct in_addr val; + + if (inet_aton(cp, &val)) + return (val.s_addr); + return (INADDR_NONE); +} + +int +getgrouplist(uname, agroup, groups, grpcnt) +const char *uname; +gid_t agroup; +register gid_t *groups; +int *grpcnt; +{ + register struct group *grp; + register int i, ngroups; + int ret, maxgroups; + + ret = 0; + ngroups = 0; + maxgroups = *grpcnt; + /* + * When installing primary group, duplicate it; + * the first element of groups is the effective gid + * and will be overwritten when a setgid file is executed. + */ + groups[ngroups++] = agroup; + if (maxgroups > 1) + groups[ngroups++] = agroup; + /* + * Scan the group file to find additional groups. + */ + setgrent(); + while ((grp = getgrent())) { + for (i = 0; i < ngroups; i++) { + if (grp->gr_gid == groups[i]) + goto skip; + } + for (i = 0; grp->gr_mem[i]; i++) { + if (!strcmp(grp->gr_mem[i], uname)) { + if (ngroups >= maxgroups) { + ret = -1; + break; + } + groups[ngroups++] = grp->gr_gid; + break; + } + } +skip: ; + } + endgrent(); + *grpcnt = ngroups; + return (ret); +} + +int +initgroups(uname, agroup) +const char *uname; +gid_t agroup; +{ + gid_t groups[32], ngroups; + + ngroups = 32; + getgrouplist(uname, agroup, groups, &ngroups); + return (setgroups(ngroups, groups)); +}