All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
edir.c
Go to the documentation of this file.
1 /*
2  * This program is is free software; you can redistribute it and/or modify
3  * it under the terms of the GNU General Public License as published by
4  * the Free Software Foundation; either version 2 of the License, or (at
5  * your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15  */
16 
17 /**
18  * $Id: ddac7e226a1bac6dc449d84b4dab9f24425255dc $
19  * @file edir.c
20  * @brief LDAP extension for reading eDirectory universal password.
21  *
22  * To contact Novell about this file by physical or electronic mail, you may
23  * find current contact information at www.novell.com.
24  *
25  * @copyright 2012 Olivier Beytrison <olivier@heliosnet.org>
26  * @copyright 2012 Alan DeKok <aland@freeradius.org>
27  * @copyright 2002-2004 Novell, Inc.
28  */
29 
30 RCSID("$Id: ddac7e226a1bac6dc449d84b4dab9f24425255dc $")
31 
32 #include <freeradius-devel/radiusd.h>
33 #include <freeradius-devel/rad_assert.h>
34 
35 #include "ldap.h"
36 
37 /* NMAS error codes */
38 #define NMAS_E_BASE (-1600)
39 
40 #define NMAS_E_FRAG_FAILURE (NMAS_E_BASE-31) /* -1631 0xFFFFF9A1 */
41 #define NMAS_E_BUFFER_OVERFLOW (NMAS_E_BASE-33) /* -1633 0xFFFFF99F */
42 #define NMAS_E_SYSTEM_RESOURCES (NMAS_E_BASE-34) /* -1634 0xFFFFF99E */
43 #define NMAS_E_INSUFFICIENT_MEMORY (NMAS_E_BASE-35) /* -1635 0xFFFFF99D */
44 #define NMAS_E_NOT_SUPPORTED (NMAS_E_BASE-36) /* -1636 0xFFFFF99C */
45 #define NMAS_E_INVALID_PARAMETER (NMAS_E_BASE-43) /* -1643 0xFFFFF995 */
46 #define NMAS_E_INVALID_VERSION (NMAS_E_BASE-52) /* -1652 0xFFFFF98C */
47 #define NMAS_E_ACCESS_NOT_ALLOWED (NMAS_E_BASE-59) /* -1659 0xFFFFF985 */
48 #define NMAS_E_INVALID_SPM_REQUEST (NMAS_E_BASE-97) /* -1697 0xFFFFF95F */
49 
50 /* OID of LDAP extenstion calls to read Universal Password */
51 #define NMASLDAP_GET_PASSWORD_REQUEST "2.16.840.1.113719.1.39.42.100.13"
52 #define NMASLDAP_GET_PASSWORD_RESPONSE "2.16.840.1.113719.1.39.42.100.14"
53 
54 #define NMAS_LDAP_EXT_VERSION 1
55 
56 /** Takes the object DN and BER encodes the data into the BER value which is used as part of the request
57  *
58  @verbatim
59  RequestBer contents:
60  clientVersion INTEGER
61  targetObjectDN OCTET STRING
62  @endverbatim
63  *
64  * @param[out] request_bv where to write the request BER value (must be freed with ber_bvfree).
65  * @param[in] dn to query for.
66  * @return
67  * - 0 on success.
68  * - < 0 on error.
69  */
70 static int ber_encode_request_data(char const *dn, struct berval **request_bv)
71 {
72  int err = 0;
73  int rc = 0;
74  BerElement *request_ber = NULL;
75 
76  if (!dn || !*dn) {
78  goto finish;
79  }
80 
81  /* Allocate a BerElement for the request parameters.*/
82  if ((request_ber = ber_alloc()) == NULL) {
83  err = NMAS_E_FRAG_FAILURE;
84  goto finish;
85  }
86 
87  rc = ber_printf(request_ber, "{io}", NMAS_LDAP_EXT_VERSION, dn, strlen(dn) + 1);
88  if (rc < 0) {
89  err = NMAS_E_FRAG_FAILURE;
90  goto finish;
91  }
92 
93  /*
94  * Convert the BER we just built to a berval that we'll
95  * send with the extended request.
96  */
97  if (ber_flatten(request_ber, request_bv) < 0) {
98  err = NMAS_E_FRAG_FAILURE;
99  goto finish;
100  }
101 
102 finish:
103  if (request_ber) ber_free(request_ber, 1);
104 
105  return err;
106 }
107 
108 /** Converts the reply into server version and a return code
109  *
110  * This function takes the reply BER Value and decodes the NMAS server version and return code and if a non
111  * null retData buffer was supplied, tries to decode the the return data and length.
112  *
113  @verbatim
114  ResponseBer contents:
115  server_version INTEGER
116  error INTEGER
117  data OCTET STRING
118  @endverbatim
119  *
120  * @param[in] reply_bv reply data from extended request.
121  * @param[out] server_version that responded.
122  * @param[out] out data.
123  * @param[out] outlen Length of data written to out.
124  * @return
125  * - 0 on success.
126  * - < 0 on error.
127  */
128 static int ber_decode_login_data(struct berval *reply_bv, int *server_version, void *out, size_t *outlen)
129 {
130  int rc = 0;
131  int err = 0;
132  BerElement *reply_ber = NULL;
133 
134  rad_assert(out != NULL);
135  rad_assert(outlen != NULL);
136 
137  if ((reply_ber = ber_init(reply_bv)) == NULL) {
139  goto finish;
140  }
141 
142  rc = ber_scanf(reply_ber, "{iis}", server_version, &err, out, outlen);
143  if (rc == -1) {
144  err = NMAS_E_FRAG_FAILURE;
145  goto finish;
146  }
147 
148 finish:
149 
150  if (reply_ber) ber_free(reply_ber, 1);
151 
152  return err;
153 }
154 
155 /** Attempt to retrieve the universal password from Novell eDirectory
156  *
157  * @param[in] ld LDAP handle.
158  * @param[in] dn of user we want to retrieve the password for.
159  * @param[out] password Where to write the retrieved password.
160  * @param[out] passlen Length of data written to the password buffer.
161  * @return
162  * - 0 on success.
163  * - < 0 on failure.
164  */
165 int nmasldap_get_password(LDAP *ld, char const *dn, char *password, size_t *passlen)
166 {
167  int err = 0;
168  struct berval *request_bv = NULL;
169  char *reply_oid = NULL;
170  struct berval *reply_bv = NULL;
171  int server_version;
172  size_t bufsize;
173  char buffer[256];
174 
175  /* Validate parameters. */
176  if (!dn || !*dn || !passlen || !ld) {
178  }
179 
180  err = ber_encode_request_data(dn, &request_bv);
181  if (err) goto finish;
182 
183  /* Call the ldap_extended_operation (synchronously) */
184  err = ldap_extended_operation_s(ld, NMASLDAP_GET_PASSWORD_REQUEST, request_bv, NULL, NULL, &reply_oid, &reply_bv);
185  if (err) goto finish;
186 
187  /* Make sure there is a return OID */
188  if (!reply_oid) {
189  err = NMAS_E_NOT_SUPPORTED;
190  goto finish;
191  }
192 
193  /* Is this what we were expecting to get back. */
194  if (strcmp(reply_oid, NMASLDAP_GET_PASSWORD_RESPONSE) != 0) {
195  err = NMAS_E_NOT_SUPPORTED;
196  goto finish;
197  }
198 
199  /* Do we have a good returned berval? */
200  if (!reply_bv) {
201  /*
202  * No; returned berval means we experienced a rather
203  * drastic error. Return operations error.
204  */
206  goto finish;
207  }
208 
209  bufsize = sizeof(buffer);
210  err = ber_decode_login_data(reply_bv, &server_version, buffer, &bufsize);
211  if (err) goto finish;
212 
213  if (server_version != NMAS_LDAP_EXT_VERSION) {
215  goto finish;
216  }
217 
218  if (bufsize > *passlen) {
220  goto finish;
221  }
222 
223  memcpy(password, buffer, bufsize);
224  password[bufsize] = '\0';
225  *passlen = bufsize;
226 
227 finish:
228  if (reply_bv) {
229  ber_bvfree(reply_bv);
230  }
231 
232  /* Free the return OID string if one was returned. */
233  if (reply_oid) {
234  ldap_memfree(reply_oid);
235  }
236 
237  /* Free memory allocated while building the request ber and berval. */
238  if (request_bv) {
239  ber_bvfree(request_bv);
240  }
241 
242  return err;
243 }
244 
245 char const *edir_errstr(int code) {
246  switch (code) {
247  case NMAS_E_FRAG_FAILURE:
248  return "BER manipulation failed";
249 
251  return "Insufficient buffer space to write retrieved password";
252 
255  return "Insufficient memory or system resources";
256 
258  return "Server response indicated Universal Password is not supported (missing password response OID)";
259 
261  return "Bad arguments passed to eDir functions";
262 
264  return "LDAP EXT version does not match expected version" STRINGIFY(NMAS_LDAP_EXT_VERSION);
265 
267  return "Bound user does not have sufficient rights to read the Universal Password of users";
268 
270  return "Universal password is not enabled for the container of this user object";
271 
272  default:
273  return ldap_err2string(code);
274  }
275 }
#define NMAS_E_BUFFER_OVERFLOW
Definition: edir.c:41
#define NMAS_E_INVALID_VERSION
Definition: edir.c:46
static int ber_encode_request_data(char const *dn, struct berval **request_bv)
Takes the object DN and BER encodes the data into the BER value which is used as part of the request...
Definition: edir.c:70
#define NMAS_E_FRAG_FAILURE
Definition: edir.c:40
#define NMAS_E_SYSTEM_RESOURCES
Definition: edir.c:42
#define NMAS_E_ACCESS_NOT_ALLOWED
Definition: edir.c:47
#define NMAS_E_INSUFFICIENT_MEMORY
Definition: edir.c:43
#define NMAS_E_INVALID_PARAMETER
Definition: edir.c:45
#define rad_assert(expr)
Definition: rad_assert.h:38
#define NMASLDAP_GET_PASSWORD_REQUEST
Definition: edir.c:51
#define NMAS_LDAP_EXT_VERSION
Definition: edir.c:54
#define STRINGIFY(x)
Definition: build.h:34
char const * edir_errstr(int code)
Definition: edir.c:245
int nmasldap_get_password(LDAP *ld, char const *dn, char *password, size_t *passlen)
Attempt to retrieve the universal password from Novell eDirectory.
Definition: edir.c:165
#define NMASLDAP_GET_PASSWORD_RESPONSE
Definition: edir.c:52
#define RCSID(id)
Definition: build.h:135
LDAP authorization and authentication module headers.
#define NMAS_E_NOT_SUPPORTED
Definition: edir.c:44
#define NMAS_E_INVALID_SPM_REQUEST
Definition: edir.c:48
static int ber_decode_login_data(struct berval *reply_bv, int *server_version, void *out, size_t *outlen)
Converts the reply into server version and a return code.
Definition: edir.c:128