rlm_detail and radrelay concurrence

Michael Chernyakhovsky magmike at mail.ru
Thu Jun 15 08:40:13 CEST 2006


hello, everyone

i use radrelay
there are errors in log from rlm_detail like

Error: rlm_detail: Couldn't open file /var/log/radius/radacct/detail-relay: Bad file descriptor

while examine rlm_detail.c i found two places in it.
first while open (create if need) detail-file (line 204 rlm_detail.c).
second while do converting the FD to FP (line 243) after aquiring
filelock of detail file.

Bad file description error appear because radrelay
can remove detail file while rad_detail trying to aquire filelock, I
think (line 655 of radrelay.c).

rlm_detail.c:
201:    if ((outfd = open(buffer, O_WRONLY | O_APPEND | O_CREAT,
202:              inst->detailperm)) < 0) {
203:        radlog(L_ERR, "rlm_detail: Couldn't open file %s: %s",
204:               buffer, strerror(errno));
205:        return RLM_MODULE_FAIL;
206:    }
208:    /*
209:     *  If we're not using locking, we'll just pass straight though
210:     *  the while loop.
211:     *  If we fail to aquire the filelock in 80 tries (approximately
212:     *  two seconds) we bail out.
213:     */
214:    locked = 0;
215:    lock_count = 0;
216:    do {
          ....
231:    } while (!locked && inst->locking && lock_count < 80);
        ...
239:    /*
240:     *  Convert the FD to FP.  The FD is no longer valid
241:     *  after this operation.
242:     */
243:    if ((outfp = fdopen(outfd, "a")) == NULL) {
244:        radlog(L_ERR, "rlm_detail: Couldn't open file %s: %s",
245:               buffer, strerror(errno));
246:        if (inst->locking) {
247:            lseek(outfd, 0L, SEEK_SET);
248:            rad_unlockfd(outfd, 0);
249:            DEBUG("rlm_detail: Released filelock");
250:        }
251:        close(outfd);
253:        return RLM_MODULE_FAIL;
254:    }



radrelay.c:

655:                if (detail_move(r_args->detail, work) == 0) {
656:                    if (debug_flag > 0)
657:                        fprintf(stderr, "Moving %s to %s\n",
658:                            r_args->detail, work);
659:                    /*
660:                     *  rlm_detail might still write
661:                     *  something to <detail>.work if
662:                     *  it opens <detail> before it is
663:                     *  renamed (race condition)
664:                     */
665:                    ms_sleep(1000);
666:                    state = STATE_BACKLOG;
667:                }
668:                fpos = ftell(fp);
669:                fseek(fp, 0L, SEEK_SET);
670:                rad_unlockfd(fileno(fp), 0);
671:                fseek(fp, fpos, SEEK_SET);


so detail_move can be called by radrelay while rad_detail already
opens detail (line 201) have outfd and try to aquire lock. after radrelay made
rad_unlockfd(fileno(fp), 0) (line 670), rlm_detail try to fdopen (line
243) and will get error.


As workaround we can give to rlm_detail recreate detail...

--- rlm_detail.c-orig   2006-06-15 12:09:43.000000000 +0600
+++ rlm_detail.c        2006-06-15 12:22:49.000000000 +0600
@@ -119,6 +119,7 @@
        struct stat     st;
        int             locked;
        int             lock_count;
+       int             opencount=0;
        struct timeval  tv;
        REALM           *proxy_realm;
        char            proxy_buffer[16];
@@ -195,6 +196,8 @@
                *p = '/';
        } /* else there was no directory delimiter. */

+
+reopen:
        /*
         *      Open & create the file, with the given permissions.
         */
@@ -241,8 +244,9 @@
         *      after this operation.
         */
        if ((outfp = fdopen(outfd, "a")) == NULL) {
-               radlog(L_ERR, "rlm_detail: Couldn't open file %s: %s",
-                      buffer, strerror(errno));
+               radlog(L_ERR, "rlm_detail: Couldn't open file %s: %s. %s",
+                      buffer, strerror(errno),
+                      (opencount==0)?"try reopen to create":"return MODULE_FAIL");
                if (inst->locking) {
                        lseek(outfd, 0L, SEEK_SET);
                        rad_unlockfd(outfd, 0);
@@ -250,7 +254,10 @@
                }
                close(outfd);

-               return RLM_MODULE_FAIL;
+               if (opencount++ == 0)
+                       goto reopen;
+               else
+                       return RLM_MODULE_FAIL;
        }

        /*
        

        
btw, why to sleep 1000ms on 665 at radrelay.c?
how rlm_detail can write something to detail.work, while file is locked
by radreplay?


Mike.









More information about the Freeradius-Users mailing list