jabberd2  2.2.16
util/jid.c
Go to the documentation of this file.
00001 /*
00002  * jabberd - Jabber Open Source Server
00003  * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney,
00004  *                    Ryan Eatmon, Robert Norris
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA
00019  */
00020 
00021 #include "util.h"
00022 #include <stringprep.h>
00023 
00025 static jid_t jid_reset_components_internal(jid_t jid, const unsigned char *node, const unsigned char *domain, const unsigned char *resource, int prepare);
00026 
00028 static int jid_prep_pieces(char *node, char *domain, char *resource) {
00029     if(node[0] != '\0')
00030         if(stringprep_xmpp_nodeprep(node, 1024) != 0)
00031             return 1;
00032 
00033     if(stringprep_nameprep(domain, 1024) != 0)
00034         return 1;
00035 
00036     if(resource[0] != '\0')
00037         if(stringprep_xmpp_resourceprep(resource, 1024) != 0)
00038             return 1;
00039 
00040     return 0;
00041 }
00042 
00044 int jid_prep(jid_t jid)
00045 {
00046     char node[MAXLEN_JID_COMP+1];
00047     char domain[MAXLEN_JID_COMP+1];
00048     char resource[MAXLEN_JID_COMP+1];
00049 
00050     if(jid->node != NULL) {
00051         strncpy(node, jid->node, MAXLEN_JID_COMP);
00052         node[MAXLEN_JID_COMP]='\0';
00053     }
00054     else
00055         node[0] = '\0';
00056 
00057     if(jid->domain != NULL) {
00058         strncpy(domain, jid->domain, MAXLEN_JID_COMP);
00059         domain[MAXLEN_JID_COMP]='\0';
00060     }
00061     else
00062         domain[0] = '\0';
00063 
00064     if(jid->resource != NULL) {
00065         strncpy(resource, jid->resource, MAXLEN_JID_COMP);
00066         resource[MAXLEN_JID_COMP]='\0';
00067     }
00068     else
00069         resource[0] = '\0';
00070 
00071     if(jid_prep_pieces(node, domain, resource) != 0)
00072         return 1;
00073 
00074     /* put prepared components into jid */
00075     jid_reset_components_internal(jid, node, domain, resource, 0);
00076 
00077     return 0;
00078 }
00079 
00081 jid_t jid_new(const unsigned char *id, int len) {
00082     jid_t jid, ret;
00083 
00084     jid = malloc(sizeof(struct jid_st));
00085     jid->jid_data = NULL;
00086 
00087     ret = jid_reset(jid, id, len);
00088     if(ret == NULL) {
00089         if(len < 0) {
00090            log_debug(ZONE, "invalid jid: %s", id);   
00091         } else {
00092            log_debug(ZONE, "invalid jid: %.*s", len, id);
00093         }
00094         free(jid);
00095     }
00096 
00097     return ret;
00098 }
00099 
00102 void jid_static(jid_t jid, jid_static_buf *buf)
00103 {
00104     /* clear jid */
00105     memset(jid, 0, sizeof(*jid));
00106 
00107     /* set buffer */
00108     jid->jid_data = (unsigned char *)buf;
00109 }
00110 
00111 
00113 jid_t jid_reset(jid_t jid, const unsigned char *id, int len) {
00114     unsigned char *myid, *cur, *olddata=NULL;
00115 
00116     assert((int) (jid != NULL));
00117 
00118     if (jid->jid_data != NULL) {
00119         if(jid->jid_data_len != 0)
00120             free(jid->jid_data);
00121         else
00122             olddata = jid->jid_data; /* store pointer to old data */
00123     }
00124     memset(jid, 0, sizeof(struct jid_st));
00125     jid->dirty = 1;
00126     jid->node = "";
00127     jid->domain = "";
00128     jid->resource = "";
00129 
00130     /* nice empty jid */
00131     if(id == NULL)
00132         return jid;
00133 
00134     if(len < 0)
00135         len = strlen(id);
00136 
00137     if((len == 0) || (len > MAXLEN_JID))
00138         return NULL;
00139 
00140     if(olddata != NULL)
00141         myid = olddata; /* use static buffer */
00142     else {
00143         jid->jid_data_len = sizeof(char) * (len + 1);
00144         myid = (char *) malloc(jid->jid_data_len);
00145     }
00146     sprintf(myid, "%.*s", len, id);
00147 
00148     /* fail - only a resource or leading @ */
00149     if(myid[0] == '/' || myid[0] == '@') {
00150         if(olddata == NULL) free(myid);
00151         return NULL;
00152     }
00153 
00154     /* get the resource first */
00155     cur = strstr(myid, "/");
00156 
00157     if(cur != NULL)
00158     {
00159         *cur = '\0';
00160         cur++;
00161         if(strlen(cur) > 0) {
00162             jid->resource = cur;
00163         } else {
00164             /* fail - a resource separator but nothing after it */
00165             if(olddata == NULL) free(myid);
00166             return NULL;
00167         }
00168     }
00169 
00170     /* find the domain */
00171     cur = strstr(myid, "@");
00172     if(cur != NULL) {
00173         *cur = '\0';
00174         cur++;
00175         if(strlen(cur) == 0) {
00176             /* no domain part, bail out */
00177             if(olddata == NULL) free(myid);
00178             return NULL;
00179         }
00180         jid->domain = cur;
00181         jid->node = myid;
00182     } else {
00183         /* no @, so it's a domain only */
00184         jid->domain = myid;
00185     }
00186 
00187     jid->jid_data = myid;
00188 
00189     if(jid_prep(jid) != 0) {
00190         if(olddata == NULL) free(myid);
00191         jid->jid_data = NULL;
00192         return NULL;
00193     }
00194 
00195     return jid;
00196 }
00197 
00199 static jid_t jid_reset_components_internal(jid_t jid, const unsigned char *node, const unsigned char *domain, const unsigned char *resource, int prepare) {
00200     unsigned char *olddata=NULL;
00201     int node_l,domain_l,resource_l;
00202     int dataStatic;
00203     jid_static_buf staticTmpBuf;
00204 
00205     assert((int) (jid != NULL));
00206 
00207     if(jid->jid_data != NULL)
00208         olddata = jid->jid_data; /* Store old data before clearing JID */
00209 
00210     dataStatic = ((jid->jid_data != NULL) && (jid->jid_data_len == 0));
00211 
00212     if (jid->_user != NULL )
00213         free(jid->_user);
00214     if (jid->_full != NULL )
00215         free(jid->_full);
00216 
00217     memset(jid, 0, sizeof(struct jid_st));
00218 
00219     /* get lengths */
00220     node_l = strlen(node);
00221     domain_l = strlen(domain);
00222     resource_l = strlen(resource);
00223 
00224     if(node_l > MAXLEN_JID_COMP)
00225         node_l = MAXLEN_JID_COMP;
00226 
00227     if(domain_l > MAXLEN_JID_COMP)
00228         domain_l = MAXLEN_JID_COMP;
00229 
00230     if(resource_l > MAXLEN_JID_COMP)
00231         resource_l = MAXLEN_JID_COMP;
00232     
00233     if(dataStatic) {
00234         /* use static buffer */
00235         jid->jid_data = staticTmpBuf;
00236     }
00237     else {
00238         /* allocate new data buffer */
00239         jid->jid_data_len = node_l+domain_l+resource_l+3;
00240         jid->jid_data = realloc(jid->jid_data, jid->jid_data_len);
00241     }
00242 
00243     /* copy to buffer */
00244     jid->node = jid->jid_data;
00245     strncpy(jid->node, node, node_l);
00246     jid->node[node_l] = 0;
00247     
00248     jid->domain = jid->node + node_l + 1;
00249     strncpy(jid->domain, domain, domain_l);
00250     jid->domain[domain_l] = 0;
00251 
00252     jid->resource = jid->domain + domain_l + 1;
00253     strncpy(jid->resource, resource, resource_l);
00254     jid->resource[resource_l] = 0;
00255 
00256     /* Free old data buffer. Postponed to this point so that arguments may point (in)to old jid data. */
00257     if((!dataStatic) && (olddata != NULL))
00258         free(olddata);
00259     
00260     if(prepare) {
00261         if(jid_prep(jid) != 0)
00262             return NULL;
00263     }
00264 
00265     jid->dirty = 1;
00266 
00267     if (dataStatic) {
00268         jid->jid_data = olddata; /* Return pointer to the original static buffer */
00269         memcpy(jid->jid_data,staticTmpBuf,node_l+domain_l+resource_l+3); /* Copy data from tmp buf to original buffer */
00270 
00271         /* Relocate pointers */
00272         jid->node = olddata+(jid->node-(unsigned char *)staticTmpBuf);
00273         jid->domain = olddata+(jid->domain-(unsigned char *)staticTmpBuf);
00274         jid->resource = olddata+(jid->resource-(unsigned char *)staticTmpBuf);
00275     }
00276 
00277     return jid;
00278 }
00279 
00281 jid_t jid_reset_components(jid_t jid, const unsigned char *node, const unsigned char *domain, const unsigned char *resource) {
00282     return jid_reset_components_internal(jid, node, domain, resource, 1);
00283 }
00284 
00286 void jid_free(jid_t jid)
00287 {
00288     if((jid->jid_data != NULL) && (jid->jid_data_len != 0))
00289         free(jid->jid_data);
00290     if (jid->_user != NULL )
00291         free(jid->_user);
00292     if (jid->_full != NULL )
00293         free(jid->_full);
00294     if (jid != NULL )
00295         free(jid);
00296 }
00297 
00299 void jid_expand(jid_t jid)
00300 {
00301     int nlen, dlen, rlen, ulen;
00302     
00303     if((!jid->dirty) && (jid->_full))
00304         return; /* Not dirty & already expanded */
00305 
00306     if(*jid->domain == '\0') {
00307       /* empty */
00308       jid->_full = (unsigned char*) realloc(jid->_full, 1);
00309       jid->_full[0] = 0;
00310       return;
00311     }
00312 
00313     nlen = strlen(jid->node);
00314     dlen = strlen(jid->domain);
00315     rlen = strlen(jid->resource);
00316 
00317     if(nlen == 0) {
00318         ulen = dlen+1;
00319         jid->_user = (unsigned char*) realloc(jid->_user, ulen);
00320         strcpy(jid->_user, jid->domain);
00321     } else {
00322         ulen = nlen+1+dlen+1;
00323         jid->_user = (unsigned char*) realloc(jid->_user, ulen);
00324         snprintf(jid->_user, ulen, "%s@%s", jid->node, jid->domain);
00325     }
00326 
00327     if(rlen == 0) {
00328         jid->_full = (unsigned char*) realloc(jid->_full, ulen);
00329         strcpy(jid->_full, jid->_user);
00330     } else {
00331         jid->_full = (unsigned char*) realloc(jid->_full, ulen+1+rlen);
00332         snprintf(jid->_full, ulen+1+rlen, "%s/%s", jid->_user, jid->resource);
00333     }
00334 
00335     jid->dirty = 0;
00336 }
00337 
00339 const unsigned char *jid_user(jid_t jid)
00340 {
00341     jid_expand(jid);
00342 
00343     return jid->_user;
00344 }
00345 
00347 const unsigned char *jid_full(jid_t jid)
00348 {
00349     jid_expand(jid);
00350 
00351     return jid->_full;
00352 }
00353 
00355 int jid_compare_user(jid_t a, jid_t b)
00356 {
00357     jid_expand(a);
00358     jid_expand(b);
00359 
00360     return strcmp(a->_user, b->_user);
00361 }
00362 
00364 int jid_compare_full(jid_t a, jid_t b)
00365 {
00366     jid_expand(a);
00367     jid_expand(b);
00368 
00369     return strcmp(a->_full, b->_full);
00370 }
00371 
00373 jid_t jid_dup(jid_t jid)
00374 {
00375     jid_t new;
00376 
00377     new = (jid_t) malloc(sizeof(struct jid_st));
00378     memcpy(new, jid, sizeof(struct jid_st));
00379     if(jid->jid_data != NULL) {
00380       if(jid->jid_data_len == 0) {
00381         /* when original jid had static buffer, allocate new dynamic buffer
00382          * of the same size as has the static buffer */
00383         jid->jid_data_len = sizeof(jid_static_buf);
00384       }
00385 
00386       /* allocate & populate new dynamic buffer */
00387       new->jid_data = malloc(new->jid_data_len);
00388       memcpy(new->jid_data, jid->jid_data, new->jid_data_len);
00389 
00390       /* relocate pointers */
00391       if(jid->node[0] == '\0')
00392           new->node = "";
00393       else
00394           new->node = new->jid_data + (jid->node - jid->jid_data);
00395       if(jid->domain[0] == '\0')
00396           new->domain = "";
00397       else
00398           new->domain = new->jid_data + (jid->domain - jid->jid_data);
00399       if(jid->resource[0] == '\0')
00400           new->resource = "";
00401       else
00402           new->resource = new->jid_data + (jid->resource - jid->jid_data);
00403     }
00404     if(jid->_user)
00405       new->_user = strdup(jid->_user);
00406     if(jid->_full)
00407       new->_full = strdup(jid->_full);
00408 
00409     return new;
00410 }
00411 
00413 int jid_search(jid_t list, jid_t jid)
00414 {
00415     jid_t cur;
00416     for(cur = list; cur != NULL; cur = cur->next)
00417         if(jid_compare_full(cur,jid) == 0)
00418             return 1;
00419     return 0;
00420 }
00421 
00423 jid_t jid_zap(jid_t list, jid_t jid)
00424 {
00425     jid_t cur, dead;
00426 
00427     if(jid == NULL || list == NULL)
00428         return NULL;
00429 
00430     /* check first */
00431     if(jid_compare_full(jid,list) == 0) {
00432         cur = list->next;
00433         jid_free(list);
00434         return cur;
00435     }
00436 
00437     /* check through the list, stopping at the previous list entry to a matching one */
00438     cur = list;
00439     while(cur != NULL)
00440     {
00441         if(cur->next == NULL)
00442             /* none match, so we're done */
00443             return list;
00444 
00445         if(jid_compare_full(cur->next, jid) == 0)
00446         {
00447             /* match, kill it */
00448             dead = cur->next;
00449             cur->next = cur->next->next;
00450             jid_free(dead);
00451 
00452             return list;
00453         }
00454 
00455         /* loop */
00456         cur = cur->next;
00457     }
00458 
00459     /* shouldn't get here */
00460     return list;
00461 }
00462 
00464 jid_t jid_append(jid_t list, jid_t jid)
00465 {
00466     jid_t scan;
00467 
00468     if(list == NULL)
00469         return jid_dup(jid);
00470 
00471     scan = list;
00472     while(scan != NULL)
00473     {
00474         /* check for dups */
00475         if(jid_compare_full(scan, jid) == 0)
00476             return list;
00477 
00478         /* tack it on to the end of the list */
00479         if(scan->next == NULL)
00480         {
00481             scan->next = jid_dup(jid);
00482             return list;
00483         }
00484 
00485         scan = scan->next;
00486     }
00487 
00488     return list;
00489 }
00490 
00492 void jid_random_part(jid_t jid, jid_part_t part)
00493 {
00494     char hashBuf[41];
00495     char randomBuf[257];
00496     int i,r;
00497 
00498     /* create random string */
00499     for(i = 0; i < 256; i++) {
00500         r = (int) (36.0 * rand() / RAND_MAX);
00501         randomBuf[i] = (r >= 0 && r <= 0) ? (r + 48) : (r + 87);
00502     }
00503     randomBuf[256] = 0;
00504 
00505     /* hash it */
00506     shahash_r(randomBuf, hashBuf);
00507 
00508     /* change jid */
00509     switch(part) {
00510        case jid_NODE:
00511            jid_reset_components(jid, hashBuf, jid->domain, jid->resource);
00512            break;
00513 
00514        case jid_DOMAIN: /* unused */
00515            jid_reset_components(jid, jid->node, hashBuf, jid->resource);
00516            break;
00517 
00518        case jid_RESOURCE:
00519            jid_reset_components(jid, jid->node, jid->domain, hashBuf);
00520            break;
00521      }
00522 
00523     /* prepare */
00524     jid_prep(jid);
00525 }
00526