/* Copyright (c) 2010, Dirk Krause All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above opyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the Dirk Krause nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @file uacl.c Useraud client module. */ /** In the uacl module. */ #define UACL_C 1 #include "useraudi.h" #line 48 "uacl.ctr" /** @file uacl.c useraud daemon client library. This module contains functions to connect to the useraud backend daemon. */ /** Abbreviation. */ #define UC USERAUD_CONNECTION /** Abbreviation. */ #define UR USERAUD_RESPONSE /** Abbreviation. */ #define UL USERAUD_RESPONSE_LINE /** Compare two response lines by line number. This function is used to build a sorted collection of response lines. @param l Left response line. @param r Right response line. @param cr Comparison criteria (ignored). @return Comparison result. */ int uacl_compare_response_lines DK_P3(void *,l, void *,r, int,cr) { int back = 0; UL *ll, *lr; if(l) { if(r) { ll = (UL *)l; lr = (UL *)r; if(ll->lineno > lr->lineno) { back = 1; } else { if(ll->lineno < lr->lineno) { back = -1; } } if(back == 0) { if(ll->text) { if(lr->text) { back = strcmp(ll->text, lr->text); } else { back = 1; } } else { if(lr->text) { back = -11; } } } } else { back = 1; } } else { if(r) { back = -1; } } return back; } void uacl_close DK_P1(UC *,u) { char *x; if(u) { if(u->sockname) { x = u->sockname; dk_delete(x); } u->sockname = NULL; u->ec = 0; dk_delete(u); } } UC * uacl_open DK_P1(char *,sockname) { UC *back = NULL; if(sockname) { back = dk_new(UC,1); if(back) { back->ec = 0; back->sockname = dkstr_dup(sockname); if(!(back->sockname)) { uacl_close(back); back = NULL; } } } return back; } void uacl_response_close DK_P1(UR *,u) { UL *l; char *x; if(u) { if(u->s_r) { if(u->i_r) { dksto_it_reset(u->i_r); while((l = (UL *)dksto_it_next(u->i_r)) != NULL) { if(l->text) { x = l->text; dk_delete(x); l->text = NULL; } l->lineno = 0UL; dk_delete(l); } dksto_it_close(u->i_r); } dksto_close(u->s_r); } u->s_r = NULL; u->i_r = NULL; dk_delete(u); } } /** Flush the data received so far. The data collected so far in \a b2 is saved as one line in the \a ur response data structure. @param uc Connection to the useraud daemon. @param ur Response structure. @param b2 Buffer containing the received data. @param b2u Number of bytes used in \a b2. @param li Pointer to variable to receive the line number. */ static void fl DK_P5(UC *,uc, UR *,ur, char *,b2, size_t *,b2u,unsigned long *,li) { char *x; UL *l; if(*b2u > 0) { l = dk_new(UL,1); if(l) { l->lineno = *li; l->text = dkstr_dup(b2); if(l->text) { if(!dksto_add(ur->s_r, (void *)l)) { x = l->text; dk_delete(x); l->text = NULL; dk_delete(l); uc->ec = UA_ERROR_MEMORY; } } else { dk_delete(l); uc->ec = UA_ERROR_MEMORY; } } else { uc->ec = UA_ERROR_MEMORY; } *b2u = 0; *li += 1UL; } } /** Put a byte to the temporary buffer, flush if necessary. @param uc Connection to the useraud daemon. @param ur Response data structure. @param c Current character to add. @param b2 Temporary buffer. @param sz Size of \a b2. @param b2u Pointer to variable to store number of bytes used in \a b2. @param l Pointer to variable storing the line number. */ static void pb DK_P7(UC *,uc,UR *,ur,char,c,char *,b2,size_t,sz,size_t *,b2u,unsigned long *,l) { switch(c) { case '\0': case '\r': case '\n': { b2[*b2u] = '\0'; fl(uc, ur, b2, b2u, l); } break; default: { if(*b2u < (sz - 1)) { b2[*b2u] = c; *b2u += 1; } else { b2[sz - 1] = '\0'; fl(uc, ur, b2, b2u, l); b2[*b2u] = c; *b2u += 1; } } break; } } UR * uacl_process DK_P2(UC *,uc, char *,request) { UR *back = NULL; /* UL *l; */ struct sockaddr_un soun; int newec = 0; /* New error code. */ int datafound = 0; /* Flag: Any response. */ int sock; /* Client socket. */ unsigned long lineno = 0UL; /* Current line number. */ int cc = 0; /* Flag: Can continue. */ int res; /* Read/write result. */ char b[USERAUD_LINESIZE]; char b2[USERAUD_LINESIZE]; size_t i; size_t b2_used = 0; if((uc) && (request)) { back = dk_new(UR,1); if(back) { back->s_r = dksto_open(0); if(back->s_r) { dksto_set_comp(back->s_r, uacl_compare_response_lines, 0); back->i_r = dksto_it_open(back->s_r); if(back->i_r) { if(strlen(uc->sockname) < 108) { soun.sun_family = AF_UNIX; strcpy(soun.sun_path, uc->sockname); sock = socket(PF_UNIX, SOCK_STREAM, 0); if(sock > -1) { if(connect(sock, (struct sockaddr *)(&soun), SZSOUN) == 0) { send(sock, request, (1+strlen(request)), 0); shutdown(sock, SHUT_WR); cc = 1; b2_used = 0; DK_MEMRES(b2,sizeof(b2)) ; while(cc) { cc = 0; res = recv(sock, b, sizeof(b), 0); if(res > 0) { datafound = 1; cc = 1; for(i = 0; i < res; i++) { pb(uc, back, b[i], b2, sizeof(b2), &b2_used, &lineno); } } } if(b2_used > 0) { if(b2_used < sizeof(b2)) { b2[b2_used] = '\0'; } else { b2[sizeof(b2) - 1] = '\0'; } fl(uc, back, b2, &b2_used, &lineno); } } else { uc->ec = UA_ERROR_CONNECT_FAILED; } close(sock); } else { uc->ec = UA_ERROR_SOCKET_FAILED; } } else { uc->ec = UA_ERROR_SOCKET_NAME_TOO_LONG; } } else { uc->ec = UA_ERROR_MEMORY; } } else { uc->ec = UA_ERROR_MEMORY; } } else { uc->ec = UA_ERROR_MEMORY; } if((newec) || (!datafound)) { uacl_response_close(back); back = NULL; if(newec) { uc->ec = newec; } else { uc->ec = UA_ERROR_NO_RESPONSE; } } } else { uc->ec = UA_ERROR_ILLEGAL_ARGUMENTS; } return back; } void uacl_response_reset DK_P1(UR *,u) { if(u) { if((u->s_r) && (u->i_r)) { dksto_it_reset(u->i_r); } } } char * uacl_response_line DK_P1(UR *,u) { char *back = NULL; UL *l; if(u) { if((u->s_r) && (u->i_r)) { l = (UL *)dksto_it_next(u->i_r); if(l) { back = l->text; } } } return back; }