// Copyright status: this file is in the public domain. #include #include #include #include #include #include #include "internal.h" #define XAUTH_FILE_LOCAL 256 #define XAUTH_FILE_INET 0 #define XAUTH_FILE_INET6 6 typedef struct authent AUTHENT; typedef struct priv_local PRIV_LOCAL; struct authent { unsigned int family; unsigned int addrlen; char *addr; unsigned int num; unsigned int protolen; char *proto; unsigned int datalen; char *data; } ; struct priv_local { int hnl; char *hn; } ; static int get2(FILE *f) { int c1; int c2; c1 = getc(f); if (c1 == EOF) return(-1); c2 = getc(f); if (c2 == EOF) return(-1); return((c1*256)+c2); } static int getn(FILE *f, int n, unsigned char *v) { int c; for (;n>0;n--) { c = getc(f); if (c == EOF) return(-1); *v++ = c; } return(0); } static int getstr(FILE *f, unsigned int *lenp, char **strp) { int l; char *s; l = get2(f); if (l < 0) return(-1); *lenp = l; s = malloc(l); if (! s) return(-1); free(*strp); *strp = s; return(getn(f,l,(void *)s)); } static int parse_num(const char *s, unsigned int l) { int v; int c; int dv; v = 0; for (;l>0;s++,l--) { c = *s; switch (c) { case '0': dv = 0; break; case '1': dv = 1; break; case '2': dv = 2; break; case '3': dv = 3; break; case '4': dv = 4; break; case '5': dv = 5; break; case '6': dv = 6; break; case '7': dv = 7; break; case '8': dv = 8; break; case '9': dv = 9; break; default: return(-1); break; } v = (v * 10) + dv; } return(v); } static int find_auth_entry(AUTHENT *ae, int type, int dno, int (*match)(AUTHENT *, void *), void *matchdata) { const char *home; const char *path; char *pfree; FILE *f; int c; unsigned int numlen; char *numstr; path = getenv("XAUTHORITY"); if (path) { pfree = 0; } else { home = getenv("HOME"); if (! home) return(-1); if (asprintf(&pfree,"%s/.Xauthority",home) < 0) return(-1); path = pfree; } f = fopen(path,"r"); if (f == 0) { free(pfree); return(-1); } ae->addr = 0; numstr = 0; ae->proto = 0; ae->data = 0; while (1) { c = getc(f); if (c == EOF) break; ungetc(c,f); c = get2(f); if (c < 0) break; ae->family = c; if ( (getstr(f,&ae->addrlen,&ae->addr) < 0) || (getstr(f,&numlen,&numstr) < 0) || (getstr(f,&ae->protolen,&ae->proto) < 0) || (getstr(f,&ae->datalen,&ae->data) < 0) ) break; c = parse_num(numstr,numlen); if (c < 0) continue; ae->num = c; if (ae->family != type) continue; if (ae->num != dno) continue; if (! (*match)(ae,matchdata)) continue; fclose(f); free(numstr); return(0); } fclose(f); free(ae->addr); free(numstr); free(ae->proto); free(ae->data); return(-1); } static int match_local(AUTHENT *ae, void *plv) { PRIV_LOCAL *pl; if (ae->family != XAUTH_FILE_LOCAL) return(0); pl = plv; if (pl->hnl != ae->addrlen) return(0); return(!strncasecmp(pl->hn,ae->addr,pl->hnl)); } static int match_network(AUTHENT *ae, void *ssv) { struct sockaddr_storage *ss; ss = ssv; switch (ss->ss_family) { case AF_INET: if (ae->family != XAUTH_FILE_INET) abort(); if (ae->addrlen != 4) return(0); return(!bcmp(ae->addr,&((struct sockaddr_in *)ss)->sin_addr,4)); break; case AF_INET6: if (ae->family != XAUTH_FILE_INET6) abort(); if (ae->addrlen != 16) return(0); return(!bcmp(ae->addr,&((struct sockaddr_in6 *)ss)->sin6_addr,16)); break; default: // XXX can this happen? return(0); break; } } int lx__findauth_local(LX_CONN *c, int *aplenp, unsigned char **app, int *adlenp, unsigned char **adp) { int hna; PRIV_LOCAL pl; AUTHENT ae; hna = 8; while (1) { pl.hn = malloc(hna); if (! pl.hn) return(-1); if (gethostname(pl.hn,hna) < 0) { free(pl.hn); return(-1); } pl.hnl = strnlen(pl.hn,hna); if (pl.hnl < hna-1) break; hna *= 2; free(pl.hn); } if (find_auth_entry(&ae,256,c->os->dispno,&match_local,&pl) < 0) { free(pl.hn); return(-1); } *aplenp = ae.protolen; *app = ae.proto; *adlenp = ae.datalen; *adp = ae.data; free(ae.addr); return(0); } int lx__findauth_network(LX_CONN *c, int *aplenp, unsigned char **app, int *adlenp, unsigned char **adp) { AUTHENT ae; unsigned int type; struct sockaddr_storage ss; socklen_t sslen; sslen = sizeof(ss); if (getsockname(c->fd,(void *)&ss,&sslen) < 0) return(-1); switch (ss.ss_family) { case AF_INET: type = 0; break; case AF_INET6: type = 6; break; default: return(-1); break; } if (find_auth_entry(&ae,type,c->os->dispno,&match_network,&ss) < 0) return(-1); *aplenp = ae.protolen; *app = ae.proto; *adlenp = ae.datalen; *adp = ae.data; free(ae.addr); return(0); }