Logo Search packages:      
Sourcecode: ncpfs version File versions  Download package

rdn.c

/*
    rdn.c
    Copyright (C) 1999  Petr Vandrovec

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

    Revision history:

      1.00  1999, November 20       Petr Vandrovec <vandrove@vc.cvut.cz>
            Created this file from nwnet.c

      1.01  1999, December  5       Petr Vandrovec <vandrove@vc.cvut.cz>
            DN length check in __NWDSExtractRDN and NWDSRemoveAllTypesW

*/

#include <stddef.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>

#include <sys/mman.h>

#include "nwnet_i.h"
#include "ncplib_i.h"
#include "ncpcode.h"

struct RDNEntry {
      size_t typeLen;
      const wchar_t* type;    /* C, S, L, OU, O, CN, SA, ... */
      size_t valLen;
      const wchar_t* val;
      struct RDNEntry* up;
      struct RDNEntry* next;  /* for CN=A+Bindery Type=B... */
};

/* frees entry in case of failure */
static NWDSCCODE __NWDSAddRDN(struct RDNEntry** add, struct RDNEntry* entry, struct RDNEntry*** next) {
      if (entry->typeLen) {
            switch (entry->typeLen) {
                  case 11:
                        if (!wcsncasecmp(entry->type, L"Common Name", 11)) {
                              entry->typeLen = 2;
                              entry->type = L"CN";
                        }
                        break;
                  case 12:
                        if (!wcsncasecmp(entry->type, L"Country Name", 12)) {
                              entry->typeLen = 1;
                              entry->type = L"C";
                        }
                        break;
                  case 13:
                        if (!wcsncasecmp(entry->type, L"Locality Name", 13)) {
                              entry->typeLen = 1;
                              entry->type = L"L";
                        }
                        break;
                  case 14:
                        if (!wcsncasecmp(entry->type, L"Street Address", 14)) {
                              entry->typeLen = 2;
                              entry->type = L"SA";
                        }
                        break;
                  case 17:
                        if (!wcsncasecmp(entry->type, L"Organization Name", 17)) {
                              entry->typeLen = 1;
                              entry->type = L"O";
                        }
                        break;
                  case 22:
                        if (!wcsncasecmp(entry->type, L"State or Province Name", 22)) {
                              entry->typeLen = 1;
                              entry->type = L"S";
                        }
                        break;
                  case 24:
                        if (!wcsncasecmp(entry->type, L"Organizational Unit Name", 24)) {
                              entry->typeLen = 2;
                              entry->type = L"OU";
                        }
                        break;
            }
      }
      if ((entry->typeLen == 1) && (entry->valLen > 2) &&
          ((*entry->type == L'C') || (*entry->type == L'c'))) {
            free(entry);
            return ERR_COUNTRY_NAME_TOO_LONG;
      }
      if (*add) {
            struct RDNEntry** curr = add;
            struct RDNEntry* nextEntry = *curr;
            size_t typeLen = entry->typeLen;
            const wchar_t* type = entry->type;
            
            if (typeLen) {
                  if (!nextEntry->typeLen) {
                        free(entry);
                        return ERR_ATTR_TYPE_NOT_EXPECTED;
                  }
                  do {
                        int prop;
                        size_t l;
                        int cmp;
                  
                        nextEntry = *curr;
                        if (!nextEntry)
                              break;
                        l = typeLen;
                        prop = 0;
                        if (typeLen < nextEntry->typeLen) {
                              prop = -1;
                        } else if (typeLen > nextEntry->typeLen) {
                              l = nextEntry->typeLen;
                              prop = 1;
                        }
                        cmp = wcsncasecmp(type, nextEntry->type, l);
                        if (cmp < 0)
                              break;
                        if (cmp == 0) {
                              if (prop < 0)
                                    break;
                              if (!prop) {
                                    free(entry);
                                    return ERR_DUPLICATE_TYPE;
                              }
                        }
                        curr = &nextEntry->next;
                  } while (1);
            } else {
                  if (nextEntry->typeLen) {
                        free(entry);
                        return ERR_ATTR_TYPE_EXPECTED;
                  }
                  do {
                        nextEntry = *curr;
                        if (!nextEntry)
                              break;
                        curr = &nextEntry->next;
                  } while (1);
            }
            entry->next = nextEntry;
            *curr = entry;
            /* '+' rule in action*/
            if (next)
                  *next = &((*add)->up);
      } else {
            *add = entry;
            if (next)
                  *next = &entry->up;
      }
      return 0;
}

void __NWDSDestroyRDN(struct RDNInfo* rdn) {
      struct RDNEntry* up;
      
      up = rdn->end;
      while (up) {
            struct RDNEntry* tmp;
            
            tmp = up;
            up = up->up;
            do {
                  struct RDNEntry* tmp2;
                  
                  tmp2 = tmp;
                  tmp = tmp->next;
                  free(tmp2);
            } while (tmp);
      }
}

/* returned rdn contains pointers to DN! */
NWDSCCODE __NWDSCreateRDN(struct RDNInfo* rdn, const wchar_t* dn, size_t* trailingDots) {
      NWDSCCODE err = 0;
      int first = 1;
      struct RDNEntry** add;
      size_t dots = 0;
      struct RDNEntry* currEntry = NULL;
            
      rdn->depth = 0;
      rdn->end = NULL;
      /* map empty string to nothing */
      if (!*dn) {
            if (trailingDots)
                  *trailingDots = 0;
            return 0;
      }
      add = &rdn->end;
      do {
            wchar_t x;
            
            x = *dn++;
            if (!x) {
                  if (dots)
                        break;
                  if (!currEntry || !currEntry->val) {
                        err = ERR_EXPECTED_IDENTIFIER;
                        break;      /* end; we did not expect anything */
                  }
                  currEntry->valLen = dn-currEntry->val-1;
                  err = __NWDSAddRDN(add, currEntry, &add);
                  currEntry = NULL;
                  rdn->depth++;
                  break;      /* we have value... */
            } else if (x == '.') {
                  if (first || dots) {
                        dots++;
                  } else if (!currEntry || !currEntry->val) {
                        err = ERR_EXPECTED_IDENTIFIER;
                        break;
                  } else {
                        currEntry->valLen = dn-currEntry->val-1;
                        err = __NWDSAddRDN(add, currEntry, &add);
                        currEntry = NULL;
                        rdn->depth++;
                        dots=1;
                  }
            } else if (x == '+') {
                  if (dots || !currEntry || !currEntry->val) {
                        err = ERR_EXPECTED_IDENTIFIER;
                        break;
                  }
                  currEntry->valLen = dn-currEntry->val-1;
                  err = __NWDSAddRDN(add, currEntry, NULL);
                  currEntry = NULL;
            } else if (x == '=') {
                  if (dots || !currEntry || !currEntry->val) {
                        err = ERR_EXPECTED_IDENTIFIER;
                        break;
                  }
                  if (currEntry->type) {
                        err = ERR_EXPECTED_RDN_DELIMITER;
                        break;
                  }
                  currEntry->type = currEntry->val;
                  currEntry->typeLen = dn - currEntry->type - 1;
                  currEntry->val = NULL;
            } else {
                  if (first + dots > 1) {
                        err = ERR_EXPECTED_IDENTIFIER;
                        break;
                  }
                  first = dots = 0;
                  if (!currEntry) {
                        currEntry = (struct RDNEntry*)malloc(sizeof(*currEntry));
                        if (!currEntry) {
                              err = ERR_NOT_ENOUGH_MEMORY;
                              break;
                        }
                        memset(currEntry, 0, sizeof(*currEntry));
                  }
                  if (!currEntry->val)
                        currEntry->val = dn-1;
                  if (x == '\\') {
                        x = *dn++;
                        if (!x) {
                              err = ERR_EXPECTED_IDENTIFIER;
                              break;
                        }
                  }
            }
      } while (!err);
      if (currEntry)
            free(currEntry);
      if (!err) {
            if (trailingDots)
                  *trailingDots = dots;
            else if (dots)
                  err = ERR_EXPECTED_IDENTIFIER;
      }
      if (err)
            __NWDSDestroyRDN(rdn);
      return err;
}

static NWDSCCODE __NWDSApplyDefaultNamingRule(const struct RDNInfo* rdn) {
      size_t depth = rdn->depth;
      if (depth > 0) {
            struct RDNEntry* level = rdn->end;
            const wchar_t* type = L"CN";
            size_t typeLen = 2;     /* wcslen(type) */
            while (--depth) {
                  if (!level->typeLen) {
                        if (level->next)
                              return ERR_INCONSISTENT_MULTIAVA;
                        level->type = type;
                        level->typeLen = typeLen;
                  }
                  type = L"OU";
                  typeLen = 2;      /* wcslen(type) */
                  level = level->up;
            }
            if (!level->typeLen) {
                  if (level->next)
                        return ERR_INCONSISTENT_MULTIAVA;
                  level->type = L"O";
                  level->typeLen = 1; /* wcslen(type) */
            }
      }
      return 0;
}

static NWDSCCODE __NWDSCopyRDN(struct RDNEntry** dst, struct RDNEntry* src) {
      while (src) {
            struct RDNEntry* tmp = src;
            struct RDNEntry** dst2 = dst;
            
            do {
                  struct RDNEntry* wrt = *dst2 = (struct RDNEntry*)malloc(sizeof(*wrt));
                  if (!wrt)
                        return ERR_NOT_ENOUGH_MEMORY;
                  wrt->type = tmp->type;
                  wrt->typeLen = tmp->typeLen;
                  wrt->val = tmp->val;
                  wrt->valLen = tmp->valLen;
                  wrt->up = NULL; /* wrt->next is set later */
                  dst2 = &wrt->next;
                  tmp = tmp->next;
            } while (tmp);
            *dst2 = NULL;
            src = src->up;
            dst = &(*dst)->up;
      }
      return 0;
}

static NWDSCCODE __NWDSExtractRDN(struct RDNInfo* rdn, wchar_t* dst, size_t maxlen, int typeLess, size_t tdots) {
      struct RDNEntry* entry;
      
      entry = rdn->end;
      if (entry || tdots) {
            while (entry) {
                  struct RDNEntry* en;
            
                  en = entry;
                  while (en) {
                        if (!typeLess && en->typeLen) {
                              if (en->typeLen + 1 > maxlen)
                                    return ERR_DN_TOO_LONG;
                              maxlen -= en->typeLen + 1;
                              memcpy(dst, en->type, en->typeLen * sizeof(wchar_t));
                              dst += en->typeLen;
                              *dst++ = '=';
                        }
                        if (en->valLen > maxlen)
                              return ERR_DN_TOO_LONG;
                        maxlen -= en->valLen;
                        memcpy(dst, en->val, en->valLen * sizeof(wchar_t));
                        dst += en->valLen;
                        en = en->next;
                        if (en) {
                              if (!maxlen)
                                    return ERR_DN_TOO_LONG;
                              --maxlen;
                              *dst++ = '+';
                        }
                  }
                  entry = entry->up;
                  if (entry) {
                        if (!maxlen)
                              return ERR_DN_TOO_LONG;
                        --maxlen;
                        *dst++ = '.';
                  }
            }
            if (tdots > maxlen)
                  return ERR_DN_TOO_LONG;
            for (;tdots;tdots--)
                  *dst++ = '.';
            *dst++ = 0;
      } else
            wcscpy(dst, L"[Root]");
      return 0;
}

/* DN modification procedures */
NWDSCCODE NWDSRemoveAllTypesW(UNUSED(NWDSContextHandle ctx), const wchar_t* src,
            wchar_t* dst) {
      wchar_t c;
      wchar_t lc = 0;
      wchar_t* dst2 = dst;
      wchar_t* dste = dst + MAX_DN_CHARS;
      int bdot = 0;
      int mdot = 0;
      int dsteq = 1;

      while ((c = *src++) != 0) {
            if (c == '.') {
                  if (dsteq) {
                        /* two or more consecutive dots */
                        if (lc == '.')
                              mdot = 1;
                        /* dot on the begining of name */
                        else if (!lc)
                              bdot = 1;
                        else 
                              return ERR_EXPECTED_IDENTIFIER;
                  }
                  if (dst == dste)
                        return ERR_DN_TOO_LONG;
                  *dst++ = c;
                  dst2 = dst;
                  dsteq = 1;
            } else if (mdot) {
                  return ERR_INVALID_DS_NAME;
            } else if (c == '=') {
                  if (!dst2)
                        return ERR_EXPECTED_RDN_DELIMITER;
                  if (dsteq)
                        return ERR_EXPECTED_IDENTIFIER;     /* empty before = */
                  dst = dst2;
                  dst2 = NULL;
                  dsteq = 1;
            } else if (c == '+') {
                  if (dsteq)
                        return ERR_EXPECTED_IDENTIFIER;     /* empty before + */
                  if (dst == dste)
                        return ERR_DN_TOO_LONG;
                  *dst++ = c;
                  dst2 = dst;
                  dsteq = 1;
            } else {
                  if (dst == dste)
                        return ERR_DN_TOO_LONG;
                  dsteq = 0;
                  *dst++ = c;
                  if (c == L'\\') {
                        wchar_t tmp_c;
                        
                        tmp_c = *src++;
                        if (!tmp_c)
                              return ERR_INVALID_DS_NAME;
                        if (dst == dste)
                              return ERR_DN_TOO_LONG;
                        *dst++ = tmp_c;
                  }
            }
            lc = c;
      }
      /* DN was empty or terminated with '.', '+' or '=' */
      if (dsteq) {
            /* FIXME: Should we allow empty string? */
            /* only '.' is legal terminator */
            if (lc != '.')
                  return ERR_INVALID_DS_NAME;
            /* and we must not have dots on both end of name */
            if (bdot)
                  return ERR_INVALID_DS_NAME;
      }
      *dst++ = c;
      return 0;
}

static inline int __NWDSIsSpecialName(const wchar_t* src) {
      if (*src == '[') {
            if (!wcscasecmp(src, L"[Root]") ||
                !wcscasecmp(src, L"[Supervisor]") ||
                !wcscasecmp(src, L"[Public]") ||
                !wcscasecmp(src, L"[Self]") ||
                !wcscasecmp(src, L"[Creator]") ||
                !wcscasecmp(src, L"[Inheritance Mask]") ||
                !wcscasecmp(src, L"[Root Template]") ||
                !wcscasecmp(src, L"[Nothing]")) {
                  return 1;
            }
      }
      return 0;
}

NWDSCCODE NWDSCanonicalizeNameW(NWDSContextHandle ctx, const wchar_t* src,
            wchar_t* dst) {
      struct RDNInfo rdn;
      struct RDNInfo ctxRDN;
      struct RDNEntry* ctxEntry;
      struct RDNEntry** rdnEntry;
      size_t dots;
      size_t oldDepth;
      int absolute = 0;
      NWDSCCODE err;
      int typeLess;
      u_int32_t flags;
      
      err = NWDSGetContext(ctx, DCK_FLAGS, &flags);
      if (err)
            return err;
      typeLess = (flags & DCV_TYPELESS_NAMES) ? 1 : 0;
      /* check for specials... */
      if (__NWDSIsSpecialName(src)) {
            wcscpy(dst, src);
            return 0;
      }
      if (*src == '.') {
            absolute = 1;
            src++;
      }
      err = __NWDSCreateRDN(&rdn, src, &dots);
      if (err)
            return err;
      err = NWDSGetContext2(ctx, DCK_RDN, &ctxRDN, sizeof(ctxRDN));
      if (err) {
            __NWDSDestroyRDN(&rdn);
            return err;
      }
      if (absolute) {
            if (dots) {
                  if (rdn.depth) {
                        __NWDSDestroyRDN(&rdn);
                        return ERR_INVALID_OBJECT_NAME;
                  }
                  dots++;
            } else {
                  if (rdn.depth) {
                        dots = ctxRDN.depth;
                  } else
                        dots++;
            }
      }
      if (dots > ctxRDN.depth) {
            __NWDSDestroyRDN(&rdn);
            return ERR_TOO_MANY_TOKENS;
      }
      ctxEntry = ctxRDN.end;
      rdnEntry = &rdn.end;
      oldDepth = rdn.depth;
      rdn.depth = rdn.depth + ctxRDN.depth - dots;
      if (dots > oldDepth) {
            while (dots-- > oldDepth) {
                  ctxEntry = ctxEntry->up;
            }
      } else if (dots < oldDepth) {
            while (dots++ < oldDepth) {
                  rdnEntry = &(*rdnEntry)->up;
            }
      }
      if (typeLess) {
            /* skip to end, ignore types */
            while (*rdnEntry) {
                  rdnEntry = &(*rdnEntry)->up;
                  ctxEntry = ctxEntry->up;
            }
      } else {
            /* copy types */
            while (*rdnEntry) {
                  struct RDNEntry* re;
                  
                  re = *rdnEntry;
                  /* copy types from context if DN have no types */
                  /* and context has types */
                  /* If both are typeless, DefaultNamingRule tries to fix it */
                  if (!re->typeLen && ctxEntry->typeLen) {
                        struct RDNEntry* ctxE = ctxEntry;
                        
                        while (re) {
                              /* context has less items than DN: boom */
                              if (!ctxE) {
                                    err = ERR_INCONSISTENT_MULTIAVA;
                                    goto returnerr;
                              }
                              re->typeLen = ctxE->typeLen;
                              re->type = ctxE->type;
                              /* fix country attribute... */
                              if ((re->typeLen == 1) && (re->valLen > 2) &&
                                  ((*re->type == L'C') || (*re->type == L'c')))
                                    re->type = L"O";
                              ctxE = ctxE->next;
                              re = re->next;
                        }     
                  }
                  rdnEntry = &(*rdnEntry)->up;
                  ctxEntry = ctxEntry->up;
            }
      }
      err = __NWDSCopyRDN(rdnEntry, ctxEntry);
      if (!err) {
            if (!typeLess)
                  err = __NWDSApplyDefaultNamingRule(&rdn);
            if (!err)
                  err = __NWDSExtractRDN(&rdn, dst, MAX_DN_CHARS, typeLess, 0);
      }
returnerr:; 
      __NWDSDestroyRDN(&rdn);
      return err;
}

NWDSCCODE NWDSAbbreviateNameW(NWDSContextHandle ctx, const wchar_t* src,
            wchar_t* dst) {
      struct RDNInfo rdn;
      struct RDNInfo ctxRDN;
      struct RDNEntry* ctxEntry;
      struct RDNEntry** rdnEntry;
      struct RDNEntry** ostop;
      size_t oldDepth;
      NWDSCCODE err;
      int typeLess;
      u_int32_t flags;
      size_t trailingDots;
      size_t adots;
      
      err = NWDSGetContext(ctx, DCK_FLAGS, &flags);
      if (err)
            return err;
      typeLess = (flags & DCV_TYPELESS_NAMES) ? 1 : 0;
      /* check for specials... */
      if (__NWDSIsSpecialName(src)) {
            wcscpy(dst, src);
            return 0;
      }
      err = __NWDSCreateRDN(&rdn, src, NULL);
      if (err)
            return err;
      err = NWDSGetContext2(ctx, DCK_RDN, &ctxRDN, sizeof(ctxRDN));
      if (err) {
            __NWDSDestroyRDN(&rdn);
            return err;
      }
      
      trailingDots = 0;
      
      ctxEntry = ctxRDN.end;
      rdnEntry = &rdn.end;
      oldDepth = rdn.depth;

      if (rdn.depth < ctxRDN.depth) {
            while (rdn.depth < ctxRDN.depth--) {
                  ctxEntry = ctxEntry->up;
                  trailingDots++;
            }
      } else if (rdn.depth > ctxRDN.depth) {
            while (rdn.depth-- >ctxRDN.depth) {
                  rdnEntry = &(*rdnEntry)->up;
            }
      }
      ostop = rdnEntry;
      adots = 0;
      while (*rdnEntry) {
            struct RDNEntry* re = *rdnEntry;
      
            adots++;
                  
            if (((re->typeLen && ctxEntry->typeLen) &&
                 ((re->typeLen != ctxEntry->typeLen) ||
                  wcsncasecmp(re->type, ctxEntry->type, re->typeLen))) ||
                 ((re->valLen != ctxEntry->valLen) ||
                  wcsncasecmp(re->val, ctxEntry->val, re->valLen))) {
                  rdnEntry = &re->up;
                  ctxEntry = ctxEntry->up;
                  trailingDots += adots;
                  ostop = rdnEntry;
                  adots = 0;
            } else {
                  rdnEntry = &re->up;
                  ctxEntry = ctxEntry->up;
            }
      }
      if (ostop == &rdn.end) {
            if (*ostop) {
                  ostop = &(*ostop)->up;  /* do 'a..' instead of '.' */
                  trailingDots++;
            } else
                  trailingDots = 0; /* emit '[Root]' instead of '.' */
      }
      ctxEntry = *ostop;
      *ostop = NULL;
      if (!err) {
            /* FIXME: should we limit length by MAX_DN_CHARS or MAX_RDN_CHARS?! */
            err = __NWDSExtractRDN(&rdn, dst, MAX_DN_CHARS, typeLess, trailingDots);
            /* FIXME: and should we return ERR_DN_TOO_LONG or ERR_RDN_TOO_LONG */
      }
      *ostop = ctxEntry;
      __NWDSDestroyRDN(&rdn);
      return err;
}


Generated by  Doxygen 1.6.0   Back to index