/*
 * user_options.c - pppd plugin to implement options depending on username
 *
 * Copyright 2005 Folke Ashberg <folke@ashberg.de>
 *
 *  This program is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU General Public License
 *  as published by the Free Software Foundation; either version
 *  2 of the License, or (at your option) any later version.
 *
 * If you want to set options depending on a per user basis you probably
 * need this pppd-plugin.
 *
 * Installation:
 * Copy the user_options.c into ppp-2.4.X/pppd/plugins source-tree and
 * add the following line into the Makefile (same directory) after
 * the 'PLUGINS=' line:
 * 
 *      PLUGINS += user_options.so
 *     
 * Then run make install in the ppp-2.4.X directory
 * (or just in the plugins dir if you know what you're doing).
 * 
 * Usage:
 * 1) Enable this plugin in your ppp config (e.g. /etc/ppp/options,
 *      /etc/ppp/pptpd-options or however):
 *      
 *     plugin user_options.so
 *    
 * 2) define the per-user config directory:
 *
 *     user_options_dir /etc/ppp/user-options
 *
 *  (/etc/ppp/user-options is default)
 * 3) create the per user configfiles as needed:
 * 
 *    vi /etc/ppp/user-options/jon-doe
 *    
 * config style is like any other ppp config file (see pppd(8))
 * 
 * Notes:
 * All characters _not_ matching [a-zA-Z0-9_@#![]+=% -] will be
 *    converted to '_' (underscore).
 * Not any ppp option can be set/overwritten, you can't change
 *    e.g. authentication options since the remote peer is 
 *    already authenticated at this point!
 * When you want to overwrite ms-dns or ms-wins you have to set
 *    it twice (even if you only  have one wins-server/dns-server. 
 * 
 */


#include <stddef.h>
#include <time.h>
#include "pppd.h"
#include <syslog.h>
#include <string.h>
#include <errno.h>

char pppd_version[] = VERSION;

static char * user_options_dir = "/etc/ppp/user-options";

static option_t my_options[] = {
      { "user_options_dir", o_string, &user_options_dir,  "Per user config options directory" },
      { NULL }
};

void my_auth_up(void *opaque, int arg)
{
    char filename[MAXPATHLEN] = "\0";
    FILE *f;
    int a, good, len = 0, err;
    char  * c;
    if (!peer_authname){
	syslog(LOG_NOTICE, "pppd user_options called, but peer_authname is NULL! -> aborting");
	return;
    }
    if (!user_options_dir || !strlen(user_options_dir)){
	syslog(LOG_NOTICE, "pppd user_options called, but user_options_dir is NULL/empty! -> aborting");
	return;
    }
    syslog(LOG_NOTICE, "pppd user_options called, directory is '%s', user is '%s'", user_options_dir, peer_authname);
    strncpy(filename, user_options_dir, MAXPATHLEN);
    len+=strlen(user_options_dir);
    if (filename[len-1]!='/'){
	strncat(filename, "/", MAXPATHLEN - len);
	len++;
    }
    if (strlen(peer_authname)>MAXPATHLEN-len-1){
	syslog(LOG_NOTICE, "pppd user_options: peer_authname is tooooooo long! -> aborting");
	return;	
    };
    strncat(filename, peer_authname, MAXPATHLEN - len);
    c=filename+len;
    a=0; good=0;
    while (1){
	a=strspn(c, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890-_@#![]+=% ");
	good+=a;
	if (good>=strlen(peer_authname)) break;
	c+=a;
	c[0]='_';
    }
    f = fopen(filename, "r");
    err = errno;
    if (err == ENOENT || err == ENOTDIR){
	syslog(LOG_WARNING,"pppd user_options: %s doesn't exists!", filename);
	return;
    } else if (err){
	syslog(LOG_ERR,"pppd user_options: Can't open %s!", filename);
	return;
    }
    fclose(f);
    syslog(LOG_NOTICE, "pppd user_options: Opening file '%s'", filename);
    options_from_file(filename, 0, 0, 0);
}


void plugin_init(void)
{
    info("plugin_init");
    add_options(my_options);
    add_notifier(&auth_up_notifier, my_auth_up, 0);
}

