X-Git-Url: http://dolda2000.com/gitweb/?a=blobdiff_plain;f=lib%2Fuilib.c;h=f7a6b28554c2e11c4ea86168b4c3835b97ae2a84;hb=8affe2ff5a4c2125128d9a9510aa67b29c0c0b18;hp=034c8233fd0dd1dd356094447e75eee3c64873ff;hpb=12383d48e624213114482f29af819ff77aef70fa;p=doldaconnect.git diff --git a/lib/uilib.c b/lib/uilib.c index 034c823..f7a6b28 100644 --- a/lib/uilib.c +++ b/lib/uilib.c @@ -96,8 +96,12 @@ static int state = -1; static int fd = -1; static iconv_t ichandle; static int resetreader = 1; -static char *dchostname = NULL; static struct addrinfo *hostlist = NULL, *curhost = NULL; +struct { + char *hostname; + int family; + int sentcreds; +} servinfo; static struct dc_response *makeresp(void) { @@ -276,9 +280,9 @@ void dc_disconnect(void) while((resp = dc_getresp()) != NULL) dc_freeresp(resp); dc_uimisc_disconnected(); - if(dchostname != NULL) - free(dchostname); - dchostname = NULL; + if(servinfo.hostname != NULL) + free(servinfo.hostname); + memset(&servinfo, 0, sizeof(servinfo)); } void dc_freeresp(struct dc_response *resp) @@ -374,7 +378,7 @@ int dc_queuecmd(int (*callback)(struct dc_response *), void *data, ...) struct qcmd *qcmd; int num, freepart; va_list al; - char *final; + char *final, *sarg; wchar_t **toks; wchar_t *buf; wchar_t *part, *tpart; @@ -386,7 +390,7 @@ int dc_queuecmd(int (*callback)(struct dc_response *), void *data, ...) va_start(al, data); while((part = va_arg(al, wchar_t *)) != NULL) { - if(!wcscmp(part, L"%%a")) + if(!wcscmp(part, L"%a")) { for(toks = va_arg(al, wchar_t **); *toks != NULL; toks++) { @@ -406,25 +410,36 @@ int dc_queuecmd(int (*callback)(struct dc_response *), void *data, ...) } else { if(*part == L'%') { - /* This demands that all arguments that are passed to the - * function are of equal length, that of an int. I know - * that GCC does that on IA32 platforms, but I do not know - * which other platforms and compilers that it applies - * to. If this breaks your platform, please mail me about - * it. - */ - part = vswprintf2(tpart = (part + 1), al); - for(; *tpart != L'\0'; tpart++) + tpart = part + 1; + if(!wcscmp(tpart, L"i")) { - if(*tpart == L'%') + freepart = 1; + part = swprintf2(L"%i", va_arg(al, int)); + } else if(!wcscmp(tpart, L"s")) { + freepart = 1; + part = icmbstowcs(sarg = va_arg(al, char *), NULL); + if(part == NULL) { - if(tpart[1] == L'%') - tpart++; - else - va_arg(al, int); + if(buf != NULL) + free(buf); + return(-1); } + } else if(!wcscmp(tpart, L"ls")) { + part = va_arg(al, wchar_t *); + } else if(!wcscmp(tpart, L"ll")) { + freepart = 1; + part = swprintf2(L"%lli", va_arg(al, long long)); + } else if(!wcscmp(tpart, L"f")) { + freepart = 1; + part = swprintf2(L"%f", va_arg(al, double)); + } else if(!wcscmp(tpart, L"x")) { + freepart = 1; + part = swprintf2(L"%x", va_arg(al, int)); + } else { + if(buf != NULL) + free(buf); + return(-1); } - freepart = 1; } else { freepart = 0; } @@ -532,7 +547,8 @@ int dc_handleread(void) } } if(curhost->ai_canonname != NULL) - dchostname = sstrdup(curhost->ai_canonname); + servinfo.hostname = sstrdup(curhost->ai_canonname); + servinfo.family = curhost->ai_family; state = 1; resetreader = 1; break; @@ -744,17 +760,48 @@ int dc_handleread(void) return(0); } +static void mkcreds(struct msghdr *msg) +{ + struct ucred *ucred; + static char buf[CMSG_SPACE(sizeof(*ucred))]; + struct cmsghdr *cmsg; + + msg->msg_control = buf; + msg->msg_controllen = sizeof(buf); + cmsg = CMSG_FIRSTHDR(msg); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_CREDENTIALS; + cmsg->cmsg_len = CMSG_LEN(sizeof(*ucred)); + ucred = (struct ucred *)CMSG_DATA(cmsg); + ucred->pid = getpid(); + ucred->uid = getuid(); + ucred->gid = getgid(); + msg->msg_controllen = cmsg->cmsg_len; +} + int dc_handlewrite(void) { int ret; int errnobak; + struct msghdr msg; + struct iovec bufvec; switch(state) { case 1: if(queue->buflen > 0) { - ret = send(fd, queue->buf, queue->buflen, MSG_NOSIGNAL | MSG_DONTWAIT); + memset(&msg, 0, sizeof(msg)); + msg.msg_iov = &bufvec; + msg.msg_iovlen = 1; + bufvec.iov_base = queue->buf; + bufvec.iov_len = queue->buflen; + if((servinfo.family == PF_UNIX) && !servinfo.sentcreds) + { + mkcreds(&msg); + servinfo.sentcreds = 1; + } + ret = sendmsg(fd, &msg, MSG_NOSIGNAL | MSG_DONTWAIT); if(ret < 0) { if((errno == EAGAIN) || (errno == EINTR)) @@ -1049,30 +1096,39 @@ static struct addrinfo *resolvhost(char *host) return(NULL); } -static struct addrinfo *defaulthost(void) +static struct addrinfo *getlocalai(void) { struct addrinfo *ret; struct passwd *pwd; char *tmp; - char dn[1024]; - - if(((tmp = getenv("DCSERVER")) != NULL) && *tmp) - return(resolvhost(tmp)); + ret = NULL; if((getuid() != 0) && ((pwd = getpwuid(getuid())) != NULL)) { tmp = sprintf2("/tmp/doldacond-%s", pwd->pw_name); - ret = gaicat(ret, unixgai(SOCK_STREAM, tmp)); + ret = unixgai(SOCK_STREAM, tmp); free(tmp); } ret = gaicat(ret, unixgai(SOCK_STREAM, "/var/run/doldacond.sock")); + return(ret); +} + +static struct addrinfo *defaulthost(void) +{ + struct addrinfo *ret; + char *tmp; + char dn[1024]; + + if(((tmp = getenv("DCSERVER")) != NULL) && *tmp) + return(resolvhost(tmp)); + ret = getlocalai(); ret = gaicat(ret, resolvtcp("localhost", 1500)); if(!getdomainname(dn, sizeof(dn)) && *dn && strcmp(dn, "(none)")) ret = gaicat(ret, resolvsrv(dn)); return(ret); } -int dc_connect(char *host) +static int dc_connectai(struct addrinfo *hosts) { struct qcmd *qcmd; int errnobak; @@ -1082,12 +1138,7 @@ int dc_connect(char *host) state = -1; if(hostlist != NULL) freeaddrinfo(hostlist); - if(!host || !*host) - hostlist = defaulthost(); - else - hostlist = resolvhost(host); - if(hostlist == NULL) - return(-1); + hostlist = hosts; for(curhost = hostlist; curhost != NULL; curhost = curhost->ai_next) { if((fd = socket(curhost->ai_family, curhost->ai_socktype, curhost->ai_protocol)) < 0) @@ -1108,7 +1159,8 @@ int dc_connect(char *host) fd = -1; } else { if(curhost->ai_canonname != NULL) - dchostname = sstrdup(curhost->ai_canonname); + servinfo.hostname = sstrdup(curhost->ai_canonname); + servinfo.family = curhost->ai_family; state = 1; break; } @@ -1118,6 +1170,33 @@ int dc_connect(char *host) return(fd); } +int dc_connect(char *host) +{ + struct addrinfo *ai; + int ret; + + if(!host || !*host) + ai = defaulthost(); + else + ai = resolvhost(host); + if(ai == NULL) + return(-1); + if((ret = dc_connectai(ai)) != 0) + freeaddrinfo(ai); + return(ret); +} + +int dc_connectlocal(void) +{ + struct addrinfo *ai; + int ret; + + ai = getlocalai(); + if((ret = dc_connectai(ai)) != 0) + freeaddrinfo(ai); + return(ret); +} + struct dc_intresp *dc_interpret(struct dc_response *resp) { int i; @@ -1188,7 +1267,25 @@ void dc_freeires(struct dc_intresp *ires) free(ires); } +int dc_checkprotocol(struct dc_response *resp, int revision) +{ + struct dc_intresp *ires; + int low, high; + + if(resp->code != 201) + return(-1); + resp->curline = 0; + if((ires = dc_interpret(resp)) == NULL) + return(-1); + low = ires->argv[0].val.num; + high = ires->argv[0].val.num; + dc_freeires(ires); + if((revision < low) || (revision > high)) + return(-1); + return(0); +} + const char *dc_gethostname(void) { - return(dchostname); + return(servinfo.hostname); }