1 /*
2    service.c - service entry lookup routines
3    Parts of this file were part of the nss_ldap library (as ldap-service.c)
4    which has been forked into the nss-pam-ldapd library.
5 
6    Copyright (C) 1997-2005 Luke Howard
7    Copyright (C) 2006 West Consulting
8    Copyright (C) 2006-2014 Arthur de Jong
9 
10    This library is free software; you can redistribute it and/or
11    modify it under the terms of the GNU Lesser General Public
12    License as published by the Free Software Foundation; either
13    version 2.1 of the License, or (at your option) any later version.
14 
15    This library is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18    Lesser General Public License for more details.
19 
20    You should have received a copy of the GNU Lesser General Public
21    License along with this library; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23    02110-1301 USA
24 */
25 
26 #include "config.h"
27 
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #ifdef HAVE_STDINT_H
32 #include <stdint.h>
33 #endif /* HAVE_STDINT_H */
34 
35 #include "common.h"
36 #include "log.h"
37 #include "myldap.h"
38 #include "cfg.h"
39 #include "attmap.h"
40 
41 /* ( nisSchema.2.3 NAME 'ipService' SUP top STRUCTURAL
42  *   DESC 'Abstraction an Internet Protocol service.
43  *         Maps an IP port and protocol (such as tcp or udp)
44  *         to one or more names; the distinguished value of
45  *         the cn attribute denotes the service's canonical
46  *         name'
47  *   MUST ( cn $ ipServicePort $ ipServiceProtocol )
48  *   MAY ( description ) )
49  */
50 
51 /* the search base for searches */
52 const char *service_bases[NSS_LDAP_CONFIG_MAX_BASES] = { NULL };
53 
54 /* the search scope for searches */
55 int service_scope = LDAP_SCOPE_DEFAULT;
56 
57 /* the basic search filter for searches */
58 const char *service_filter = "(objectClass=ipService)";
59 
60 /* the attributes to request with searches */
61 const char *attmap_service_cn                = "cn";
62 const char *attmap_service_ipServicePort     = "ipServicePort";
63 const char *attmap_service_ipServiceProtocol = "ipServiceProtocol";
64 
65 /* the attribute list to request with searches */
66 static const char *service_attrs[4];
67 
mkfilter_service_byname(const char * name,const char * protocol,char * buffer,size_t buflen)68 static int mkfilter_service_byname(const char *name, const char *protocol,
69                                    char *buffer, size_t buflen)
70 {
71   char safename[BUFLEN_SAFENAME], safeprotocol[BUFLEN_SAFENAME];
72   /* escape attributes */
73   if (myldap_escape(name, safename, sizeof(safename)))
74   {
75     log_log(LOG_ERR, "mkfilter_service_byname(): safename buffer too small");
76     return -1;
77   }
78   /* build filter */
79   if (*protocol != '\0')
80   {
81     if (myldap_escape(protocol, safeprotocol, sizeof(safeprotocol)))
82     {
83       log_log(LOG_ERR, "mkfilter_service_byname(): safeprotocol buffer too small");
84       return -1;
85     }
86     return mysnprintf(buffer, buflen, "(&%s(%s=%s)(%s=%s))",
87                       service_filter, attmap_service_cn, safename,
88                       attmap_service_ipServiceProtocol, safeprotocol);
89   }
90   else
91     return mysnprintf(buffer, buflen, "(&%s(%s=%s))",
92                       service_filter, attmap_service_cn, safename);
93 }
94 
mkfilter_service_bynumber(int number,const char * protocol,char * buffer,size_t buflen)95 static int mkfilter_service_bynumber(int number, const char *protocol,
96                                      char *buffer, size_t buflen)
97 {
98   char safeprotocol[BUFLEN_SAFENAME];
99   if (*protocol != '\0')
100   {
101     if (myldap_escape(protocol, safeprotocol, sizeof(safeprotocol)))
102     {
103       log_log(LOG_ERR, "mkfilter_service_bynumber(): safeprotocol buffer too small");
104       return -1;
105     }
106     return mysnprintf(buffer, buflen, "(&%s(%s=%d)(%s=%s))",
107                       service_filter, attmap_service_ipServicePort, number,
108                       attmap_service_ipServiceProtocol, safeprotocol);
109   }
110   else
111     return mysnprintf(buffer, buflen, "(&%s(%s=%d))",
112                       service_filter, attmap_service_ipServicePort, number);
113 }
114 
service_init(void)115 void service_init(void)
116 {
117   int i;
118   /* set up search bases */
119   if (service_bases[0] == NULL)
120     for (i = 0; i < NSS_LDAP_CONFIG_MAX_BASES; i++)
121       service_bases[i] = nslcd_cfg->bases[i];
122   /* set up scope */
123   if (service_scope == LDAP_SCOPE_DEFAULT)
124     service_scope = nslcd_cfg->scope;
125   /* set up attribute list */
126   service_attrs[0] = attmap_service_cn;
127   service_attrs[1] = attmap_service_ipServicePort;
128   service_attrs[2] = attmap_service_ipServiceProtocol;
129   service_attrs[3] = NULL;
130 }
131 
write_service(TFILE * fp,MYLDAP_ENTRY * entry,const char * reqname,const char * reqprotocol)132 static int write_service(TFILE *fp, MYLDAP_ENTRY *entry,
133                          const char *reqname, const char *reqprotocol)
134 {
135   int32_t tmpint32, tmp2int32, tmp3int32;
136   const char *name;
137   const char **aliases;
138   const char **ports;
139   const char **protocols;
140   char *tmp;
141   long port;
142   int i;
143   /* get the most canonical name */
144   name = myldap_get_rdn_value(entry, attmap_service_cn);
145   /* get the other names for the service entries */
146   aliases = myldap_get_values(entry, attmap_service_cn);
147   if ((aliases == NULL) || (aliases[0] == NULL))
148   {
149     log_log(LOG_WARNING, "%s: %s: missing",
150             myldap_get_dn(entry), attmap_service_cn);
151     return 0;
152   }
153   /* if the service name is not yet found, get the first entry */
154   if (name == NULL)
155     name = aliases[0];
156   /* check case of returned services entry */
157   if ((reqname != NULL) && (STR_CMP(reqname, name) != 0))
158   {
159     for (i = 0; (aliases[i] != NULL) && (STR_CMP(reqname, aliases[i]) != 0); i++)
160       /* nothing */ ;
161     if (aliases[i] == NULL)
162       return 0; /* neither the name nor any of the aliases matched */
163   }
164   /* get the service number */
165   ports = myldap_get_values(entry, attmap_service_ipServicePort);
166   if ((ports == NULL) || (ports[0] == NULL))
167   {
168     log_log(LOG_WARNING, "%s: %s: missing",
169             myldap_get_dn(entry), attmap_service_ipServicePort);
170     return 0;
171   }
172   else if (ports[1] != NULL)
173   {
174     log_log(LOG_WARNING, "%s: %s: multiple values",
175             myldap_get_dn(entry), attmap_service_ipServicePort);
176   }
177   errno = 0;
178   port = strtol(ports[0], &tmp, 10);
179   if ((*(ports[0]) == '\0') || (*tmp != '\0'))
180   {
181     log_log(LOG_WARNING, "%s: %s: non-numeric value",
182             myldap_get_dn(entry), attmap_service_ipServicePort);
183     return 0;
184   }
185   else if ((errno != 0) || (port <= 0) || (port > (long)UINT16_MAX))
186   {
187     log_log(LOG_WARNING, "%s: %s: out of range",
188             myldap_get_dn(entry), attmap_service_ipServicePort);
189     return 0;
190   }
191   /* get protocols */
192   protocols = myldap_get_values(entry, attmap_service_ipServiceProtocol);
193   if ((protocols == NULL) || (protocols[0] == NULL))
194   {
195     log_log(LOG_WARNING, "%s: %s: missing",
196             myldap_get_dn(entry), attmap_service_ipServiceProtocol);
197     return 0;
198   }
199   /* write the entries */
200   for (i = 0; protocols[i] != NULL; i++)
201     if ((reqprotocol == NULL) || (*reqprotocol == '\0') ||
202         (STR_CMP(reqprotocol, protocols[i]) == 0))
203     {
204       WRITE_INT32(fp, NSLCD_RESULT_BEGIN);
205       WRITE_STRING(fp, name);
206       WRITE_STRINGLIST_EXCEPT(fp, aliases, name);
207       /* port number is actually a 16-bit value but we write 32 bits anyway */
208       WRITE_INT32(fp, port);
209       WRITE_STRING(fp, protocols[i]);
210     }
211   return 0;
212 }
213 
214 NSLCD_HANDLE(
215   service, byname, NSLCD_ACTION_SERVICE_BYNAME,
216   char name[BUFLEN_NAME];
217   char protocol[BUFLEN_NAME];
218   char filter[BUFLEN_FILTER];
219   READ_STRING(fp, name);
220   READ_STRING(fp, protocol);
221   log_setrequest("service=\"%s\"%s%s", name,
222                  *protocol != '\0' ? "/" : "", protocol);,
223   mkfilter_service_byname(name, protocol, filter, sizeof(filter)),
224   write_service(fp, entry, name, protocol)
225 )
226 
227 NSLCD_HANDLE(
228   service, bynumber, NSLCD_ACTION_SERVICE_BYNUMBER,
229   int number;
230   char protocol[BUFLEN_NAME];
231   char filter[BUFLEN_FILTER];
232   READ_INT32(fp, number);
233   READ_STRING(fp, protocol);
234   log_setrequest("service=%lu%s%s", (unsigned long int)number,
235                  *protocol != '\0' ? "/" : "", protocol);,
236   mkfilter_service_bynumber(number, protocol, filter, sizeof(filter)),
237   write_service(fp, entry, NULL, protocol)
238 )
239 
240 NSLCD_HANDLE(
241   service, all, NSLCD_ACTION_SERVICE_ALL,
242   const char *filter;
243   log_setrequest("service(all)");,
244   (filter = service_filter, 0),
245   write_service(fp, entry, NULL, NULL)
246 )
247