"referenced entity .* not found" message fixed to be fatal
[tac_plus.git] / do_author.c
1 /*
2    Copyright (c) 1995-1998 by Cisco systems, Inc.
3
4    Permission to use, copy, modify, and distribute this software for
5    any purpose and without fee is hereby granted, provided that this
6    copyright and permission notice appear on all copies of the
7    software and supporting documentation, the name of Cisco Systems,
8    Inc. not be used in advertising or publicity pertaining to
9    distribution of the program without specific prior permission, and
10    notice be given in supporting documentation that modification,
11    copying and distribution is by permission of Cisco Systems, Inc.
12
13    Cisco Systems, Inc. makes no representations about the suitability
14    of this software for any purpose.  THIS SOFTWARE IS PROVIDED ``AS
15    IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
16    WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
17    FITNESS FOR A PARTICULAR PURPOSE.
18 */
19
20
21 #include "tac_plus.h"
22
23 #include <stdlib.h>
24 #include <string.h>
25
26 #include "do_author.h"
27 #include "tac_regexp.h"
28 #include "cfgfile.h"
29 #include "report.h"
30 #include "utils.h"
31 #include "programs.h"
32 #include "main.h"
33 #include "parse.h"
34 #include "cfgeval.h"
35
36 #ifdef MAXSESS
37 #include "maxsess.h"
38 #endif
39 #ifdef USE_PAM
40 #include "tac_pam.h"
41 #endif
42
43
44 static int pre_authorization TAC_ARGS((const char *username, struct author_data *data));
45 static int get_nas_svc TAC_ARGS((struct author_data *data, char **cmdname, char **protocol, char **svcname));
46 static int authorize_cmd TAC_ARGS((const char *user, const char *cmd, struct author_data *data));
47 static int authorize_exec TAC_ARGS((const char *user, struct author_data *data));
48 static int authorize_svc TAC_ARGS((const char *user, int svc, const char *protocol, const char *svcname, struct author_data *data));
49 static void post_authorization TAC_ARGS((const char *username, struct author_data *data));
50
51
52 int do_author TAC_ARGS((struct author_data *data));
53
54 /* Return 0 is data->status is valid */
55 int
56 do_author(data)
57 struct author_data *data;
58 {
59     char *username = data->id->username;
60     int status;
61     int svc;
62     char *cmd, *protocol, *svcname;
63 #ifdef USE_PAM
64     const char *pam_service= NULL;
65 #endif
66     protocol = NULL;
67
68     data->status = AUTHOR_STATUS_FAIL;  /* for safety */
69
70     data->output_args = NULL;
71     data->num_out_args = 0;
72
73     /* If this user doesn't exist in our configs, do the default */
74
75     if (!cfg_user_exists(username)) {
76         if (!cfg_user_exists(DEFAULT_USERNAME)) {
77
78             if (cfg_no_user_permitted()) {
79                 if (debug & DEBUG_AUTHOR_FLAG)
80                     report(LOG_DEBUG,
81                            "user '%s' or '%s' not found, permitted by default",
82                            username, DEFAULT_USERNAME);
83
84                 data->status = AUTHOR_STATUS_PASS_ADD;
85                 data->output_args = NULL;
86                 data->num_out_args = 0;
87                 return (0);
88             }
89
90             if (debug & DEBUG_AUTHOR_FLAG)
91                 report(LOG_DEBUG,
92                        "user '%s' or '%s' not found, denied by default",
93                        username, DEFAULT_USERNAME);
94             data->status = AUTHOR_STATUS_FAIL;
95             return (0);
96         }
97
98         /* assumed (cfg_user_exists(DEFAULT_USERNAME)): */
99
100         if (debug & DEBUG_AUTHOR_FLAG) {
101             report(LOG_DEBUG, "Authorizing user '%s' instead of '%s'",
102                    DEFAULT_USERNAME, username);
103         }
104         username = DEFAULT_USERNAME;
105     }
106
107     /* See if there's a program defined which will do authorization for us */
108     if (pre_authorization(username, data))
109         return(0);
110
111     /*
112      * Decide what kind of authorization request this is. Currently
113      * one of: exec, cmd, slip, arap, ppp or <string>
114      *
115      * If it's a command typed to the exec, return its text in cmd.
116      *
117      * If it's a ppp request, return the protocol name in protocol.
118      */
119
120     svc = get_nas_svc(data, &cmd, &protocol, &svcname);
121
122     if (!svc) {
123         /* if we can't identify the service in the request it's an error */
124         data->status = AUTHOR_STATUS_ERROR;
125         data->admin_msg =
126         tac_strdup("No identifiable service/protocol in authorization request");
127         if (debug & DEBUG_AUTHOR_FLAG) {
128             report(LOG_DEBUG, "user %s %s", username, data->admin_msg);
129         }
130         return (0);
131     }
132
133     if (debug & DEBUG_AUTHOR_FLAG)
134         report(LOG_DEBUG, "user '%s' found", username);
135
136 #ifdef MAXSESS
137     /* Never permit if they're going over their session limit */
138     switch (svc) {
139     case N_svc_arap:
140     case N_svc_ppp:
141     case N_svc_slip:
142     case N_svc_exec:
143 /*    case N_svc: */
144         if (maxsess_check_count(username, data)) {
145             return(0);
146         }
147
148     default:
149         break;
150     }
151 #endif /* MAXSESS */
152
153 #ifdef USE_PAM
154     /* Check  PAM Authorization */
155     switch (svc) {
156
157     case N_svc_ppp:
158     case N_svc_exec:
159         if ((pam_service = cfg_get_pam_service(data->id->username, TAC_PLUS_RECURSE) )) {
160
161             if (debug & DEBUG_AUTHOR_FLAG)
162                 report(LOG_DEBUG, "PAM Authorization begin for user %s",data->id->username);
163             if (tac_pam_authorization(data->id->username, data, pam_service)) {
164                 if (debug & DEBUG_AUTHOR_FLAG)
165                     report(LOG_DEBUG, "PAM Authorization Fail");
166                 return(0);
167             }
168         } /* Pam_service */
169
170     default:
171         break;
172     }
173 #endif
174
175     switch(svc) {
176     default:
177         report(LOG_ERR, "%s: Bad service type %d", session.peer, svc);
178         data->status = AUTHOR_STATUS_FAIL;
179         return(0);
180
181     case N_svc_cmd:
182         /* A command authorisation request */
183         status = authorize_cmd(username, cmd, data);
184         break;
185
186     case N_svc_exec:
187         if (authorize_exec(username, data))
188             return(0);
189         /* FALLTHRU */
190
191     case N_svc_arap:
192     case N_svc_ppp:
193     case N_svc_slip:
194         status = authorize_svc(username, svc, protocol, NULL, data);
195         break;
196
197     case N_svc:
198         status = authorize_svc(username, svc, protocol, svcname, data);
199         break;
200     }
201
202     post_authorization(username, data);
203     return(status);
204 }
205
206 /* If an before-authorization program has been specified, call it.
207
208    A return value of 1 means no further authorization is required
209 */
210
211 static int pre_authorization TAC_ARGS((const char *username, struct author_data *data));
212
213 static int
214 pre_authorization(username, data)
215 const char *username;
216 struct author_data *data;
217 {
218     int status;
219     char **out_args;
220     int out_cnt, i;
221     const char *cmd;
222     char error_str[255];
223     int error_len = 255;
224
225     out_cnt = 0;
226     out_args = NULL;
227
228     /* If a before-authorization program exists, call it to see how to
229        proceed */
230
231     cmd = cfg_get_pvalue(S_user, username,
232                          S_before, TAC_PLUS_RECURSE);
233     if (!cmd)
234         return(0);
235
236     if (debug & DEBUG_AUTHOR_FLAG)
237         report(LOG_DEBUG, "Before authorization call: %s", cmd);
238
239     status = call_pre_process(cmd, data, &out_args, &out_cnt, error_str,
240                               error_len);
241
242     switch (status) {
243     default:
244         if (debug & DEBUG_AUTHOR_FLAG)
245             report(LOG_DEBUG, "cmd %s returns %d (unrecognised value)",
246                    cmd, status);
247
248         data->status = AUTHOR_STATUS_ERROR;
249         data->admin_msg =
250             tac_strdup("Illegal return status from pre-authorization command");
251         data->msg = tac_strdup(error_str);
252         data->num_out_args = 0;
253         data->output_args = NULL;
254         /* throw away out_args */
255         for(i=0; i < out_cnt; i++) {
256             free(out_args[i]);
257         }
258         if (out_args) {
259             free(out_args);
260         }
261         return(1);
262
263     case 0: /* Permit */
264         if (debug & DEBUG_AUTHOR_FLAG)
265             report(LOG_DEBUG, "cmd %s returns 0 (unconditional permit)", cmd);
266
267         data->status = AUTHOR_STATUS_PASS_ADD;
268         data->num_out_args = 0;
269         data->output_args = NULL;
270
271         /* throw away out_args */
272         for(i=0; i < out_cnt; i++) {
273             free(out_args[i]);
274         }
275         if (out_args) {
276             free(out_args);
277         }
278         return(1);
279
280     case 1: /* Deny */
281         if (debug & DEBUG_AUTHOR_FLAG)
282             report(LOG_DEBUG, "cmd %s returns %d (unconditional deny)",
283                    cmd, status);
284
285         data->status = AUTHOR_STATUS_FAIL;
286         data->msg = tac_strdup(error_str);
287         data->num_out_args = 0;
288         data->output_args = NULL;
289
290         /* throw away out_args */
291         for(i=0; i < out_cnt; i++) {
292             free(out_args[i]);
293         }
294         if (out_args) {
295             free(out_args);
296         }
297         return(1);
298
299     case 2: /* Use replacement AV pairs from program as final result */
300         if (debug & DEBUG_AUTHOR_FLAG) {
301             report(LOG_DEBUG, "cmd %s returns %d (permitted, args replaced)",
302                    cmd, status);
303             for(i=0; i < out_cnt; i++)
304                 report(LOG_DEBUG, "%s", out_args[i]);
305         }
306
307         /* and install the new set of AV pairs as output */
308         data->output_args = out_args;
309         data->num_out_args = out_cnt;
310         data->status = AUTHOR_STATUS_PASS_REPL;
311         return(1); /* no more processing required */
312
313     case 3: /* deny, but return attributes and server-msg to NAS */
314         if (debug & DEBUG_AUTHOR_FLAG) {
315             report(LOG_DEBUG, "cmd %s returns %d (deny, args replaced)",
316                    cmd, status);
317             for(i=0; i < out_cnt; i++)
318                 report(LOG_DEBUG, "%s", out_args[i]);
319         }
320
321         /* and install the new set of AV pairs as output */
322         data->output_args = out_args;
323         data->num_out_args = out_cnt;
324         data->msg = tac_strdup(error_str);
325         data->status = AUTHOR_STATUS_FAIL;
326         return(1); /* no more processing required */
327     }
328 }
329
330 /* If an after-authorization program has been specified, call it. It
331    can rewrite the output arguments in the authorization data, or
332    change the authorization status by calling an external program.
333 */
334
335 static void post_authorization TAC_ARGS((const char *username, struct author_data *data));
336
337 static void
338 post_authorization(username, data)
339 const char *username;
340 struct author_data *data;
341 {
342     char **out_args;
343     int out_cnt, i;
344     int status;
345     const char *after = cfg_get_pvalue(S_user, username, S_after, TAC_PLUS_RECURSE);
346     if (!after)
347         return;
348
349     if (debug & DEBUG_AUTHOR_FLAG)
350         report(LOG_DEBUG, "After authorization call: %s", after);
351
352     status = call_post_process(after, data, &out_args, &out_cnt);
353
354     if (status != 2) {
355         /* throw away out_args */
356         for(i=0; i < out_cnt; i++) {
357             free(out_args[i]);
358         }
359         free(out_args);
360     }
361
362     switch (status) {
363     default:
364         if (debug & DEBUG_AUTHOR_FLAG)
365             report(LOG_DEBUG,
366                    "cmd %s returns %d (Error)", after, status);
367
368         data->status = AUTHOR_STATUS_ERROR;
369         return;
370
371     case 0:                             /* Permit */
372         if (debug & DEBUG_AUTHOR_FLAG)
373             report(LOG_DEBUG, "cmd %s returns 0 (no change)", after);
374         return;
375
376     case 1:                             /* Deny */
377         if (debug & DEBUG_AUTHOR_FLAG)
378             report(LOG_DEBUG, "cmd %s returns %d (unconditional deny)",
379                    after, status);
380
381         data->status = AUTHOR_STATUS_FAIL;
382         return;
383
384     case 2:
385         /* Use replacement AV pairs from program */
386         if (debug & DEBUG_AUTHOR_FLAG)
387             report(LOG_DEBUG, "cmd %s returns 2 (replace & continue)",
388                    after);
389
390         /* Free any existing AV output pairs */
391         if (data->num_out_args) {
392             for(i=0; i < data->num_out_args; i++) {
393                 free(data->output_args[i]);
394             }
395             free(data->output_args);
396             data->output_args = NULL;
397         }
398
399         if (debug & DEBUG_AUTHOR_FLAG) {
400             report(LOG_DEBUG, "status is now AUTHOR_STATUS_PASS_REPL");
401         }
402
403         data->status = AUTHOR_STATUS_PASS_REPL;
404         data->output_args = out_args;
405         data->num_out_args = out_cnt;
406         return;
407     }
408 }
409
410
411 static char *value TAC_ARGS((char *s));
412
413 /* Return a pointer to the value part of an attr=value string */
414 static char *
415 value(s)
416 char *s;
417 {
418     while (*s && *s != '=' && *s != '*')
419         s++;
420     if (*s)
421         return (++s);
422     return (NULL);
423 }
424
425 /* Reassemble the command arguments as typed by the user, out of the
426    array of args we received. Return "" if there are no arguments */
427
428 static char *assemble_args TAC_ARGS((struct author_data *data));
429
430 static char *
431 assemble_args(data)
432 struct author_data *data;
433 {
434     char *buf;
435     int i;
436     char *nas_arg, *v;
437     int len;
438
439     len = 0;
440     for (i = 0; i < data->num_in_args; i++) {
441         nas_arg = data->input_args[i];
442         if (strncmp(nas_arg, "cmd-arg", strlen("cmd-arg"))==0)
443             len += strlen(value(nas_arg)) + 1;
444     }
445
446     if (len <= 0) {
447         return(tac_strdup(""));
448     }
449
450     buf = tac_malloc(len);
451     buf[0] = '\0';
452
453     for (i = 0; i < data->num_in_args; i++) {
454         nas_arg = data->input_args[i];
455         if (strncmp(nas_arg, "cmd-arg", strlen("cmd-arg")))
456             continue;
457
458         v = value(nas_arg);
459         if (!v) {
460             free(buf);
461             return (NULL);
462         }
463         strcat(buf, v);
464         if (i < (data->num_in_args - 1))
465             strcat(buf, " ");
466     }
467     return (buf);
468 }
469
470
471 /* See if an exec is authorized. Either the user has explicitly
472    authorized the exec, or she has authorized some commands (which
473    implicitly authorizes an exec), or the default is permit.
474
475    If she has explicitly authorized an exec, we need to process its
476    attribute=value pairs. We indicate this by returning zero to the
477    caller.
478
479    Otherwise, we return 1, indicating no further processing is
480    required for this request. */
481
482 static int authorize_exec TAC_ARGS((const char *user, struct author_data *data));
483
484 static int
485 authorize_exec(user, data)
486 const char *user;
487 struct author_data *data;
488 {
489     if (debug & DEBUG_AUTHOR_FLAG)
490         report(LOG_DEBUG, "exec authorization request for %s", user);
491
492     /* Is an exec explicitly configured? If so, return 0 so we know to
493        process its attributes */
494
495     if (cfg_get_svc_node(user, N_svc_exec, NULL, NULL, TAC_PLUS_RECURSE, NULL /* nodep */)) {
496         if (debug & DEBUG_AUTHOR_FLAG)
497             report(LOG_DEBUG, "exec is explicitly permitted");
498         return (0);
499     }
500
501     /* No exec is configured. Are any commands configured? */
502     if (cfg_get_svc_node(user, N_svc_cmd, NULL, NULL, TAC_PLUS_RECURSE, NULL /* nodep */)) {
503         if (debug & DEBUG_AUTHOR_FLAG)
504             report(LOG_DEBUG, "exec permitted because commands are configured");
505
506         data->status = AUTHOR_STATUS_PASS_ADD;
507         data->output_args = NULL;
508         data->num_out_args = 0;
509         return (1);
510     }
511
512     if (debug & DEBUG_AUTHOR_FLAG)
513         report(LOG_DEBUG, "exec denied by default");
514
515     data->status = AUTHOR_STATUS_FAIL;
516     data->num_out_args = 0;
517     return(1);
518 }
519
520 /* Is an exec command authorized per our database(s)?
521    Return 0 if status is valid */
522
523 static int authorize_cmd TAC_ARGS((const char *user, const char *cmd, struct author_data *data));
524
525 static int
526 authorize_cmd(user, cmd, data)
527 const char *user;
528 const char *cmd;
529 struct author_data *data;
530 {
531     char *args;
532
533     if (!cmd) {
534         data->status = AUTHOR_STATUS_ERROR;
535         data->admin_msg = tac_strdup("No command found");
536         report(LOG_ERR, "%s: %s %s", session.peer, cmd, data->admin_msg);
537         data->num_out_args = 0;
538         return (0);
539     }
540
541     args = assemble_args(data);
542     switch (cfg_authorize_cmd(user, cmd, args)) {
543
544     case ER_TRUE:
545         data->status = AUTHOR_STATUS_PASS_ADD;
546         data->num_out_args = 0;
547         break;
548
549     case ER_FALSE:
550         data->status = AUTHOR_STATUS_FAIL;
551         data->num_out_args = 0;
552         break;
553
554     case ER_UNKNOWN:
555         data->status = AUTHOR_STATUS_ERROR;
556         data->admin_msg = tac_strdup("Server error illegal configuration");
557         break;
558     }
559
560     if (args)
561         free(args);
562     return(0);
563 }
564
565 static int is_separator TAC_ARGS((int ch));
566
567 static int
568 is_separator(ch)
569 int ch;                         /* promoted "char" type */
570 {
571     return (ch == '=' || ch == '*');
572 }
573
574 static int arg_ok TAC_ARGS((char *arg));
575
576 /* check an attr=value pair for well-formedness */
577 static int
578 arg_ok(arg)
579 char *arg;
580 {
581     char *p = arg;
582
583     /* It must contain an attribute */
584     if (!*p)
585         return(0);
586
587     for(p=arg; *p; p++) {
588         if (is_separator(*p)) {
589             if (p == arg) /* no attribute */
590                 return(0);
591             return(1);
592         }
593     }
594     /* no separator */
595     return(0);
596 }
597
598
599 static int match_attrs TAC_ARGS((char *nas_arg, char *server_arg));
600
601 /* return 1 if attrs match, 0 otherwise */
602 static int
603 match_attrs(nas_arg, server_arg)
604 char *nas_arg, *server_arg;
605 {
606     while (*nas_arg && *server_arg) {
607         if (is_separator(*nas_arg) && is_separator(*server_arg)) {
608             return (1);
609         }
610         if (*nas_arg != *server_arg)
611             return (0);
612         nas_arg++;
613         server_arg++;
614     }
615     return (0);
616 }
617
618 static int match_values TAC_ARGS((char *nas_arg, char *server_arg));
619
620 /* return 1 if values match, 0 otherwise */
621 static int
622 match_values(nas_arg, server_arg)
623 char *nas_arg, *server_arg;
624 {
625     while (*nas_arg &&
626            *server_arg &&
627            !is_separator(*nas_arg)) {
628         nas_arg++;
629         server_arg++;
630     }
631
632     if (!*nas_arg)
633         return(0);
634
635     /* skip separator */
636     nas_arg++;
637     if (*server_arg)
638         server_arg++;
639
640     /* compare values */
641     return(STREQ(nas_arg, server_arg));
642 }
643
644 static int mandatory TAC_ARGS((char *arg));
645
646 /* Return 1 if arg is mandatory, 0 otherwise */
647 static int
648 mandatory(arg)
649 char *arg;
650 {
651     char *p = arg;
652
653     while (*p && !is_separator(*p))
654         p++;
655
656     /* if we're not at the end, this must be the separator */
657     if (*p && !is_separator(*p)) {
658         report(LOG_ERR, "%s: Error on arg %s cannot find separator",
659                session.peer, arg);
660         return (0);
661     }
662     return (*p == '=');
663 }
664
665 static int optional TAC_ARGS((char *arg));
666
667 static int
668 optional(arg)
669 char *arg;
670 {
671     return (!mandatory(arg));
672 }
673
674 /* PPP-LCP requests are a special case. If they are not explicitly
675    configured, but there are other ppp services explicitly configured,
676    we admit (return 1) any PPP-LCP request */
677
678 static int ppp_lcp_allowed TAC_ARGS((const char *user));
679
680 static int
681 ppp_lcp_allowed(user)
682 const char *user;
683 {
684     /* It is an LCP request. Are there PPP services configured? */
685     if (cfg_get_svc_node(user, N_svc_ppp, NULL /* protocol */, NULL /* svcname */, TAC_PLUS_RECURSE, NULL /* nodep */)) {
686         if (debug & DEBUG_AUTHOR_FLAG) {
687             report(LOG_DEBUG,
688                    "ppp/lcp request permitted (ppp is configured for %s)",
689                    user);
690         }
691         return(1);
692     }
693
694     /* It is an LCP request but no PPP services are configured */
695     if (debug & DEBUG_AUTHOR_FLAG) {
696         report(LOG_DEBUG, "ppp/lcp request denied (ppp not configured for %s)",
697                user);
698     }
699     return(0);
700 }
701
702 static int authorize_svc TAC_ARGS((const char *user, int svc, const char *protocol, const char *svcname, struct author_data *data));
703
704 /* Return 0 means data->status is valid */
705 static int
706 authorize_svc(user, svc, protocol, svcname, data)
707 const char *user;
708 int svc;
709 const char *svcname;
710 struct author_data *data;
711 const char *protocol;           /* valid only if svc == ppp */
712 {
713     int max_args;
714     char **out_args, **outp;
715     char *nas_arg, *cfg_arg;
716     int i, j;
717     char **cfg_args;
718     char **cfg_argp;
719     int deny_by_default;
720     NODE *node;
721     int service_permit;
722
723     int replaced = 0;
724     int added = 0;
725     int cfg_cnt;
726
727     /* Does this service exist? */
728     service_permit = cfg_get_svc_node(user, svc, protocol, svcname, TAC_PLUS_RECURSE, &node);
729
730     /* Now we may have three cases:
731      * service_permit == 1 && node != NULL
732      * service_permit == 1 && node == NULL
733      * service_permit == 0    (BTW node == NULL)
734      */
735
736     if (service_permit && !node) {
737         /* Service not found and the default is permit, we'll allow it. */
738
739         if (debug & DEBUG_AUTHOR_FLAG)
740             report(LOG_DEBUG,
741            "svc=%s protocol=%s svcname=%s not found, permitted by default",
742                    cfg_nodestring(svc),
743                    protocol ? protocol : "",
744                    svcname ? svcname : "");
745
746         data->status = AUTHOR_STATUS_PASS_ADD;
747         data->num_out_args = 0;
748         data->output_args = NULL;
749         return(0);
750         }
751
752     if (!service_permit) {
753         /* Service not found, if this is an
754            PPP/LCP request and other ppp services are configured,
755            we'll allow it. */
756
757         if (svc == N_svc_ppp && protocol && STREQ(protocol, "lcp")
758          && ppp_lcp_allowed(user)) {
759             data->status = AUTHOR_STATUS_PASS_ADD;
760             data->num_out_args = 0;
761             data->output_args = NULL;
762             return(0);
763         }
764
765         if (debug & DEBUG_AUTHOR_FLAG)
766             report(LOG_DEBUG, "svc=%s protocol=%s not found, denied by default",
767                    cfg_nodestring(svc), protocol ? protocol : "");
768
769         data->status = AUTHOR_STATUS_FAIL;
770         data->num_out_args = 0;
771         data->output_args = NULL;
772         return(0);
773     }
774
775     /* Get server args configured in the config file. */
776     cfg_args = cfg_get_svc_attrs(node, &deny_by_default);
777
778     /* Check the nas args for well-formedness */
779     for (i = 0; i < data->num_in_args; i++) {
780         if (!arg_ok(data->input_args[i])) {
781             char buf[MAX_INPUT_LINE_LEN+50];
782             sprintf(buf, "Illegal arg %s from NAS", data->input_args[i]);
783             data->status = AUTHOR_STATUS_ERROR;
784             data->admin_msg = tac_strdup(buf);
785             report(LOG_ERR, "%s: Error %s", session.peer, buf);
786
787             /* free any server arguments */
788             for(cfg_argp = cfg_args; cfg_args && *cfg_argp; cfg_argp++)
789                 free(*cfg_argp);
790             free(cfg_args);
791             return (0);
792         }
793     }
794
795     /* How many configured AV pairs are there ? */
796     for (cfg_cnt = 0; cfg_args && cfg_args[cfg_cnt];)
797         cfg_cnt++;
798
799     /* Allocate space for in + out args */
800     max_args = cfg_cnt + data->num_in_args;
801     out_args = (char **) tac_malloc((max_args + 1) * sizeof(char *));
802     outp = out_args;
803     data->num_out_args = 0;
804
805     bzero(out_args, (max_args + 1) * sizeof(char *));
806
807     for (i = 0; i < data->num_in_args; i++) {
808         nas_arg = data->input_args[i];
809
810         /* always pass these pairs through unchanged */
811         if (match_attrs(nas_arg, "service=") ||
812             match_attrs(nas_arg, "protocol=") ||
813             match_attrs(nas_arg, "cmd=")) {
814
815             if (debug & DEBUG_AUTHOR_FLAG) {
816                 report(LOG_DEBUG, "nas:%s (passed thru)", nas_arg);
817             }
818             *outp++ = tac_strdup(nas_arg);
819             data->num_out_args++;
820             continue;
821         }
822
823         /* NAS AV pair is mandatory */
824         if (mandatory(nas_arg)) {
825
826             /* a). look for an exact attribute,value match in the daemon's
827                mandatory list. If found, add the AV pair to the output */
828
829             for (j = 0; j < cfg_cnt; j++) {
830                 cfg_arg = cfg_args[j];
831                 if (optional(cfg_arg))
832                     continue;
833
834                 if (STREQ(nas_arg, cfg_arg)) {
835                     if (debug & DEBUG_AUTHOR_FLAG) {
836                         report(LOG_DEBUG, "nas:%s, svr:%s -> add %s (a)",
837                                nas_arg, cfg_arg, nas_arg);
838                     }
839                     *outp++ = tac_strdup(nas_arg);
840                     data->num_out_args++;
841                     goto next_nas_arg;
842                 }
843             }
844
845             /* b). If an exact match doesn't exist, look in the
846                daemon's optional list for the first attribute
847                match. If found, add the NAS AV pair to the output */
848
849             for (j = 0; j < cfg_cnt; j++) {
850                 cfg_arg = cfg_args[j];
851                 if (mandatory(cfg_arg))
852                     continue;
853
854                 if (match_attrs(nas_arg, cfg_arg)) {
855                     if (debug & DEBUG_AUTHOR_FLAG) {
856                         report(LOG_DEBUG, "nas:%s, svr:%s -> add %s (b)",
857                                nas_arg, cfg_arg, nas_arg);
858                     }
859                     *outp++ = tac_strdup(nas_arg);
860                     data->num_out_args++;
861                     goto next_nas_arg;
862                 }
863             }
864
865             /* c). If no attribute match exists, deny the command if the
866                default is to deny */
867
868             if (deny_by_default) {
869                 data->status = AUTHOR_STATUS_FAIL;
870                 if (debug & DEBUG_AUTHOR_FLAG) {
871                     report(LOG_DEBUG, "nas:%s svr:absent, default=deny -> denied (c)",
872                            nas_arg);
873                 }
874                 if (out_args) {
875                     for (i = 0; i < data->num_out_args; i++)
876                         free(out_args[i]);
877                     free(out_args);
878                 }
879
880                 data->num_out_args = 0;
881                 data->output_args = NULL;
882
883                 /* free the server arguments */
884                 for(cfg_argp = cfg_args; *cfg_argp; cfg_argp++)
885                     free(*cfg_argp);
886                 free(cfg_args);
887                 return (0);
888             }
889
890             /* d). If the default is permit, add the NAS AV pair to
891                the output */
892
893             if (debug & DEBUG_AUTHOR_FLAG) {
894                 report(LOG_DEBUG,
895                        "nas:%s, svr:absent, default=permit -> add %s (d)",
896                        nas_arg, nas_arg);
897             }
898             *outp++ = tac_strdup(nas_arg);
899             data->num_out_args++;
900             goto next_nas_arg;
901
902         } else {
903
904             /* NAS AV pair is Optional */
905
906             /* e). look for an exact attribute,value match in the mandatory
907                list. If found, add DAEMON's AV pair to output */
908
909             for (j = 0; j < cfg_cnt; j++) {
910                 cfg_arg = cfg_args[j];
911                 if (optional(cfg_arg))
912                     continue;
913
914                 if (match_attrs(nas_arg, cfg_arg) &&
915                     match_values(nas_arg, cfg_arg)) {
916
917                     if (debug & DEBUG_AUTHOR_FLAG) {
918                         report(LOG_DEBUG, "nas:%s svr:%s -> replace with %s (e)",
919                                nas_arg, cfg_arg, cfg_arg);
920                     }
921                     *outp++ = tac_strdup(cfg_arg);
922                     data->num_out_args++;
923                     replaced++;
924                     goto next_nas_arg;
925                 }
926             }
927
928             /* f). If not found, look for the first attribute match in
929                the mandatory list. If found, add DAEMONS's AV pair to
930                output */
931
932             for (j = 0; j < cfg_cnt; j++) {
933                 cfg_arg = cfg_args[j];
934                 if (optional(cfg_arg))
935                     continue;
936
937                 if (match_attrs(nas_arg, cfg_arg)) {
938                     if (debug & DEBUG_AUTHOR_FLAG) {
939                         report(LOG_DEBUG, "nas:%s svr:%s -> replace with %s (f)",
940                                nas_arg, cfg_arg, cfg_arg);
941                     }
942                     *outp++ = tac_strdup(cfg_arg);
943                     data->num_out_args++;
944                     replaced++;
945                     goto next_nas_arg;
946                 }
947             }
948
949             /* g). If no mandatory match exists, look for an exact
950                attribute,value pair match among the daemon's optional AV
951                pairs. If found add the DAEMON's matching AV pair to the
952                output.
953                */
954
955             for (j = 0; j < cfg_cnt; j++) {
956                 cfg_arg = cfg_args[j];
957                 if (!optional(cfg_arg))
958                     continue;
959
960                 if (match_attrs(nas_arg, cfg_arg) &&
961                     match_values(nas_arg, cfg_arg)) {
962                     if (debug & DEBUG_AUTHOR_FLAG) {
963                         report(LOG_DEBUG, "nas:%s svr:%s -> replace with %s (g)",
964                                nas_arg, cfg_arg, cfg_arg);
965                     }
966                     *outp++ = tac_strdup(cfg_arg);
967                     data->num_out_args++;
968                     replaced++;
969                     goto next_nas_arg;
970                 }
971             }
972
973             /* h). If no exact match exists, locate the first
974                attribute match among the daemon's optional AV
975                pairs. If found add the DAEMON's matching AV pair to
976                the output */
977
978             for (j = 0; j < cfg_cnt; j++) {
979                 cfg_arg = cfg_args[j];
980                 if (!optional(cfg_arg))
981                     continue;
982
983                 if (match_attrs(nas_arg, cfg_arg)) {
984                     if (debug & DEBUG_AUTHOR_FLAG) {
985                         report(LOG_DEBUG, "nas:%s svr:%s -> replace with %s (h)",
986                                nas_arg, cfg_arg, cfg_arg);
987                     }
988                     *outp++ = tac_strdup(cfg_arg);
989                     data->num_out_args++;
990                     replaced++;
991                     goto next_nas_arg;
992                 }
993             }
994
995
996             /* i). If no match is found, delete the AV pair if default is
997                deny */
998
999             if (deny_by_default) {
1000                 if (debug & DEBUG_AUTHOR_FLAG) {
1001                     report(LOG_DEBUG, "nas:%s svr:absent/deny -> delete %s (i)",
1002                            nas_arg, nas_arg);
1003                 }
1004                 replaced++;
1005                 goto next_nas_arg;
1006             }
1007
1008             /* j). If the default is permit add the NAS AV pair to the output */
1009
1010             if (debug & DEBUG_AUTHOR_FLAG) {
1011                 report(LOG_DEBUG, "nas:%s svr:absent/permit -> add %s (j)",
1012                        nas_arg, nas_arg);
1013             }
1014             *outp++ = tac_strdup(nas_arg);
1015             data->num_out_args++;
1016             goto next_nas_arg;
1017         }
1018     next_nas_arg:;
1019
1020     }
1021
1022
1023     /* k). After all AV pairs have been processed, for each mandatory
1024        DAEMON AV pair, if there is no attribute match already in the
1025        output list, add the AV pair (add only one AV pair for each
1026        mandatory attribute) */
1027
1028     for (i = 0; i < cfg_cnt; i++) {
1029         cfg_arg = cfg_args[i];
1030
1031         if (!mandatory(cfg_arg))
1032             continue;
1033
1034         for (j = 0; j < data->num_out_args; j++) {
1035             char *output_arg = out_args[j];
1036
1037             if (match_attrs(cfg_arg, output_arg)) {
1038                 goto next_cfg_arg;
1039             }
1040         }
1041
1042         /* Attr is required by daemon but not present in
1043            output. Add it */
1044
1045         if (debug & DEBUG_AUTHOR_FLAG) {
1046             report(LOG_DEBUG, "nas:absent, server:%s -> add %s (k)",
1047                    cfg_arg, cfg_arg);
1048         }
1049         added++;
1050         *outp++ = tac_strdup(cfg_arg);
1051         data->num_out_args++;
1052
1053     next_cfg_arg:;
1054
1055     }
1056
1057     /* If we replaced or deleted some pairs we must return the entire
1058        list we've constructed */
1059
1060     if (replaced) {
1061         if (debug & DEBUG_AUTHOR_FLAG) {
1062             report(LOG_DEBUG, "replaced %d args", replaced);
1063         }
1064         data->status = AUTHOR_STATUS_PASS_REPL;
1065         data->output_args = out_args;
1066
1067         /* free the server arguments */
1068         for(cfg_argp = cfg_args; *cfg_argp; cfg_argp++)
1069             free(*cfg_argp);
1070         free(cfg_args);
1071
1072         return (0);
1073     }
1074
1075     /* We added something not on the original nas list, but didn't
1076        replace or delete anything. We should return only the
1077        additions */
1078
1079     if (added) {
1080
1081         if (debug & DEBUG_AUTHOR_FLAG)
1082             report(LOG_DEBUG, "added %d args", added);
1083
1084         /* throw away output args which are just copies of the input args */
1085         for (i = 0; i < data->num_in_args; i++) {
1086             if (debug & DEBUG_AUTHOR_FLAG) {
1087                 report(LOG_DEBUG, "out_args[%d] = %s input copy discarded",
1088                        i, out_args[i]);
1089             }
1090             free(out_args[i]);
1091             out_args[i] = NULL;
1092         }
1093
1094         /* Now compact the new args added to the end of the array down
1095            to the beginning */
1096
1097         j = 0;
1098         for (i = data->num_in_args; i < data->num_out_args; i++) {
1099             if (out_args[j]) /* we goofed */
1100                 report(LOG_ERR, "%s: out_args[%d] should be NULL",
1101                        session.peer, j);
1102             if (!out_args[i]) /* we goofed */
1103                 report(LOG_ERR, "%s: out_args[%d] should not be NULL",
1104                        session.peer, i);
1105
1106             if (debug & DEBUG_AUTHOR_FLAG) {
1107                 report(LOG_DEBUG, "out_args[%d] = %s compacted to out_args[%d]",
1108                        i, out_args[i], j);
1109             }
1110             out_args[j++] = out_args[i];
1111             out_args[i] = NULL;
1112         }
1113         data->num_out_args = j;
1114         if (debug & DEBUG_AUTHOR_FLAG) {
1115             report(LOG_DEBUG, "%d output args", data->num_out_args);
1116         }
1117
1118         /* should/could do a realloc here but it won't matter */
1119         data->status = AUTHOR_STATUS_PASS_ADD;
1120         data->output_args = out_args;
1121
1122         /* free the server arguments */
1123         for(cfg_argp = cfg_args; *cfg_argp; cfg_argp++)
1124             free(*cfg_argp);
1125         free(cfg_args);
1126
1127         return (0);
1128     }
1129
1130     /* no additions or replacements. Input and output are
1131        identical. Don't need to return anything */
1132
1133     if (debug & DEBUG_AUTHOR_FLAG) {
1134         report(LOG_DEBUG, "added %d", added);
1135     }
1136     data->status = AUTHOR_STATUS_PASS_ADD;
1137     if (out_args) {
1138         for (i = 0; i < data->num_out_args; i++) {
1139             free(out_args[i]);
1140         }
1141         free(out_args);
1142     }
1143
1144     /* Final sanity check */
1145     if (data->num_out_args != data->num_in_args) {
1146         data->status = AUTHOR_STATUS_ERROR;
1147         data->admin_msg = tac_strdup("Bad output arg cnt from do_author");
1148         report(LOG_ERR, "%s: Error %s", session.peer, data->admin_msg);
1149
1150         /* free the server arguments */
1151         for(cfg_argp = cfg_args; *cfg_argp; cfg_argp++)
1152             free(*cfg_argp);
1153         free(cfg_args);
1154
1155         return (0);
1156     }
1157
1158     data->num_out_args = 0;
1159     data->output_args = NULL;
1160
1161     /* free the server arguments */
1162     for(cfg_argp = cfg_args; *cfg_argp; cfg_argp++)
1163         free(*cfg_argp);
1164     free(cfg_args);
1165
1166     return (0);
1167 }
1168
1169 /* Return an integer indicating which kind of service is being
1170    requested.
1171
1172    Conveniently this integer is one of our node types. If the service
1173    is a command authorisation request, also return the command name in
1174    cmdname.
1175
1176    If this service is a ppp request, return the protocol name in
1177    protocol.
1178
1179    If this service is not one of the standard, known ones, return its
1180    name in svcname.
1181 */
1182
1183 static int get_nas_svc TAC_ARGS((struct author_data *data, char **cmdname, char **protocol, char **svcname));
1184
1185 static int
1186 get_nas_svc(data, cmdname, protocol, svcname)
1187 struct author_data *data;
1188 char **cmdname, **protocol, **svcname;
1189 {
1190     int i;
1191     char *nas_arg;
1192
1193     *cmdname = NULL;
1194     *protocol = NULL;
1195     *svcname = NULL;
1196
1197     for (i = 0; i < data->num_in_args; i++) {
1198         nas_arg = data->input_args[i];
1199
1200         if (STREQ(nas_arg, "service=shell")) {
1201             for (i = 0; i < data->num_in_args; i++) {
1202                 nas_arg = data->input_args[i];
1203                 if (strncmp(nas_arg, "cmd", strlen("cmd")) == 0) {
1204                     /* A cmd=<nothing> means we are authorising exec startup */
1205                     if ((int)strlen(nas_arg) <= 4)
1206                         return (N_svc_exec);
1207
1208                     /* A non-null command means we are authorising a command */
1209                     *cmdname = nas_arg + strlen("cmd") + 1;
1210                     return (N_svc_cmd);
1211                 }
1212             }
1213             return(0);
1214         }
1215
1216         if (STREQ(nas_arg, "service=slip")) {
1217             return (N_svc_slip);
1218         }
1219         if (STREQ(nas_arg, "service=arap")) {
1220             return (N_svc_arap);
1221         }
1222         if (STREQ(nas_arg, "service=ppp")) {
1223             for (i = 0; i < data->num_in_args; i++) {
1224                 nas_arg = data->input_args[i];
1225                 if (strncmp(nas_arg, "protocol", strlen("protocol")) == 0) {
1226                     *protocol = nas_arg + strlen("protocol") + 1;
1227                     return(N_svc_ppp);
1228                 }
1229             }
1230         }
1231
1232         if (strncmp(nas_arg, "service=", strlen("service=")) ==0 ) {
1233             *svcname = nas_arg + strlen("service=");
1234             return(N_svc);
1235         }
1236     }
1237     return (0);
1238 }