1 /*
2    attmap.c - attribute mapping values and functions
3    This file is part of the nss-pam-ldapd library.
4 
5    Copyright (C) 2007-2014 Arthur de Jong
6 
7    This library is free software; you can redistribute it and/or
8    modify it under the terms of the GNU Lesser General Public
9    License as published by the Free Software Foundation; either
10    version 2.1 of the License, or (at your option) any later version.
11 
12    This library is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15    Lesser General Public License for more details.
16 
17    You should have received a copy of the GNU Lesser General Public
18    License along with this library; if not, write to the Free Software
19    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20    02110-1301 USA
21 */
22 
23 #include "config.h"
24 
25 #include <stdlib.h>
26 #include <strings.h>
27 
28 #include "attmap.h"
29 #include "log.h"
30 #include "common/expr.h"
31 
32 /* these are the bases that are defined per database */
33 extern const char *alias_bases[];
34 extern const char *ether_bases[];
35 extern const char *group_bases[];
36 extern const char *host_bases[];
37 extern const char *netgroup_bases[];
38 extern const char *network_bases[];
39 extern const char *passwd_bases[];
40 extern const char *protocol_bases[];
41 extern const char *rpc_bases[];
42 extern const char *service_bases[];
43 extern const char *shadow_bases[];
44 
base_get_var(enum ldap_map_selector map)45 const char **base_get_var(enum ldap_map_selector map)
46 {
47   switch (map)
48   {
49     case LM_ALIASES:   return alias_bases;
50     case LM_ETHERS:    return ether_bases;
51     case LM_GROUP:     return group_bases;
52     case LM_HOSTS:     return host_bases;
53     case LM_NETGROUP:  return netgroup_bases;
54     case LM_NETWORKS:  return network_bases;
55     case LM_PASSWD:    return passwd_bases;
56     case LM_PROTOCOLS: return protocol_bases;
57     case LM_RPC:       return rpc_bases;
58     case LM_SERVICES:  return service_bases;
59     case LM_SHADOW:    return shadow_bases;
60     case LM_NFSIDMAP:
61     case LM_NONE:
62     default:           return NULL;
63   }
64 }
65 
66 /* these are the scopes that are defined per database */
67 extern int alias_scope;
68 extern int ether_scope;
69 extern int group_scope;
70 extern int host_scope;
71 extern int netgroup_scope;
72 extern int network_scope;
73 extern int passwd_scope;
74 extern int protocol_scope;
75 extern int rpc_scope;
76 extern int service_scope;
77 extern int shadow_scope;
78 
scope_get_var(enum ldap_map_selector map)79 int *scope_get_var(enum ldap_map_selector map)
80 {
81   switch (map)
82   {
83     case LM_ALIASES:   return &alias_scope;
84     case LM_ETHERS:    return &ether_scope;
85     case LM_GROUP:     return &group_scope;
86     case LM_HOSTS:     return &host_scope;
87     case LM_NETGROUP:  return &netgroup_scope;
88     case LM_NETWORKS:  return &network_scope;
89     case LM_PASSWD:    return &passwd_scope;
90     case LM_PROTOCOLS: return &protocol_scope;
91     case LM_RPC:       return &rpc_scope;
92     case LM_SERVICES:  return &service_scope;
93     case LM_SHADOW:    return &shadow_scope;
94     case LM_NFSIDMAP:
95     case LM_NONE:
96     default:           return NULL;
97   }
98 }
99 
100 /* these are the filters that are defined per database */
101 extern const char *alias_filter;
102 extern const char *ether_filter;
103 extern const char *group_filter;
104 extern const char *host_filter;
105 extern const char *netgroup_filter;
106 extern const char *network_filter;
107 extern const char *passwd_filter;
108 extern const char *protocol_filter;
109 extern const char *rpc_filter;
110 extern const char *service_filter;
111 extern const char *shadow_filter;
112 
filter_get_var(enum ldap_map_selector map)113 const char **filter_get_var(enum ldap_map_selector map)
114 {
115   switch (map)
116   {
117     case LM_ALIASES:   return &alias_filter;
118     case LM_ETHERS:    return &ether_filter;
119     case LM_GROUP:     return &group_filter;
120     case LM_HOSTS:     return &host_filter;
121     case LM_NETGROUP:  return &netgroup_filter;
122     case LM_NETWORKS:  return &network_filter;
123     case LM_PASSWD:    return &passwd_filter;
124     case LM_PROTOCOLS: return &protocol_filter;
125     case LM_RPC:       return &rpc_filter;
126     case LM_SERVICES:  return &service_filter;
127     case LM_SHADOW:    return &shadow_filter;
128     case LM_NFSIDMAP:
129     case LM_NONE:
130     default:           return NULL;
131   }
132 }
133 
attmap_get_var(enum ldap_map_selector map,const char * name)134 const char **attmap_get_var(enum ldap_map_selector map, const char *name)
135 {
136   if (map == LM_ALIASES)
137   {
138     if (strcasecmp(name, "cn") == 0)                return &attmap_alias_cn;
139     if (strcasecmp(name, "rfc822MailMember") == 0)  return &attmap_alias_rfc822MailMember;
140   }
141   else if (map == LM_ETHERS)
142   {
143     if (strcasecmp(name, "cn") == 0)                return &attmap_ether_cn;
144     if (strcasecmp(name, "macAddress") == 0)        return &attmap_ether_macAddress;
145   }
146   else if (map == LM_GROUP)
147   {
148     if (strcasecmp(name, "cn") == 0)                return &attmap_group_cn;
149     if (strcasecmp(name, "userPassword") == 0)      return &attmap_group_userPassword;
150     if (strcasecmp(name, "gidNumber") == 0)         return &attmap_group_gidNumber;
151     if (strcasecmp(name, "memberUid") == 0)         return &attmap_group_memberUid;
152     if (strcasecmp(name, "member") == 0)            return &attmap_group_member;
153   }
154   else if (map == LM_HOSTS)
155   {
156     if (strcasecmp(name, "cn") == 0)                return &attmap_host_cn;
157     if (strcasecmp(name, "ipHostNumber") == 0)      return &attmap_host_ipHostNumber;
158   }
159   else if (map == LM_NETGROUP)
160   {
161     if (strcasecmp(name, "cn") == 0)                return &attmap_netgroup_cn;
162     if (strcasecmp(name, "nisNetgroupTriple") == 0) return &attmap_netgroup_nisNetgroupTriple;
163     if (strcasecmp(name, "memberNisNetgroup") == 0) return &attmap_netgroup_memberNisNetgroup;
164   }
165   else if (map == LM_NETWORKS)
166   {
167     if (strcasecmp(name, "cn") == 0)                return &attmap_network_cn;
168     if (strcasecmp(name, "ipNetworkNumber") == 0)   return &attmap_network_ipNetworkNumber;
169   }
170   else if (map == LM_PASSWD)
171   {
172     if (strcasecmp(name, "uid") == 0)               return &attmap_passwd_uid;
173     if (strcasecmp(name, "userPassword") == 0)      return &attmap_passwd_userPassword;
174     if (strcasecmp(name, "uidNumber") == 0)         return &attmap_passwd_uidNumber;
175     if (strcasecmp(name, "gidNumber") == 0)         return &attmap_passwd_gidNumber;
176     if (strcasecmp(name, "gecos") == 0)             return &attmap_passwd_gecos;
177     if (strcasecmp(name, "homeDirectory") == 0)     return &attmap_passwd_homeDirectory;
178     if (strcasecmp(name, "loginShell") == 0)        return &attmap_passwd_loginShell;
179   }
180   else if (map == LM_PROTOCOLS)
181   {
182     if (strcasecmp(name, "cn") == 0)                return &attmap_protocol_cn;
183     if (strcasecmp(name, "ipProtocolNumber") == 0)  return &attmap_protocol_ipProtocolNumber;
184   }
185   else if (map == LM_RPC)
186   {
187     if (strcasecmp(name, "cn") == 0)                return &attmap_rpc_cn;
188     if (strcasecmp(name, "oncRpcNumber") == 0)      return &attmap_rpc_oncRpcNumber;
189   }
190   else if (map == LM_SERVICES)
191   {
192     if (strcasecmp(name, "cn") == 0)                return &attmap_service_cn;
193     if (strcasecmp(name, "ipServicePort") == 0)     return &attmap_service_ipServicePort;
194     if (strcasecmp(name, "ipServiceProtocol") == 0) return &attmap_service_ipServiceProtocol;
195   }
196   else if (map == LM_SHADOW)
197   {
198     if (strcasecmp(name, "uid") == 0)               return &attmap_shadow_uid;
199     if (strcasecmp(name, "userPassword") == 0)      return &attmap_shadow_userPassword;
200     if (strcasecmp(name, "shadowLastChange") == 0)  return &attmap_shadow_shadowLastChange;
201     if (strcasecmp(name, "shadowMin") == 0)         return &attmap_shadow_shadowMin;
202     if (strcasecmp(name, "shadowMax") == 0)         return &attmap_shadow_shadowMax;
203     if (strcasecmp(name, "shadowWarning") == 0)     return &attmap_shadow_shadowWarning;
204     if (strcasecmp(name, "shadowInactive") == 0)    return &attmap_shadow_shadowInactive;
205     if (strcasecmp(name, "shadowExpire") == 0)      return &attmap_shadow_shadowExpire;
206     if (strcasecmp(name, "shadowFlag") == 0)        return &attmap_shadow_shadowFlag;
207   }
208   return NULL;
209 }
210 
attmap_set_mapping(const char ** var,const char * value)211 const char *attmap_set_mapping(const char **var, const char *value)
212 {
213   /* check if we are setting an expression */
214   if (value[0] == '"')
215   {
216     /* these attributes may contain an expression
217        (note that this needs to match the functionality in the specific
218        lookup module) */
219     if ((var != &attmap_group_userPassword) &&
220         (var != &attmap_group_member) &&
221         (var != &attmap_passwd_userPassword) &&
222         (var != &attmap_passwd_gidNumber) &&
223         (var != &attmap_passwd_gecos) &&
224         (var != &attmap_passwd_homeDirectory) &&
225         (var != &attmap_passwd_loginShell) &&
226         (var != &attmap_shadow_userPassword) &&
227         (var != &attmap_shadow_shadowLastChange) &&
228         (var != &attmap_shadow_shadowMin) &&
229         (var != &attmap_shadow_shadowMax) &&
230         (var != &attmap_shadow_shadowWarning) &&
231         (var != &attmap_shadow_shadowInactive) &&
232         (var != &attmap_shadow_shadowExpire) &&
233         (var != &attmap_shadow_shadowFlag))
234       return NULL;
235     /* the member attribute may only be set to an empty string */
236     if ((var == &attmap_group_member) && (strcmp(value, "\"\"") != 0))
237       return NULL;
238   }
239   /* check if the value will be changed */
240   if ((*var == NULL) || (strcmp(*var, value) != 0))
241     *var = strdup(value);
242   return *var;
243 }
244 
entry_expand(const char * name,void * expander_attr)245 static const char *entry_expand(const char *name, void *expander_attr)
246 {
247   MYLDAP_ENTRY *entry = (MYLDAP_ENTRY *)expander_attr;
248   const char **values;
249   if (strcasecmp(name, "dn") == 0)
250     return myldap_get_dn(entry);
251   values = myldap_get_values(entry, name);
252   if (values == NULL)
253     return "";
254   /* TODO: handle userPassword attribute specially */
255   if ((values[0] != NULL) && (values[1] != NULL))
256   {
257     log_log(LOG_WARNING, "%s: %s: multiple values",
258             myldap_get_dn(entry), name);
259   }
260   return values[0];
261 }
262 
attmap_get_value(MYLDAP_ENTRY * entry,const char * attr,char * buffer,size_t buflen)263 const char *attmap_get_value(MYLDAP_ENTRY *entry, const char *attr,
264                              char *buffer, size_t buflen)
265 {
266   const char **values;
267   /* check and clear buffer */
268   if ((buffer == NULL) || (buflen <= 0))
269     return NULL;
270   buffer[0] = '\0';
271   /* for simple values just return the attribute */
272   if (attr[0] != '"')
273   {
274     values = myldap_get_values(entry, attr);
275     if ((values == NULL) || (values[0] == NULL))
276       return NULL;
277     if (strlen(values[0]) >= buflen)
278     {
279       log_log(LOG_ERR, "attmap_get_value(): buffer too small (%lu required)",
280               (unsigned long) strlen(values[0]));
281       return NULL;
282     }
283     strncpy(buffer, values[0], buflen);
284     buffer[buflen - 1] = '\0';
285     return buffer;
286     /* TODO: maybe warn when multiple values are found */
287   }
288   /* we have an expression, try to parse */
289   if ((attr[strlen(attr) - 1] != '"') ||
290       (expr_parse(attr + 1, buffer, buflen, entry_expand, (void *)entry) == NULL))
291   {
292     log_log(LOG_ERR, "attribute mapping %s is invalid", attr);
293     buffer[0] = '\0';
294     return NULL;
295   }
296   /* strip trailing " */
297   if (buffer[strlen(buffer) - 1] == '"')
298     buffer[strlen(buffer) - 1] = '\0';
299   return buffer;
300 }
301 
attmap_add_attributes(SET * set,const char * attr)302 SET *attmap_add_attributes(SET *set, const char *attr)
303 {
304   if (attr[0] != '\"')
305     set_add(set, attr);
306   else
307     expr_vars(attr, set);
308   return set;
309 }
310