Blob Blame History Raw
/*
   attmap.c - attribute mapping values and functions
   This file is part of the nss-pam-ldapd library.

   Copyright (C) 2007-2014 Arthur de Jong

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

   This library 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
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with this library; if not, write to the Free Software
   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
   02110-1301 USA
*/

#include "config.h"

#include <stdlib.h>
#include <strings.h>

#include "attmap.h"
#include "log.h"
#include "common/expr.h"

/* these are the bases that are defined per database */
extern const char *alias_bases[];
extern const char *ether_bases[];
extern const char *group_bases[];
extern const char *host_bases[];
extern const char *netgroup_bases[];
extern const char *network_bases[];
extern const char *passwd_bases[];
extern const char *protocol_bases[];
extern const char *rpc_bases[];
extern const char *service_bases[];
extern const char *shadow_bases[];

const char **base_get_var(enum ldap_map_selector map)
{
  switch (map)
  {
    case LM_ALIASES:   return alias_bases;
    case LM_ETHERS:    return ether_bases;
    case LM_GROUP:     return group_bases;
    case LM_HOSTS:     return host_bases;
    case LM_NETGROUP:  return netgroup_bases;
    case LM_NETWORKS:  return network_bases;
    case LM_PASSWD:    return passwd_bases;
    case LM_PROTOCOLS: return protocol_bases;
    case LM_RPC:       return rpc_bases;
    case LM_SERVICES:  return service_bases;
    case LM_SHADOW:    return shadow_bases;
    case LM_NFSIDMAP:
    case LM_NONE:
    default:           return NULL;
  }
}

/* these are the scopes that are defined per database */
extern int alias_scope;
extern int ether_scope;
extern int group_scope;
extern int host_scope;
extern int netgroup_scope;
extern int network_scope;
extern int passwd_scope;
extern int protocol_scope;
extern int rpc_scope;
extern int service_scope;
extern int shadow_scope;

int *scope_get_var(enum ldap_map_selector map)
{
  switch (map)
  {
    case LM_ALIASES:   return &alias_scope;
    case LM_ETHERS:    return &ether_scope;
    case LM_GROUP:     return &group_scope;
    case LM_HOSTS:     return &host_scope;
    case LM_NETGROUP:  return &netgroup_scope;
    case LM_NETWORKS:  return &network_scope;
    case LM_PASSWD:    return &passwd_scope;
    case LM_PROTOCOLS: return &protocol_scope;
    case LM_RPC:       return &rpc_scope;
    case LM_SERVICES:  return &service_scope;
    case LM_SHADOW:    return &shadow_scope;
    case LM_NFSIDMAP:
    case LM_NONE:
    default:           return NULL;
  }
}

/* these are the filters that are defined per database */
extern const char *alias_filter;
extern const char *ether_filter;
extern const char *group_filter;
extern const char *host_filter;
extern const char *netgroup_filter;
extern const char *network_filter;
extern const char *passwd_filter;
extern const char *protocol_filter;
extern const char *rpc_filter;
extern const char *service_filter;
extern const char *shadow_filter;

const char **filter_get_var(enum ldap_map_selector map)
{
  switch (map)
  {
    case LM_ALIASES:   return &alias_filter;
    case LM_ETHERS:    return &ether_filter;
    case LM_GROUP:     return &group_filter;
    case LM_HOSTS:     return &host_filter;
    case LM_NETGROUP:  return &netgroup_filter;
    case LM_NETWORKS:  return &network_filter;
    case LM_PASSWD:    return &passwd_filter;
    case LM_PROTOCOLS: return &protocol_filter;
    case LM_RPC:       return &rpc_filter;
    case LM_SERVICES:  return &service_filter;
    case LM_SHADOW:    return &shadow_filter;
    case LM_NFSIDMAP:
    case LM_NONE:
    default:           return NULL;
  }
}

const char **attmap_get_var(enum ldap_map_selector map, const char *name)
{
  if (map == LM_ALIASES)
  {
    if (strcasecmp(name, "cn") == 0)                return &attmap_alias_cn;
    if (strcasecmp(name, "rfc822MailMember") == 0)  return &attmap_alias_rfc822MailMember;
  }
  else if (map == LM_ETHERS)
  {
    if (strcasecmp(name, "cn") == 0)                return &attmap_ether_cn;
    if (strcasecmp(name, "macAddress") == 0)        return &attmap_ether_macAddress;
  }
  else if (map == LM_GROUP)
  {
    if (strcasecmp(name, "cn") == 0)                return &attmap_group_cn;
    if (strcasecmp(name, "userPassword") == 0)      return &attmap_group_userPassword;
    if (strcasecmp(name, "gidNumber") == 0)         return &attmap_group_gidNumber;
    if (strcasecmp(name, "memberUid") == 0)         return &attmap_group_memberUid;
    if (strcasecmp(name, "member") == 0)            return &attmap_group_member;
  }
  else if (map == LM_HOSTS)
  {
    if (strcasecmp(name, "cn") == 0)                return &attmap_host_cn;
    if (strcasecmp(name, "ipHostNumber") == 0)      return &attmap_host_ipHostNumber;
  }
  else if (map == LM_NETGROUP)
  {
    if (strcasecmp(name, "cn") == 0)                return &attmap_netgroup_cn;
    if (strcasecmp(name, "nisNetgroupTriple") == 0) return &attmap_netgroup_nisNetgroupTriple;
    if (strcasecmp(name, "memberNisNetgroup") == 0) return &attmap_netgroup_memberNisNetgroup;
  }
  else if (map == LM_NETWORKS)
  {
    if (strcasecmp(name, "cn") == 0)                return &attmap_network_cn;
    if (strcasecmp(name, "ipNetworkNumber") == 0)   return &attmap_network_ipNetworkNumber;
  }
  else if (map == LM_PASSWD)
  {
    if (strcasecmp(name, "uid") == 0)               return &attmap_passwd_uid;
    if (strcasecmp(name, "userPassword") == 0)      return &attmap_passwd_userPassword;
    if (strcasecmp(name, "uidNumber") == 0)         return &attmap_passwd_uidNumber;
    if (strcasecmp(name, "gidNumber") == 0)         return &attmap_passwd_gidNumber;
    if (strcasecmp(name, "gecos") == 0)             return &attmap_passwd_gecos;
    if (strcasecmp(name, "homeDirectory") == 0)     return &attmap_passwd_homeDirectory;
    if (strcasecmp(name, "loginShell") == 0)        return &attmap_passwd_loginShell;
  }
  else if (map == LM_PROTOCOLS)
  {
    if (strcasecmp(name, "cn") == 0)                return &attmap_protocol_cn;
    if (strcasecmp(name, "ipProtocolNumber") == 0)  return &attmap_protocol_ipProtocolNumber;
  }
  else if (map == LM_RPC)
  {
    if (strcasecmp(name, "cn") == 0)                return &attmap_rpc_cn;
    if (strcasecmp(name, "oncRpcNumber") == 0)      return &attmap_rpc_oncRpcNumber;
  }
  else if (map == LM_SERVICES)
  {
    if (strcasecmp(name, "cn") == 0)                return &attmap_service_cn;
    if (strcasecmp(name, "ipServicePort") == 0)     return &attmap_service_ipServicePort;
    if (strcasecmp(name, "ipServiceProtocol") == 0) return &attmap_service_ipServiceProtocol;
  }
  else if (map == LM_SHADOW)
  {
    if (strcasecmp(name, "uid") == 0)               return &attmap_shadow_uid;
    if (strcasecmp(name, "userPassword") == 0)      return &attmap_shadow_userPassword;
    if (strcasecmp(name, "shadowLastChange") == 0)  return &attmap_shadow_shadowLastChange;
    if (strcasecmp(name, "shadowMin") == 0)         return &attmap_shadow_shadowMin;
    if (strcasecmp(name, "shadowMax") == 0)         return &attmap_shadow_shadowMax;
    if (strcasecmp(name, "shadowWarning") == 0)     return &attmap_shadow_shadowWarning;
    if (strcasecmp(name, "shadowInactive") == 0)    return &attmap_shadow_shadowInactive;
    if (strcasecmp(name, "shadowExpire") == 0)      return &attmap_shadow_shadowExpire;
    if (strcasecmp(name, "shadowFlag") == 0)        return &attmap_shadow_shadowFlag;
  }
  return NULL;
}

const char *attmap_set_mapping(const char **var, const char *value)
{
  /* check if we are setting an expression */
  if (value[0] == '"')
  {
    /* these attributes may contain an expression
       (note that this needs to match the functionality in the specific
       lookup module) */
    if ((var != &attmap_group_userPassword) &&
        (var != &attmap_group_member) &&
        (var != &attmap_passwd_userPassword) &&
        (var != &attmap_passwd_gidNumber) &&
        (var != &attmap_passwd_gecos) &&
        (var != &attmap_passwd_homeDirectory) &&
        (var != &attmap_passwd_loginShell) &&
        (var != &attmap_shadow_userPassword) &&
        (var != &attmap_shadow_shadowLastChange) &&
        (var != &attmap_shadow_shadowMin) &&
        (var != &attmap_shadow_shadowMax) &&
        (var != &attmap_shadow_shadowWarning) &&
        (var != &attmap_shadow_shadowInactive) &&
        (var != &attmap_shadow_shadowExpire) &&
        (var != &attmap_shadow_shadowFlag))
      return NULL;
    /* the member attribute may only be set to an empty string */
    if ((var == &attmap_group_member) && (strcmp(value, "\"\"") != 0))
      return NULL;
  }
  /* check if the value will be changed */
  if ((*var == NULL) || (strcmp(*var, value) != 0))
    *var = strdup(value);
  return *var;
}

static const char *entry_expand(const char *name, void *expander_attr)
{
  MYLDAP_ENTRY *entry = (MYLDAP_ENTRY *)expander_attr;
  const char **values;
  if (strcasecmp(name, "dn") == 0)
    return myldap_get_dn(entry);
  values = myldap_get_values(entry, name);
  if (values == NULL)
    return "";
  /* TODO: handle userPassword attribute specially */
  if ((values[0] != NULL) && (values[1] != NULL))
  {
    log_log(LOG_WARNING, "%s: %s: multiple values",
            myldap_get_dn(entry), name);
  }
  return values[0];
}

const char *attmap_get_value(MYLDAP_ENTRY *entry, const char *attr,
                             char *buffer, size_t buflen)
{
  const char **values;
  /* check and clear buffer */
  if ((buffer == NULL) || (buflen <= 0))
    return NULL;
  buffer[0] = '\0';
  /* for simple values just return the attribute */
  if (attr[0] != '"')
  {
    values = myldap_get_values(entry, attr);
    if ((values == NULL) || (values[0] == NULL))
      return NULL;
    if (strlen(values[0]) >= buflen)
    {
      log_log(LOG_ERR, "attmap_get_value(): buffer too small (%lu required)",
              (unsigned long) strlen(values[0]));
      return NULL;
    }
    strncpy(buffer, values[0], buflen);
    buffer[buflen - 1] = '\0';
    return buffer;
    /* TODO: maybe warn when multiple values are found */
  }
  /* we have an expression, try to parse */
  if ((attr[strlen(attr) - 1] != '"') ||
      (expr_parse(attr + 1, buffer, buflen, entry_expand, (void *)entry) == NULL))
  {
    log_log(LOG_ERR, "attribute mapping %s is invalid", attr);
    buffer[0] = '\0';
    return NULL;
  }
  /* strip trailing " */
  if (buffer[strlen(buffer) - 1] == '"')
    buffer[strlen(buffer) - 1] = '\0';
  return buffer;
}

SET *attmap_add_attributes(SET *set, const char *attr)
{
  if (attr[0] != '\"')
    set_add(set, attr);
  else
    expr_vars(attr, set);
  return set;
}