source: npl/internetserver/pppd_ldap/main.c @ c5c522c

gcc484ntopperl-5.22
Last change on this file since c5c522c was c5c522c, checked in by Edwin Eefting <edwin@datux.nl>, 8 years ago

initial commit, transferred from cleaned syn3 svn tree

  • Property mode set to 100644
File size: 14.9 KB
Line 
1/*******************************************************************
2* main.c
3*
4* LDAP plugin for pppd. Performs PAP authentication and sets
5* pppd parameters using LDAP as a backend.
6*
7* Copyright (c) Nordcomp LTD, Syktyvkar, Russian Federation
8* Initial version written by Grigoriy Sitkarev <sitkarew@nordcomp.ru>
9*
10* This plugin may be distributed according to the terms of the GNU
11* General Public License, version 2 or any later version.
12*
13********************************************************************/
14/*
15* 2004/05/17: first release!!! :) v 0.10
16*
17* 2004/05/19: Small bugfix. If peer's address was specified by pppd options
18* at startup use it if can't get if from LDAP. Usefull feature for those
19* who needn't have per-user fixed IP for one part and define fixed IP for
20* another through LDAP.
21*
22* 2004/05/20: Cleanups. IP address handling improved.
23*
24* 2004/05/21: Plugin can talk TLS/SSL now. Added a hack to run with servers
25* which can use only LDAPS. Code seems beeing more clean. Created TODO file.
26* v 0.11 --> v 0.11b
27*
28* 2004/05/30: Plugin can log ppp session data (login, line, IP, time etc) to
29* ppp_utmp file. A simple tool "ppp_list" can list active entries. New option
30* "lutmp" introduced. This functionality NEEDS COMPEHENSIVE TESTING.
31* v 0.11b --> v 0.12
32*
33* 2004/04/03: VERY DIRTY bugs fixed in new code. Shame of you, Grisha!!! :))
34* Didn't I told that code needs testing?
35* v 0.12a --> v 0.12b
36*/
37
38#include <stdio.h>
39#include <string.h>
40#include <errno.h>
41#include <sys/types.h>
42#include <sys/socket.h>
43#include <arpa/inet.h>
44#include <sys/fcntl.h>
45
46#include <netinet/in.h>
47#include <ldap.h>
48
49#include "pppd.h"
50#include "fsm.h"
51#include "ipcp.h"
52#include "lcp.h"
53#include "main.h"
54
55#include "ppp_utmp.h"
56
57char pppd_version[] = VERSION;
58static char rcsid[] = "$Id: main.c, v 0.12b-DatuX 2006/11/16 13:37:00 Erwin Drent Exp$";
59
60#ifndef LDAP_FILT_MAXSIZ
61#define LDAP_FILT_MAXSIZ 1024
62#endif
63
64static char ldap_host[MAX_BUF] = "localhost";
65static char ldap_dn[MAX_BUF];
66static char ldap_pw[MAX_BUF];
67static char userbasedn[MAX_BUF];
68static int      ldap_port = LDAP_PORT;
69static int      ldap_timeout = 15;
70static int      ldap_nettimeout = 10;
71static bool     ldap_usetls = 0;
72static bool     lutmp = 0;
73
74static struct ldap_data ldap_data;
75
76static option_t ldap_options[] = {
77
78        { "ldaphost", o_string, ldap_host,
79          "LDAP server host name",
80          OPT_PRIV | OPT_STATIC, NULL, (MAX_BUF - 1)},
81
82        { "ldapdn", o_string, ldap_dn,
83          "DN to bind with to LDAP server",
84          OPT_PRIV | OPT_STATIC, NULL, (MAX_BUF - 1)},
85
86        { "ldappw", o_string, ldap_pw,
87          "DN password",
88          OPT_PRIV | OPT_STATIC, NULL, (MAX_BUF - 1)},
89
90        { "ldapport", o_int, &ldap_port,
91          "LDAP server port",
92          OPT_PRIV | OPT_STATIC},
93
94        { "userbasedn", o_string, userbasedn,
95          "LDAP user base DN",
96          OPT_PRIV | OPT_STATIC, NULL, (MAX_BUF - 1)},
97
98        { "ldaptimeout", o_int, &ldap_timeout,
99          "LDAP search timeout",
100          OPT_PRIV | OPT_STATIC},
101
102        { "ldapnettimeout", o_int, &ldap_nettimeout,
103          "LDAP network activity timeout",
104          OPT_PRIV | OPT_STATIC },
105#ifdef OPT_WITH_TLS
106        { "ldapusetls", o_bool, &ldap_usetls,
107          "Connect to LDAP server using TLS", 1},
108#endif
109
110        { "lutmp", o_bool, &lutmp,
111          "Write session data to ppp_utmp", 1},
112
113        { NULL }
114};
115
116int plugin_init()
117{
118        add_options(ldap_options);
119        pap_check_hook = ldap_pap_check;
120        pap_auth_hook = ldap_pap_auth;
121        ip_choose_hook = ldap_ip_choose;
122        allowed_address_hook = ldap_address_allowed;
123
124        add_notifier(&ip_down_notifier, ldap_ip_down, NULL);
125        add_notifier(&ip_up_notifier, ldap_ip_up, NULL);
126
127        info("LDAP: plugin initialized.");
128}
129
130/*
131*       FUNCTION: ldap_pap_auth()
132*       PURPOSE: Authenticates PAP user against LDAP server.
133*
134*       ARGUMENTS:
135*       user - user name
136*       password - user password
137*       msgp - PAP message to send
138*
139*       RETURN:  0 - Supplied username/password values incorrect
140*                        1 - Success
141*                       -1 - Error, proceed to normal pap-options file
142*/
143
144static int ldap_pap_auth(char *user, char *password, char **msgp,
145        struct wordlist **paddrs, struct wordlist **popts)
146{
147        int rc,ldap_errno;
148        int version = LDAP_VERSION3;
149        char filter[LDAP_FILT_MAXSIZ];
150        char userdn[MAX_BUF];
151        char **ldap_values;
152        LDAP *ldap;
153        LDAPMessage *ldap_mesg;
154        LDAPMessage     *ldap_entry;
155
156        /* Initiate session and bind to LDAP server */
157
158
159        if ((ldap = ldap_init(ldap_host, ldap_port)) == NULL) {
160                error("LDAP: failed to initialize session\n");
161                return -1;
162        }
163
164        /* Set LDAP specific options such as timeout, version and tls */
165
166        if ((rc = ldap_set_option(ldap, LDAP_OPT_PROTOCOL_VERSION,
167                &version) != LDAP_OPT_SUCCESS)) {
168                error("LDAP: failed to set protocol version\n");
169                return -1;
170        }
171
172        if ((rc = ldap_set_option(ldap, LDAP_OPT_NETWORK_TIMEOUT,
173                &ldap_nettimeout) != LDAP_OPT_SUCCESS)) {
174                error("LDAP: failed to set network timeout version\n");
175                return -1;
176        }
177
178        if ((rc = ldap_set_option(ldap, LDAP_OPT_TIMELIMIT,
179                &ldap_timeout) != LDAP_OPT_SUCCESS)) {
180                error("LDAP: failed to set timeout option\n");
181                return -1;
182        }
183
184#ifdef OPT_WITH_TLS
185
186        /* Some servers support only LDAPS but not TLS */
187        if ((ldap_port == LDAPS_PORT) && ldap_usetls) {
188                int tls_opt = LDAP_OPT_X_TLS_HARD;
189                if ((rc = ldap_set_option(ldap, LDAP_OPT_X_TLS,
190                        (void *)&tls_opt)) != LDAP_SUCCESS) {
191                ldap_get_option(ldap, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
192                error("LDAP: failed to set TLS option: %s\n", ldap_err2string(rc));
193                return -1;
194                }
195        }
196
197        if (ldap_usetls) {
198        #ifdef DEBUG
199                info("LDAP: Setting TLS option -> ON\n");
200        #endif
201                if((rc = ldap_start_tls_s(ldap, NULL, NULL) != LDAP_SUCCESS)) {
202                ldap_get_option(ldap, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
203                error("LDAP: failed to initiate TLS: %s\n", ldap_err2string(ldap_errno));
204                return -1;
205                }
206        };
207
208#endif
209
210        /* Perform binding at last */
211
212        if ((rc = ldap_bind_s(ldap, ldap_dn, ldap_pw, LDAP_AUTH_SIMPLE)) != LDAP_SUCCESS) {
213                ldap_get_option(ldap, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
214                error("LDAP: failed to bind: %s\n",ldap_err2string(rc));
215                ldap_unbind(ldap);
216                return -1;
217        }
218
219        /* Form a search filter from supplied peer's credentials */
220
221        if ((rc = snprintf(filter, LDAP_FILT_MAXSIZ,"(&(uid=%s)(objectClass=%s))",
222                 user, RADIUS_OBJECTCLASS)) == -1) {
223                error("LDAP: LDAP filter too big\n");
224                ldap_unbind(ldap);
225                return -1;
226        };
227
228#ifdef DEBUG
229                info("LDAP: search filter: %s\n",filter);
230#endif
231
232        /* Perform search*/
233
234        if ((rc = ldap_search_s(ldap, userbasedn, LDAP_SCOPE_SUBTREE, filter,
235                NULL, 0, &ldap_mesg)) != LDAP_SUCCESS) {
236                ldap_get_option(ldap, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
237                error("LDAP: Can't perform search: %s\n",
238                        ldap_err2string(rc));
239                ldap_unbind(ldap);
240                return -1;
241        };
242
243        /* If search returned more than 2 results or 0 - something is wrong! */
244
245        if ( ldap_mesg == NULL ){
246                info("LDAP: No such user \"%s\"\n",user);
247                ldap_unbind(ldap);
248                return -1;
249        }
250
251        if ((ldap_count_entries(ldap, ldap_mesg)) > 1){
252                warn("LDAP: more than one user \"%s\" exists!\n",user);
253                ldap_unbind(ldap);
254                return -1;
255        }
256
257        /* Check existance of dialupAccess attribute and it's value */
258#ifdef DEBUG
259        info("LDAP: found %u entries\n",ldap_count_entries(ldap, ldap_mesg));
260#endif
261
262        /* radiusAuthType = LDAP ->  check it! */
263
264        ldap_entry = ldap_first_entry(ldap, ldap_mesg);
265
266                ldap_values = ldap_get_values(ldap, ldap_entry, RADIUS_AUTHTYPE);
267
268                if (ldap_count_values(ldap_values) != 0) {
269
270                        if ((strncasecmp(ldap_values[0],"LDAP",4) != 0)) {
271#ifdef DEBUG
272                        info("LDAP: Sorry, only authtype=LDAP is supported\n");
273#endif
274                        ldap_unbind(ldap);
275                        ldap_msgfree(ldap_mesg);
276                        return -1;
277                        }
278                } else {
279#ifdef DEBUG
280                                        info("LDAP: Can not get authentication type\n");
281#endif
282                                        ldap_unbind(ldap);
283                                        ldap_msgfree(ldap_mesg);
284                                        return -1;
285                }
286
287                ldap_values = ldap_get_values(ldap, ldap_entry, RADIUS_DIALUPACCESS);
288                if (((strncasecmp(ldap_values[0],"YES",3) == 0)) ||
289                        ((strncasecmp(ldap_values[0],"FALSE",5)) != 0)) {
290
291                /* Rebind with peers supplied credentials */
292
293                if ((rc = snprintf(userdn,MAX_BUF,"%s",ldap_get_dn(ldap,ldap_entry))) == -1)
294                warn("LDAP: user DN stripped\n");
295
296#ifdef DEBUG
297        info("LDAP: rebind DN: %s\n",userdn);
298#endif
299
300                if ((rc = ldap_simple_bind_s(ldap,userdn,password)) != LDAP_SUCCESS) {
301                        error("LDAP: username or password incorrect\n");
302                        *msgp = "Username or password incorrect!";
303                        ldap_unbind(ldap);
304                        ldap_msgfree(ldap_mesg);
305                        return 0;
306                        }
307                } else {
308
309                        error("LDAP: dialup access disabled for user %s\n",user);
310                        *msgp = "Dial-in access not allowed!";
311                        ldap_unbind(ldap);
312                        ldap_msgfree(ldap_mesg);
313                        return 0;
314                }
315
316                /* Set pppd options */
317
318                ldap_setoptions(ldap, ldap_mesg, &ldap_data);
319
320#ifdef DEBUG
321                info("LDAP: Auth success\n");
322#endif
323                *msgp = "Access OK!";
324                ldap_data.access_ok = 1;
325
326                /* Write ppp_utmp data in place */
327
328                return 1;
329}
330
331static void ldap_ip_choose(u_int32_t *addrp)
332{
333        if (ldap_data.address_set)
334                *addrp = ldap_data.addr;
335}
336
337static void ldap_ip_down(void *opaque, int arg)
338{
339        if(lutmp)
340        ldap_deactivate_utmp(devnam);
341}
342
343static void ldap_ip_up(void *opaque, int arg)
344{
345        if(lutmp)
346        ldap_activate_utmp(&ldap_data, devnam, ifname, peer_authname);
347}
348
349static int ldap_address_allowed(u_int32_t addr)
350{
351        /* if (ldap_data.address_set) return 1;*/
352        if (ntohl(addr) == ldap_data.addr) return 1;
353
354        /* if peer's address was specified in options
355           allow it */
356        if ((ipcp_wantoptions[0].hisaddr != 0) &&
357             (ipcp_wantoptions[0].hisaddr == addr)) return 1;
358
359        return 0;
360}
361
362static int ldap_pap_check(void)
363{
364        return 1;
365}
366
367
368/*
369*       FUNCTION: ldap_activate_utmp(struct ldap_data *ldap_data,
370                                char *devnam, char *ppp_devname, char *user);
371*       PURPOSE: Writes ppp session data to ppp_utmp file
372*       ARGUMENTS:
373*       ldap_data - pointer to ldap_data structure
374*       devnam -        tty device name ("/dev/" will be stripped)
375*       ppp_devname - interface name (ppp1, ppp0, etc) associated with
376*                               ppp session
377*       user -          user login name
378*
379*       RETURNS: -1 in case of error
380                          1 if success
381*/
382
383static int ldap_activate_utmp(struct ldap_data *ldap_data,
384                char *devnam, char *ppp_devname, char* user)
385{
386        int rc;
387        int fd;
388        off_t offset;
389        struct ppp_utmp entry;
390        char *device;
391        char *p;
392
393        memset(&entry, 0, sizeof(struct ppp_utmp));
394
395        if ((device = malloc(MAXPATHLEN)) == NULL) {
396                error("Not enough memory\n");
397                return -1;
398        }
399
400        memset(device, '\0', MAXPATHLEN);
401
402        if ((fd = open(UTMP , O_RDWR | O_CREAT, 0644)) == -1)
403        {
404                error("LDAP: can't open utmp file\n");
405                return -1;
406        }
407
408        strncpy(device, devnam, MAXLINELEN-1);
409
410        p = device;
411        if(strncmp(device,"/dev/",5) == 0) p +=  5;
412
413        if ((rc = lockf(fd, F_LOCK, 0)) == -1)
414        {
415                error("LDAP: can't lock utmp file: %s\n",
416                strerror(errno));
417                return -1;
418        }
419
420        switch ((offset = utmp_seek(fd, devnam))) {
421
422        case -1:
423
424                strncpy(entry.line, p, MAXLINELEN-1);
425                strncpy(entry.login, user, MAXNAMELEN-1);
426                strncpy(entry.ifname, ppp_devname, MAXIFLEN-1);
427
428                if (!ldap_data->address_set)
429                entry.ip_address = ipcp_wantoptions[0].hisaddr;
430                else entry.ip_address = ldap_data->addr;
431
432                entry.time = time(NULL);
433                entry.state = ACTIVE;
434
435                lseek(fd, 0, SEEK_END);
436                if ((write_n(fd, &entry, sizeof(struct ppp_utmp))) == -1){
437                        error("LDAP: failed to write utmp entry\n");
438                        return -1;
439                }
440
441                break;
442
443        default:
444
445                lseek(fd, offset, SEEK_SET);
446                read_n(fd,&entry,sizeof(struct ppp_utmp));
447
448                strncpy(entry.line, p, MAXLINELEN-1);
449                strncpy(entry.login, user, MAXNAMELEN-1);
450                strncpy(entry.ifname, ppp_devname, MAXIFLEN-1);
451
452                if (!ldap_data->address_set)
453                entry.ip_address = ipcp_wantoptions[0].hisaddr;
454                else entry.ip_address = ldap_data->addr;
455
456                entry.time = time(NULL);
457                entry.state = ACTIVE;
458
459                lseek(fd, offset, SEEK_SET);
460                if ((write_n(fd, &entry, sizeof(struct ppp_utmp))) == -1){
461                        error("LDAP: failed to write utmp entry\n");
462                        return -1;
463                }
464
465                break;
466        }
467
468        free(device);
469
470        lseek(fd, 0, SEEK_SET);
471        if ((rc = lockf(fd, F_ULOCK, 0)) == -1)
472        {
473                error("LDAP: can't unlock utmp file: %s\n",
474                strerror(errno));
475                return -1;
476        }
477
478        if ((rc = close(fd)) == -1)
479        {
480                error("LDAP: can't close utmp file: %s\n",
481                strerror(errno));
482                return -1;
483        }
484
485return 1;
486
487}
488
489/*
490*       FUNCTION: ldap_deactivate_utmp(char *devnam);
491*       PURPOSE: sets ppp session data to IDLE in ppp_utmp associated with tty
492*       ARGUMENTS:
493*       devnam -        tty device name ("/dev/" will be stripped)
494*
495*       RETURNS: -1 in case of error
496                          1 if success
497*/
498
499
500static int ldap_deactivate_utmp(char *devnam)
501{
502
503        int rc;
504        int fd;
505        off_t offset;
506        struct ppp_utmp entry;
507        char *device;
508        char *p;
509
510        if ((device = malloc(MAXPATHLEN)) == NULL) {
511                error("Not enough memory\n");
512                return -1;
513        }
514
515        memset(device, 0, MAXPATHLEN);
516        memset(&entry, 0, sizeof(struct ppp_utmp));
517
518        p = device;
519
520        strncpy(device, devnam, MAXLINELEN-1);
521        if(strncmp(device,"/dev/",5) == 0) p += 5;
522
523#ifdef DEBUG
524        info("LDAP: deactivating %s\n",devnam);
525#endif
526
527        if ((fd = open(UTMP, O_RDWR, 0600)) == -1){
528                error("LDAP: can't open utmp file: %s\n",
529                strerror(errno));
530                return -1;
531        }
532
533        if ((rc = lockf(fd, F_LOCK, 0)) == -1){
534                error("LDAP: can't lock utmp file: %s\n",
535                strerror(errno));
536                return -1;
537        }
538
539        while(read_n(fd, &entry, sizeof(struct ppp_utmp))) {
540                if (strncmp(entry.line, p, MAXLINELEN-1) == 0) {
541                        entry.state = IDLE;
542                        lseek(fd, -sizeof(struct ppp_utmp), SEEK_CUR);
543                        if ((rc = write_n(fd, &entry, sizeof(struct ppp_utmp))) == -1) {
544                                error("LDAP: can't change utmp record status: %s\n",
545                                                strerror(errno));
546                                return -1;
547                        }
548                }
549        }
550
551        free(device);
552
553        lseek(fd, 0, SEEK_SET);
554        if ((rc = lockf(fd, F_ULOCK, 0)) == -1){
555                error("LDAP: can't unlock utmp file: %s\n",
556                strerror(errno));
557                return -1;
558        }
559
560        close(fd);
561        return 1;
562}
563
564/*
565*       FUNCTION: ldapset_options()
566*       PURPOSE: sets different pppd options retrieved from user's LDAP entry
567*       Currently ldap_set_options() processes radiusFramedIPAddress, radiusSessionTimeout,
568*       radiusIdleTimeout. Additional options should be easy.
569*
570*       ARGUMENTS:
571*       ld - pointer to current LDAP structure
572*       ldap_entry - points to current LDAP entry we want to process
573*       ldap_data - points to ldap_data structure which holds necessary values
574*
575*       RETURNS: Nothing
576*
577*/
578
579static int ldap_setoptions(LDAP *ld, LDAPMessage *ldap_entry, struct ldap_data *ldap_data)
580{
581        int rc;
582        char **ldap_values;
583
584        if (((ldap_values = ldap_get_values(ld, ldap_entry,
585                 RADIUS_FRAMEDIPADDRESS)) != NULL) &&
586                  ((ldap_count_values(ldap_values)) != 0)) {
587                  if ((rc = inet_pton(AF_INET, ldap_values[0],&ldap_data->addr)) > 0){
588                        ldap_data->address_set = 1;
589#ifdef DEBUG
590                        info("LDAP: peer address is %p\n",ldap_data->addr);
591#endif
592                  } else
593                  {
594                        switch(rc) {
595                                case 0:
596                                error("LDAP: LDAP server supplied incorrect IP address\n");
597                                break;
598
599                                default:
600                                error("LDAP: Can not convert supplied IP address: %s\n",
601                                          strerror(rc));
602                                break;
603                  }
604           }
605        }
606
607        if (((ldap_values = ldap_get_values(ld, ldap_entry,
608                 RADIUS_IDLETIMEOUT)) != NULL ) &&
609                  ((ldap_count_values(ldap_values)) != 0)) {
610                 ldap_data->idle_time_limit = atoi(ldap_values[0]);
611#ifdef DEBUG
612                info("LDAP: peer idle timeout is %u seconds\n",
613                                ldap_data->idle_time_limit);
614#endif
615                 idle_time_limit = ldap_data->idle_time_limit;
616        }
617
618        if (((ldap_values = ldap_get_values(ld, ldap_entry,
619                 RADIUS_SESSIONTIMEOUT)) != NULL ) &&
620                 ((ldap_count_values(ldap_values)) != 0)) {
621                 ldap_data->maxconnect = atoi(ldap_values[0]);
622#ifdef DEBUG
623                info("LDAP: peer session timeout is %u seconds\n",
624                                ldap_data->maxconnect);
625#endif
626                maxconnect = ldap_data->maxconnect;
627        }
628
629}
Note: See TracBrowser for help on using the repository browser.