4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 * Copyright 2000 The FreeRADIUS server project
24 /*#include "autoconf.h"
25 #include "libradius.h"*/
31 struct mypasswd *next;
43 struct mypasswd **table;
44 struct mypasswd *last_found;
53 #define rad_malloc(s) malloc(s)
55 void printpw(struct mypasswd *pw, int nfields){
58 for( i = 0; i < nfields; i++ ) printf("%s:", pw->field[i]);
61 else printf ("Not found\n");
67 static struct mypasswd * mypasswd_malloc(const char* buffer, int nfields, int* len)
70 /* reserve memory for (struct mypasswd) + listflag (nfields * sizeof (char*)) +
71 ** fields (nfields * sizeof (char)) + strlen (inst->format) + 1 */
73 *len=sizeof (struct mypasswd) + nfields * sizeof (char*) + nfields * sizeof (char ) + strlen(buffer) + 1;
74 t = (struct mypasswd *) rad_malloc(*len);
75 if (t) memset(t, 0, *len);
79 static int string_to_entry(const char* string, int nfields, char delimiter,
80 struct mypasswd *passwd, int bufferlen)
89 if (string[len-1] == '\n') len--;
91 if (string[len-1] == '\r') len--;
93 if (!len || !passwd || bufferlen < (len + nfields * sizeof (char*) + nfields * sizeof (char) + sizeof (struct mypasswd) + 1) ) return 0;
95 data_beg=(char *)passwd + sizeof(struct mypasswd);
96 str = data_beg + nfields * sizeof (char) + nfields * sizeof (char*);
97 memcpy (str, string, len);
99 passwd->field[fn++] = str;
100 passwd->listflag = data_beg + nfields * sizeof (char *);
101 for(i=0; i < len; i++){
102 if (str[i] == delimiter) {
104 passwd->field[fn++] = str + i + 1;
105 if (fn == nfields) break;
108 for (; fn < nfields; fn++) passwd->field[fn] = NULL;
109 return len + nfields * sizeof (char) + nfields * sizeof (char*) + sizeof (struct mypasswd) + 1;
113 static void destroy_password (struct mypasswd * pass)
116 while ((p=pass)!=NULL) {
123 static unsigned int hash(const unsigned char * username, unsigned int tablesize)
127 h = h * 7907 + *username++;
132 static void release_hash_table(struct hashtable * ht){
136 for (i=0; i<ht->tablesize; i++)
138 destroy_password(ht->table[i]);
139 if (ht->table) free(ht->table);
140 if (ht->fp) fclose(ht->fp);
143 static void release_ht(struct hashtable * ht){
145 release_hash_table(ht);
146 if (ht->filename) free(ht->filename);
150 static struct hashtable * build_hash_table (const char * file, int nfields,
151 int keyfield, int islist, int tablesize, int ignorenis, char * delimiter)
153 #define passwd ((struct mypasswd *) ht->buffer)
155 struct hashtable* ht;
158 struct mypasswd *hashentry, *hashentry1;
163 ht = (struct hashtable *) rad_malloc(sizeof(struct hashtable));
167 memset(ht, 0, sizeof(struct hashtable));
168 ht->filename = strdup(file);
173 ht->tablesize = tablesize;
174 ht->nfields = nfields;
175 ht->keyfield = keyfield;
177 ht->ignorenis = ignorenis;
178 if (delimiter && *delimiter) ht->delimiter = delimiter;
179 else ht->delimiter = ":";
180 if(!tablesize) return ht;
181 if(!(ht->fp = fopen(file,"r"))) return NULL;
182 memset(ht->buffer, 0, 1024);
183 ht->table = (struct mypasswd **) rad_malloc (tablesize * sizeof(struct mypasswd *));
186 * Unable allocate memory for hash table
187 * Still work without it
192 memset(ht->table, 0, tablesize * sizeof(struct mypasswd *));
193 while (fgets(buffer, 1024, ht->fp)) {
194 if(*buffer && *buffer!='\n' && (!ignorenis || (*buffer != '+' && *buffer != '-')) ){
195 if(!(hashentry = mypasswd_malloc(buffer, nfields, &len))){
196 release_hash_table(ht);
200 len = string_to_entry(buffer, nfields, *ht->delimiter, hashentry, len);
201 if(!hashentry->field[keyfield] || *hashentry->field[keyfield] == '\0') {
207 list = hashentry->field[keyfield];
208 for (nextlist = list; *nextlist && *nextlist!=','; nextlist++);
209 if (*nextlist) *nextlist++ = 0;
212 h = hash(hashentry->field[keyfield], tablesize);
213 hashentry->next = ht->table[h];
214 ht->table[h] = hashentry;
216 for(list=nextlist; nextlist; list = nextlist){
217 for (nextlist = list; *nextlist && *nextlist!=','; nextlist++);
218 if (*nextlist) *nextlist++ = 0;
220 if(!(hashentry1 = mypasswd_malloc("", nfields, &len))){
221 release_hash_table(ht);
225 for (i=0; i<nfields; i++) hashentry1->field[i] = hashentry->field[i];
226 hashentry1->field[keyfield] = list;
227 h = hash(list, tablesize);
228 hashentry1->next = ht->table[h];
229 ht->table[h] = hashentry1;
240 static struct mypasswd * get_next(char *name, struct hashtable *ht)
242 #define passwd ((struct mypasswd *) ht->buffer)
243 struct mypasswd * hashentry;
246 char *list, *nextlist;
248 if (ht->tablesize > 0) {
249 /* get saved address of next item to check from buffer */
250 hashentry = ht->last_found;
251 for (; hashentry; hashentry = hashentry->next) {
252 if (!strcmp(hashentry->field[ht->keyfield], name)) {
253 /* save new address */
254 ht->last_found = hashentry->next;
260 printf("try to find in file\n");
261 if (!ht->fp) return NULL;
262 while (fgets(buffer, 1024,ht->fp)) {
263 if(*buffer && *buffer!='\n' && (len = string_to_entry(buffer, ht->nfields, *ht->delimiter, passwd, sizeof(ht->buffer)-1)) &&
264 (!ht->ignorenis || (*buffer !='-' && *buffer != '+') ) ){
266 if(!strcmp(passwd->field[ht->keyfield], name))
270 for (list = passwd->field[ht->keyfield], nextlist = list; nextlist; list = nextlist) {
271 for(nextlist = list; *nextlist && *nextlist!=','; nextlist++);
272 if(!*nextlist)nextlist = 0;
273 else *nextlist++ = 0;
274 if(!strcmp(list, name)) return passwd;
286 static struct mypasswd * get_pw_nam(char * name, struct hashtable* ht)
289 struct mypasswd * hashentry;
291 if (!ht || !name || *name == '\0') return NULL;
292 ht->last_found = NULL;
293 if (ht->tablesize > 0) {
294 h = hash (name, ht->tablesize);
295 for (hashentry = ht->table[h]; hashentry; hashentry = hashentry->next)
296 if (!strcmp(hashentry->field[ht->keyfield], name)){
297 /* save address of next item to check into buffer */
298 ht->last_found=hashentry->next;
303 if (ht->fp) fclose(ht->fp);
304 if (!(ht->fp=fopen(ht->filename, "r"))) return NULL;
305 return get_next(name, ht);
310 #define MALLOC_CHECK_ 1
313 struct hashtable *ht;
318 ht = build_hash_table("/etc/group", 4, 3, 1, 100, 0, ":");
320 printf("Hash table not built\n");
323 for (i=0; i<ht->tablesize; i++) if (ht->table[i]) {
325 for(pw=ht->table[i]; pw; pw=pw->next) printpw(pw, 4);
328 while(fgets(buffer, 1024, stdin)){
329 buffer[strlen(buffer)-1] = 0;
330 pw = get_pw_nam(buffer, ht);
332 while (pw = get_next(buffer, ht)) printpw(pw,4);
338 struct passwd_instance {
339 struct hashtable *ht;
340 struct mypasswd *pwdfmt;
356 static CONF_PARSER module_config[] = {
357 { "filename", PW_TYPE_STRING_PTR,
358 offsetof(struct passwd_instance, filename), NULL, NULL },
359 { "format", PW_TYPE_STRING_PTR,
360 offsetof(struct passwd_instance, format), NULL, NULL },
361 { "authtype", PW_TYPE_STRING_PTR,
362 offsetof(struct passwd_instance, authtype), NULL, NULL },
363 { "delimiter", PW_TYPE_STRING_PTR,
364 offsetof(struct passwd_instance, delimiter), NULL, ":" },
365 { "ignorenislike", PW_TYPE_BOOLEAN,
366 offsetof(struct passwd_instance, ignorenislike), NULL, "yes" },
367 { "ignoreempty", PW_TYPE_BOOLEAN,
368 offsetof(struct passwd_instance, ignoreempty), NULL, "yes" },
369 { "allowmultiplekeys", PW_TYPE_BOOLEAN,
370 offsetof(struct passwd_instance, allowmultiple), NULL, "no" },
371 { "hashsize", PW_TYPE_INTEGER,
372 offsetof(struct passwd_instance, hashsize), NULL, "100" },
373 { NULL, -1, 0, NULL, NULL }
376 static int passwd_instantiate(CONF_SECTION *conf, void **instance)
378 #define inst ((struct passwd_instance *)*instance)
379 int nfields=0, keyfield=-1, listable=0;
381 char *lf=NULL; /* destination list flags temporary */
386 *instance = rad_malloc(sizeof(struct passwd_instance));
388 radlog(L_ERR, "rlm_passwd: cann't alloc instance");
391 memset(*instance, 0, sizeof(struct passwd_instance));
392 if (cf_section_parse(conf, inst, module_config) < 0) {
394 radlog(L_ERR, "rlm_passwd: cann't parse configuration");
397 if(!inst->filename || *inst->filename == '\0' || !inst->format || *inst->format == '\0') {
398 radlog(L_ERR, "rlm_passwd: cann't find passwd file and/or format in configuration");
401 lf=strdup(inst->format);
403 radlog(L_ERR, "rlm_passwd: memory allocation failed for lf");
406 memset(lf, 0, strlen(inst->format));
407 s = inst->format - 1;
409 if(s == inst->format - 1 || *s == ':'){
431 radlog(L_ERR, "rlm_passwd: no field market as key in format: %s", inst->format);
434 if (! (inst->ht = build_hash_table (inst->filename, nfields, keyfield, listable, inst->hashsize, inst->ignorenislike, inst->delimiter)) ){
435 radlog(L_ERR, "rlm_passwd: can't build hashtable from passwd file");
438 if (! (inst->pwdfmt = mypasswd_malloc(inst->format, nfields, &len)) ){
439 radlog(L_ERR, "rlm_passwd: memory allocation failed");
440 release_ht(inst->ht);
443 if (!string_to_entry(inst->format, nfields, ':', inst->pwdfmt , len)) {
444 radlog(L_ERR, "rlm_passwd: unable to convert format entry");
445 release_ht(inst->ht);
449 memcpy(inst->pwdfmt->listflag, lf, nfields);
452 for (i=0; i<nfields; i++) {
453 if (*inst->pwdfmt->field[i] == '*') inst->pwdfmt->field[i]++;
454 if (*inst->pwdfmt->field[i] == ',') inst->pwdfmt->field[i]++;
455 if (*inst->pwdfmt->field[i] == '=') inst->pwdfmt->field[i]++;
456 if (*inst->pwdfmt->field[i] == '~') inst->pwdfmt->field[i]++;
458 if (!*inst->pwdfmt->field[keyfield]) {
459 radlog(L_ERR, "rlm_passwd: key field is empty");
460 release_ht(inst->ht);
463 if (! (da = dict_attrbyname (inst->pwdfmt->field[keyfield])) ) {
464 radlog(L_ERR, "rlm_passwd: unable to resolve attribute: %s", inst->pwdfmt->field[keyfield]);
465 release_ht(inst->ht);
468 inst->keyattr = da->attr;
469 inst->keyattrtype = da->type;
470 inst->nfields = nfields;
471 inst->keyfield = keyfield;
472 inst->listable = listable;
473 radlog(L_INFO, "rlm_passwd: nfields: %d keyfield %d(%s) listable: %s", nfields, keyfield, inst->pwdfmt->field[keyfield], listable?"yes":"no");
479 static int passwd_detach (void *instance) {
480 #define inst ((struct passwd_instance *)instance)
481 if(inst->ht) release_ht(inst->ht);
482 if (inst->filename != NULL) free(inst->filename);
483 if (inst->format != NULL) free(inst->format);
484 if (inst->authtype != NULL ) free(inst->authtype);
485 if (inst->delimiter != NULL) free(inst->delimiter);
491 static void addresult (struct passwd_instance * inst, VALUE_PAIR ** vp, struct mypasswd * pw, char when, const char *listname)
496 for (i=0; i<inst->nfields; i++) {
497 if (inst->pwdfmt->field[i] && *inst->pwdfmt->field[i] && pw->field[i] && i != inst->keyfield && inst->pwdfmt->listflag[i] == when) {
498 if ( !inst->ignoreempty || pw->field[i][0] != 0 ) { /* if value in key/value pair is not empty */
499 if (! (newpair = pairmake (inst->pwdfmt->field[i], pw->field[i], T_OP_EQ))) {
500 radlog(L_AUTH, "rlm_passwd: Unable to create %s: %s", inst->pwdfmt->field[i], pw->field[i]);
503 radlog(L_DBG, "rlm_passwd: Added %s: '%s' to %s ", inst->pwdfmt->field[i], pw->field[i], listname);
504 pairadd (vp, newpair);
506 radlog(L_DBG, "rlm_passwd: NOOP %s: '%s' to %s ", inst->pwdfmt->field[i], pw->field[i], listname);
511 static int passwd_authorize(void *instance, REQUEST *request)
513 #define inst ((struct passwd_instance *)instance)
517 struct mypasswd * pw;
520 if(!request || !request->packet ||!request->packet->vps)
521 return RLM_MODULE_INVALID;
522 for (key = request->packet->vps;
523 key && (key = pairfind (key, inst->keyattr));
525 switch (inst->keyattrtype) {
526 case PW_TYPE_INTEGER:
527 snprintf(buffer, 1024, "%u", key->lvalue);
531 name = key->strvalue;
533 if (! (pw = get_pw_nam(name, inst->ht)) ) {
537 addresult(inst, &request->config_items, pw, 0, "config_items");
538 addresult(inst, &request->reply->vps, pw, 1, "reply_items");
539 addresult(inst, &request->packet->vps, pw, 2, "request_items");
540 } while ( (pw = get_next(name, inst->ht)) );
542 if (!inst->allowmultiple) break;
545 return RLM_MODULE_NOTFOUND;
547 if (inst->authtype &&
548 (key = pairmake ("Auth-Type", inst->authtype, T_OP_EQ))) {
549 radlog(L_INFO, "rlm_passwd: Adding \"Auth-Type = %s\"",
552 * Don't call pairadd. pairmove doesn't
553 * over-write existing attributes.
555 pairmove(&request->config_items, &key);
556 pairfree(&key); /* pairmove may have NOT moved it */
558 return RLM_MODULE_OK;
563 module_t rlm_passwd = {
565 RLM_TYPE_THREAD_SAFE, /* type */
566 NULL, /* initialize */
567 passwd_instantiate, /* instantiation */
569 NULL, /* authentication */
570 passwd_authorize, /* authorization */
571 NULL, /* pre-accounting */
572 NULL, /* accounting */
573 NULL, /* checksimul */
574 NULL, /* pre-proxy */
575 NULL, /* post-proxy */
578 passwd_detach, /* detach */