2 Copyright (c) 1995-1998 by Cisco systems, Inc.
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.
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.
23 static int get_nas_svc();
24 static int authorize_cmd();
25 static int authorize_exec();
26 static int authorize_svc();
27 static void post_authorization();
28 static int pre_authorization();
30 /* Return 0 is data->status is valid */
33 struct author_data *data;
35 char *username = data->id->username;
38 char *cmd, *protocol, *svcname;
40 char *pam_service= NULL;
44 data->status = AUTHOR_STATUS_FAIL; /* for safety */
46 data->output_args = NULL;
47 data->num_out_args = 0;
49 /* If this user doesn't exist in our configs, do the default */
51 if (!cfg_user_exists(username) && !cfg_user_exists(DEFAULT_USERNAME)) {
53 if (cfg_no_user_permitted()) {
54 if (debug & DEBUG_AUTHOR_FLAG)
56 "user '%s' or '%s' not found, permitted by default",
57 username, DEFAULT_USERNAME);
59 data->status = AUTHOR_STATUS_PASS_ADD;
60 data->output_args = NULL;
61 data->num_out_args = 0;
65 if (debug & DEBUG_AUTHOR_FLAG)
67 "user '%s' or '%s' not found, denied by default",
68 username, DEFAULT_USERNAME);
69 data->status = AUTHOR_STATUS_FAIL;
73 if (!cfg_user_exists(username) && cfg_user_exists(DEFAULT_USERNAME)) {
74 if (debug & DEBUG_AUTHOR_FLAG) {
75 report(LOG_DEBUG, "Authorizing user '%s' instead of '%s'",
76 DEFAULT_USERNAME, username);
78 username = DEFAULT_USERNAME;
81 /* See if there's a program defined which will do authorization for us */
82 if (pre_authorization(username, data))
86 * Decide what kind of authorization request this is. Currently
87 * one of: exec, cmd, slip, arap, ppp or <string>
89 * If it's a command typed to the exec, return its text in cmd.
91 * If it's a ppp request, return the protocol name in protocol.
94 svc = get_nas_svc(data, &cmd, &protocol, &svcname);
97 /* if we can't identify the service in the request it's an error */
98 data->status = AUTHOR_STATUS_ERROR;
100 tac_strdup("No identifiable service/protocol in authorization request");
101 if (debug & DEBUG_AUTHOR_FLAG) {
102 report(LOG_DEBUG, "user %s %s", username, data->admin_msg);
107 if (debug & DEBUG_AUTHOR_FLAG)
108 report(LOG_DEBUG, "user '%s' found", username);
111 /* Never permit if they're going over their session limit */
118 if (maxsess_check_count(username, data)) {
128 /* Check PAM Authorization */
132 if (pam_service=cfg_get_pam_service(data->id->username,TAC_PLUS_RECURSE) ) {
134 if (debug & DEBUG_AUTHOR_FLAG)
135 report(LOG_DEBUG, "PAM Authorization begin for user %s",data->id->username);
136 if(tac_pam_authorization(data->id->username,data,pam_service))
138 if (debug & DEBUG_AUTHOR_FLAG)
139 report(LOG_DEBUG, "PAM Authorization Fail");
150 report(LOG_ERR, "%s: Bad service type %d", session.peer, svc);
151 data->status = AUTHOR_STATUS_FAIL;
155 /* A command authorisation request */
156 status = authorize_cmd(username, cmd, data);
160 if (authorize_exec(username, data))
167 status = authorize_svc(username, svc, protocol, NULL, data);
171 status = authorize_svc(username, svc, protocol, svcname, data);
175 post_authorization(username, data);
179 /* If an before-authorization program has been specified, call it.
181 A return value of 1 means no further authorization is required
185 pre_authorization(username, data)
187 struct author_data *data;
199 /* If a before-authorization program exists, call it to see how to
202 cmd = cfg_get_pvalue(username, TAC_IS_USER,
203 S_before, TAC_PLUS_RECURSE);
207 if (debug & DEBUG_AUTHOR_FLAG)
208 report(LOG_DEBUG, "Before authorization call: %s", cmd);
210 status = call_pre_process(cmd, data, &out_args, &out_cnt, error_str,
215 if (debug & DEBUG_AUTHOR_FLAG)
216 report(LOG_DEBUG, "cmd %s returns %d (unrecognised value)",
219 data->status = AUTHOR_STATUS_ERROR;
221 tac_strdup("Illegal return status from pre-authorization command");
222 data->msg = tac_strdup(error_str);
223 data->num_out_args = 0;
224 data->output_args = NULL;
225 /* throw away out_args */
226 for(i=0; i < out_cnt; i++) {
235 if (debug & DEBUG_AUTHOR_FLAG)
236 report(LOG_DEBUG, "cmd %s returns 0 (unconditional permit)", cmd);
238 data->status = AUTHOR_STATUS_PASS_ADD;
239 data->num_out_args = 0;
240 data->output_args = NULL;
242 /* throw away out_args */
243 for(i=0; i < out_cnt; i++) {
252 if (debug & DEBUG_AUTHOR_FLAG)
253 report(LOG_DEBUG, "cmd %s returns %d (unconditional deny)",
256 data->status = AUTHOR_STATUS_FAIL;
257 data->msg = tac_strdup(error_str);
258 data->num_out_args = 0;
259 data->output_args = NULL;
261 /* throw away out_args */
262 for(i=0; i < out_cnt; i++) {
270 case 2: /* Use replacement AV pairs from program as final result */
271 if (debug & DEBUG_AUTHOR_FLAG) {
272 report(LOG_DEBUG, "cmd %s returns %d (permitted, args replaced)",
274 for(i=0; i < out_cnt; i++)
275 report(LOG_DEBUG, "%s", out_args[i]);
278 /* and install the new set of AV pairs as output */
279 data->output_args = out_args;
280 data->num_out_args = out_cnt;
281 data->status = AUTHOR_STATUS_PASS_REPL;
282 return(1); /* no more processing required */
284 case 3: /* deny, but return attributes and server-msg to NAS */
285 if (debug & DEBUG_AUTHOR_FLAG) {
286 report(LOG_DEBUG, "cmd %s returns %d (deny, args replaced)",
288 for(i=0; i < out_cnt; i++)
289 report(LOG_DEBUG, "%s", out_args[i]);
292 /* and install the new set of AV pairs as output */
293 data->output_args = out_args;
294 data->num_out_args = out_cnt;
295 data->msg = tac_strdup(error_str);
296 data->status = AUTHOR_STATUS_FAIL;
297 return(1); /* no more processing required */
301 /* If an after-authorization program has been specified, call it. It
302 can rewrite the output arguments in the authorization data, or
303 change the authorization status by calling an external program.
307 post_authorization(username, data)
309 struct author_data *data;
314 char *after = cfg_get_pvalue(username, TAC_IS_USER,
315 S_after, TAC_PLUS_RECURSE);
319 if (debug & DEBUG_AUTHOR_FLAG)
320 report(LOG_DEBUG, "After authorization call: %s", after);
322 status = call_post_process(after, data, &out_args, &out_cnt);
325 /* throw away out_args */
326 for(i=0; i < out_cnt; i++) {
334 if (debug & DEBUG_AUTHOR_FLAG)
336 "cmd %s returns %d (Error)", after, status);
338 data->status = AUTHOR_STATUS_ERROR;
342 if (debug & DEBUG_AUTHOR_FLAG)
343 report(LOG_DEBUG, "cmd %s returns 0 (no change)", after);
347 if (debug & DEBUG_AUTHOR_FLAG)
348 report(LOG_DEBUG, "cmd %s returns %d (unconditional deny)",
351 data->status = AUTHOR_STATUS_FAIL;
355 /* Use replacement AV pairs from program */
356 if (debug & DEBUG_AUTHOR_FLAG)
357 report(LOG_DEBUG, "cmd %s returns 2 (replace & continue)",
360 /* Free any existing AV output pairs */
361 if (data->num_out_args) {
362 for(i=0; i < data->num_out_args; i++) {
363 free(data->output_args[i]);
365 free(data->output_args);
366 data->output_args = NULL;
369 if (debug & DEBUG_AUTHOR_FLAG) {
370 report(LOG_DEBUG, "status is now AUTHOR_STATUS_PASS_REPL");
373 data->status = AUTHOR_STATUS_PASS_REPL;
374 data->output_args = out_args;
375 data->num_out_args = out_cnt;
381 /* Return a pointer to the value part of an attr=value string */
386 while (*s && *s != '=' && *s != '*')
393 /* Reassemble the command arguments as typed by the user, out of the
394 array of args we received. Return "" if there are no arguments */
398 struct author_data *data;
406 for (i = 0; i < data->num_in_args; i++) {
407 nas_arg = data->input_args[i];
408 if (strncmp(nas_arg, "cmd-arg", strlen("cmd-arg"))==0)
409 len += strlen(value(nas_arg)) + 1;
413 return(tac_strdup(""));
416 buf = tac_malloc(len);
419 for (i = 0; i < data->num_in_args; i++) {
420 nas_arg = data->input_args[i];
421 if (strncmp(nas_arg, "cmd-arg", strlen("cmd-arg")))
430 if (i < (data->num_in_args - 1))
437 /* See if an exec is authorized. Either the user has explicitly
438 authorized the exec, or she has authorized some commands (which
439 implicitly authorizes an exec), or the default is permit.
441 If she has explicitly authorized an exec, we need to process its
442 attribute=value pairs. We indicate this by returning zero to the
445 Otherwise, we return 1, indicating no further processing is
446 required for this request. */
449 authorize_exec(user, data)
451 struct author_data *data;
455 if (debug & DEBUG_AUTHOR_FLAG)
456 report(LOG_DEBUG, "exec authorization request for %s", user);
458 /* Is an exec explicitly configured? If so, return 0 so we know to
459 process its attributes */
461 svc = cfg_get_svc_node(user, N_svc_exec, NULL, NULL, TAC_PLUS_RECURSE);
463 if (debug & DEBUG_AUTHOR_FLAG)
464 report(LOG_DEBUG, "exec is explicitly permitted by line %d",
469 /* No exec is configured. Are any commands configured? */
470 svc = cfg_get_svc_node(user, N_svc_cmd, NULL, NULL, TAC_PLUS_RECURSE);
472 if (debug & DEBUG_AUTHOR_FLAG)
473 report(LOG_DEBUG, "exec permitted because commands are configured");
475 data->status = AUTHOR_STATUS_PASS_ADD;
476 data->output_args = NULL;
477 data->num_out_args = 0;
481 /* No exec or commands configured. What's the default? */
482 if (cfg_user_svc_default_is_permit(user)) {
484 if (debug & DEBUG_AUTHOR_FLAG)
485 report(LOG_DEBUG, "exec permitted by default");
487 data->status = AUTHOR_STATUS_PASS_ADD;
488 data->output_args = NULL;
489 data->num_out_args = 0;
493 if (debug & DEBUG_AUTHOR_FLAG)
494 report(LOG_DEBUG, "exec denied by default");
496 data->status = AUTHOR_STATUS_FAIL;
497 data->num_out_args = 0;
501 /* Is an exec command authorized per our database(s)?
502 Return 0 if status is valid */
505 authorize_cmd(user, cmd, data)
507 struct author_data *data;
513 args = assemble_args(data);
516 data->status = AUTHOR_STATUS_ERROR;
517 data->admin_msg = tac_strdup("No command found");
518 report(LOG_ERR, "%s: %s %s", session.peer, cmd, data->admin_msg);
519 data->num_out_args = 0;
523 node = cfg_get_cmd_node(user, cmd, TAC_PLUS_RECURSE);
525 /* The command does not exist. Do the default */
528 if (cfg_user_svc_default_is_permit(user)) {
530 if (debug & DEBUG_AUTHOR_FLAG)
531 report(LOG_DEBUG, "cmd %s does not exist, permitted by default",
534 data->status = AUTHOR_STATUS_PASS_ADD;
535 data->num_out_args = 0;
541 if (debug & DEBUG_AUTHOR_FLAG)
542 report(LOG_DEBUG, "cmd %s does not exist, denied by default",
545 data->status = AUTHOR_STATUS_FAIL;
546 data->num_out_args = 0;
552 /* The command exists. The default if nothing matches is DENY */
553 data->status = AUTHOR_STATUS_FAIL;
554 data->num_out_args = 0;
556 for (node=node->value1; node && args; node = node->next) {
557 match = regexec((regexp *) node->value1, args);
559 if (debug & DEBUG_AUTHOR_FLAG) {
560 report(LOG_INFO, "line %d compare %s %s '%s' & '%s' %smatch",
562 node->type == N_permit ? "permit" : "deny",
563 node->value, args, (match ? "" : "no "));
569 switch (node->type) {
571 if (debug & DEBUG_AUTHOR_FLAG) {
572 report(LOG_DEBUG, "%s %s permitted by line %d",
573 cmd, args, node->line);
575 data->status = AUTHOR_STATUS_PASS_ADD;
576 data->num_out_args = 0;
579 if (debug & DEBUG_AUTHOR_FLAG) {
580 report(LOG_DEBUG, "%s %s denied by line %d",
581 cmd, args, node->line);
583 data->status = AUTHOR_STATUS_FAIL;
584 data->num_out_args = 0;
587 data->status = AUTHOR_STATUS_ERROR;
588 data->admin_msg = tac_strdup("Server error illegal configuration node");
589 report(LOG_ERR, "%s: %s %s %s",
590 session.peer, cmd, args, data->admin_msg);
607 return (ch == '=' || ch == '*');
610 /* check an attr=value pair for well-formedness */
617 /* It must contain an attribute */
621 for(p=arg; *p; p++) {
622 if (is_separator(*p)) {
623 if (p == arg) /* no attribute */
633 /* return 1 if attrs match, 0 otherwise */
635 match_attrs(nas_arg, server_arg)
636 char *nas_arg, *server_arg;
638 while (*nas_arg && *server_arg) {
639 if (is_separator(*nas_arg) && is_separator(*server_arg)) {
642 if (*nas_arg != *server_arg)
650 /* return 1 if values match, 0 otherwise */
652 match_values(nas_arg, server_arg)
653 char *nas_arg, *server_arg;
657 !is_separator(*nas_arg)) {
671 return(STREQ(nas_arg, server_arg));
674 /* Return 1 if arg is mandatory, 0 otherwise */
681 while (*p && !is_separator(*p))
684 /* if we're not at the end, this must be the separator */
685 if (*p && !is_separator(*p)) {
686 report(LOG_ERR, "%s: Error on arg %s cannot find separator",
697 return (!mandatory(arg));
700 /* PPP-LCP requests are a special case. If they are not explicitly
701 configured, but there are other ppp services explicitly configured,
702 we admit (return 0) any PPP-LCP request */
705 ppp_lcp_allowed(svc, protocol, user)
707 char *user, *protocol;
709 /* This is not a ppp/lcp request. Just Say No */
710 if (!(svc == N_svc_ppp &&
712 STREQ(protocol, "lcp")))
715 /* It is an LCP request. Are there PPP services configured */
716 if (cfg_ppp_is_configured(user, TAC_PLUS_RECURSE)) {
717 if (debug & DEBUG_AUTHOR_FLAG) {
719 "ppp/lcp request permitted (ppp is configured for %s)",
725 /* It is an LCP request but no PPP services are configured */
726 if (debug & DEBUG_AUTHOR_FLAG) {
727 report(LOG_DEBUG, "ppp/lcp request denied (ppp not configured for %s)",
733 /* Return 0 means data->status is valid */
735 authorize_svc(user, svc, protocol, svcname, data)
739 struct author_data *data;
740 char *protocol; /* valid only if svc == ppp */
743 char **out_args, **outp;
744 char *nas_arg, *cfg_arg;
755 /* Does this service exist? */
756 node = cfg_get_svc_node(user, svc, protocol, svcname, TAC_PLUS_RECURSE);
759 /* Service not found. If the default is permit, or this is an
760 PPP/LCP request and other ppp services are configured,
763 if (cfg_user_svc_default_is_permit(user)) {
765 if (debug & DEBUG_AUTHOR_FLAG)
767 "svc=%s protocol=%s svcname=%s not found, permitted by default",
769 protocol ? protocol : "",
770 svcname ? svcname : "");
772 data->status = AUTHOR_STATUS_PASS_ADD;
773 data->num_out_args = 0;
774 data->output_args = NULL;
778 if (ppp_lcp_allowed(svc, protocol, user)) {
779 data->status = AUTHOR_STATUS_PASS_ADD;
780 data->num_out_args = 0;
781 data->output_args = NULL;
785 if (debug & DEBUG_AUTHOR_FLAG)
786 report(LOG_DEBUG, "svc=%s protocol=%s not found, denied by default",
787 cfg_nodestring(svc), protocol ? protocol : "");
789 data->status = AUTHOR_STATUS_FAIL;
790 data->num_out_args = 0;
791 data->output_args = NULL;
795 /* Get server args configured in the config file. */
796 cfg_args = cfg_get_svc_attrs(node, &deny_by_default);
798 /* Check the nas args for well-formedness */
799 for (i = 0; i < data->num_in_args; i++) {
800 if (!arg_ok(data->input_args[i])) {
801 char buf[MAX_INPUT_LINE_LEN+50];
802 sprintf(buf, "Illegal arg %s from NAS", data->input_args[i]);
803 data->status = AUTHOR_STATUS_ERROR;
804 data->admin_msg = tac_strdup(buf);
805 report(LOG_ERR, "%s: Error %s", session.peer, buf);
807 /* free any server arguments */
808 for(cfg_argp = cfg_args; cfg_args && *cfg_argp; cfg_argp++)
815 /* How many configured AV pairs are there ? */
816 for (cfg_cnt = 0; cfg_args && cfg_args[cfg_cnt];)
819 /* Allocate space for in + out args */
820 max_args = cfg_cnt + data->num_in_args;
821 out_args = (char **) tac_malloc((max_args + 1) * sizeof(char *));
823 data->num_out_args = 0;
825 bzero(out_args, (max_args + 1) * sizeof(char *));
827 for (i = 0; i < data->num_in_args; i++) {
828 nas_arg = data->input_args[i];
830 /* always pass these pairs through unchanged */
831 if (match_attrs(nas_arg, "service=") ||
832 match_attrs(nas_arg, "protocol=") ||
833 match_attrs(nas_arg, "cmd=")) {
835 if (debug & DEBUG_AUTHOR_FLAG) {
836 report(LOG_DEBUG, "nas:%s (passed thru)", nas_arg);
838 *outp++ = tac_strdup(nas_arg);
839 data->num_out_args++;
843 /* NAS AV pair is mandatory */
844 if (mandatory(nas_arg)) {
846 /* a). look for an exact attribute,value match in the daemon's
847 mandatory list. If found, add the AV pair to the output */
849 for (j = 0; j < cfg_cnt; j++) {
850 cfg_arg = cfg_args[j];
851 if (optional(cfg_arg))
854 if (STREQ(nas_arg, cfg_arg)) {
855 if (debug & DEBUG_AUTHOR_FLAG) {
856 report(LOG_DEBUG, "nas:%s, svr:%s -> add %s (a)",
857 nas_arg, cfg_arg, nas_arg);
859 *outp++ = tac_strdup(nas_arg);
860 data->num_out_args++;
865 /* b). If an exact match doesn't exist, look in the
866 daemon's optional list for the first attribute
867 match. If found, add the NAS AV pair to the output */
869 for (j = 0; j < cfg_cnt; j++) {
870 cfg_arg = cfg_args[j];
871 if (mandatory(cfg_arg))
874 if (match_attrs(nas_arg, cfg_arg)) {
875 if (debug & DEBUG_AUTHOR_FLAG) {
876 report(LOG_DEBUG, "nas:%s, svr:%s -> add %s (b)",
877 nas_arg, cfg_arg, nas_arg);
879 *outp++ = tac_strdup(nas_arg);
880 data->num_out_args++;
885 /* c). If no attribute match exists, deny the command if the
886 default is to deny */
888 if (deny_by_default) {
889 data->status = AUTHOR_STATUS_FAIL;
890 if (debug & DEBUG_AUTHOR_FLAG) {
891 report(LOG_DEBUG, "nas:%s svr:absent, default=deny -> denied (c)",
895 for (i = 0; i < data->num_out_args; i++)
900 data->num_out_args = 0;
901 data->output_args = NULL;
903 /* free the server arguments */
904 for(cfg_argp = cfg_args; *cfg_argp; cfg_argp++)
910 /* d). If the default is permit, add the NAS AV pair to
913 if (debug & DEBUG_AUTHOR_FLAG) {
915 "nas:%s, svr:absent, default=permit -> add %s (d)",
918 *outp++ = tac_strdup(nas_arg);
919 data->num_out_args++;
924 /* NAS AV pair is Optional */
926 /* e). look for an exact attribute,value match in the mandatory
927 list. If found, add DAEMON's AV pair to output */
929 for (j = 0; j < cfg_cnt; j++) {
930 cfg_arg = cfg_args[j];
931 if (optional(cfg_arg))
934 if (match_attrs(nas_arg, cfg_arg) &&
935 match_values(nas_arg, cfg_arg)) {
937 if (debug & DEBUG_AUTHOR_FLAG) {
938 report(LOG_DEBUG, "nas:%s svr:%s -> replace with %s (e)",
939 nas_arg, cfg_arg, cfg_arg);
941 *outp++ = tac_strdup(cfg_arg);
942 data->num_out_args++;
948 /* f). If not found, look for the first attribute match in
949 the mandatory list. If found, add DAEMONS's AV pair to
952 for (j = 0; j < cfg_cnt; j++) {
953 cfg_arg = cfg_args[j];
954 if (optional(cfg_arg))
957 if (match_attrs(nas_arg, cfg_arg)) {
958 if (debug & DEBUG_AUTHOR_FLAG) {
959 report(LOG_DEBUG, "nas:%s svr:%s -> replace with %s (f)",
960 nas_arg, cfg_arg, cfg_arg);
962 *outp++ = tac_strdup(cfg_arg);
963 data->num_out_args++;
969 /* g). If no mandatory match exists, look for an exact
970 attribute,value pair match among the daemon's optional AV
971 pairs. If found add the DAEMON's matching AV pair to the
975 for (j = 0; j < cfg_cnt; j++) {
976 cfg_arg = cfg_args[j];
977 if (!optional(cfg_arg))
980 if (match_attrs(nas_arg, cfg_arg) &&
981 match_values(nas_arg, cfg_arg)) {
982 if (debug & DEBUG_AUTHOR_FLAG) {
983 report(LOG_DEBUG, "nas:%s svr:%s -> replace with %s (g)",
984 nas_arg, cfg_arg, cfg_arg);
986 *outp++ = tac_strdup(cfg_arg);
987 data->num_out_args++;
993 /* h). If no exact match exists, locate the first
994 attribute match among the daemon's optional AV
995 pairs. If found add the DAEMON's matching AV pair to
998 for (j = 0; j < cfg_cnt; j++) {
999 cfg_arg = cfg_args[j];
1000 if (!optional(cfg_arg))
1003 if (match_attrs(nas_arg, cfg_arg)) {
1004 if (debug & DEBUG_AUTHOR_FLAG) {
1005 report(LOG_DEBUG, "nas:%s svr:%s -> replace with %s (h)",
1006 nas_arg, cfg_arg, cfg_arg);
1008 *outp++ = tac_strdup(cfg_arg);
1009 data->num_out_args++;
1016 /* i). If no match is found, delete the AV pair if default is
1019 if (deny_by_default) {
1020 if (debug & DEBUG_AUTHOR_FLAG) {
1021 report(LOG_DEBUG, "nas:%s svr:absent/deny -> delete %s (i)",
1028 /* j). If the default is permit add the NAS AV pair to the output */
1030 if (debug & DEBUG_AUTHOR_FLAG) {
1031 report(LOG_DEBUG, "nas:%s svr:absent/permit -> add %s (j)",
1034 *outp++ = tac_strdup(nas_arg);
1035 data->num_out_args++;
1043 /* k). After all AV pairs have been processed, for each mandatory
1044 DAEMON AV pair, if there is no attribute match already in the
1045 output list, add the AV pair (add only one AV pair for each
1046 mandatory attribute) */
1048 for (i = 0; i < cfg_cnt; i++) {
1049 cfg_arg = cfg_args[i];
1051 if (!mandatory(cfg_arg))
1054 for (j = 0; j < data->num_out_args; j++) {
1055 char *output_arg = out_args[j];
1057 if (match_attrs(cfg_arg, output_arg)) {
1062 /* Attr is required by daemon but not present in
1065 if (debug & DEBUG_AUTHOR_FLAG) {
1066 report(LOG_DEBUG, "nas:absent, server:%s -> add %s (k)",
1070 *outp++ = tac_strdup(cfg_arg);
1071 data->num_out_args++;
1077 /* If we replaced or deleted some pairs we must return the entire
1078 list we've constructed */
1081 if (debug & DEBUG_AUTHOR_FLAG) {
1082 report(LOG_DEBUG, "replaced %d args", replaced);
1084 data->status = AUTHOR_STATUS_PASS_REPL;
1085 data->output_args = out_args;
1087 /* free the server arguments */
1088 for(cfg_argp = cfg_args; *cfg_argp; cfg_argp++)
1095 /* We added something not on the original nas list, but didn't
1096 replace or delete anything. We should return only the
1101 if (debug & DEBUG_AUTHOR_FLAG)
1102 report(LOG_DEBUG, "added %d args", added);
1104 /* throw away output args which are just copies of the input args */
1105 for (i = 0; i < data->num_in_args; i++) {
1106 if (debug & DEBUG_AUTHOR_FLAG) {
1107 report(LOG_DEBUG, "out_args[%d] = %s input copy discarded",
1114 /* Now compact the new args added to the end of the array down
1118 for (i = data->num_in_args; i < data->num_out_args; i++) {
1119 if (out_args[j]) /* we goofed */
1120 report(LOG_ERR, "%s: out_args[%d] should be NULL",
1122 if (!out_args[i]) /* we goofed */
1123 report(LOG_ERR, "%s: out_args[%d] should not be NULL",
1126 if (debug & DEBUG_AUTHOR_FLAG) {
1127 report(LOG_DEBUG, "out_args[%d] = %s compacted to out_args[%d]",
1130 out_args[j++] = out_args[i];
1133 data->num_out_args = j;
1134 if (debug & DEBUG_AUTHOR_FLAG) {
1135 report(LOG_DEBUG, "%d output args", data->num_out_args);
1138 /* should/could do a realloc here but it won't matter */
1139 data->status = AUTHOR_STATUS_PASS_ADD;
1140 data->output_args = out_args;
1142 /* free the server arguments */
1143 for(cfg_argp = cfg_args; *cfg_argp; cfg_argp++)
1150 /* no additions or replacements. Input and output are
1151 identical. Don't need to return anything */
1153 if (debug & DEBUG_AUTHOR_FLAG) {
1154 report(LOG_DEBUG, "added %d", added);
1156 data->status = AUTHOR_STATUS_PASS_ADD;
1158 for (i = 0; i < data->num_out_args; i++) {
1164 /* Final sanity check */
1165 if (data->num_out_args != data->num_in_args) {
1166 data->status = AUTHOR_STATUS_ERROR;
1167 data->admin_msg = tac_strdup("Bad output arg cnt from do_author");
1168 report(LOG_ERR, "%s: Error %s", session.peer, data->admin_msg);
1170 /* free the server arguments */
1171 for(cfg_argp = cfg_args; *cfg_argp; cfg_argp++)
1178 data->num_out_args = 0;
1179 data->output_args = NULL;
1181 /* free the server arguments */
1182 for(cfg_argp = cfg_args; *cfg_argp; cfg_argp++)
1189 /* Return an integer indicating which kind of service is being
1192 Conveniently this integer is one of our node types. If the service
1193 is a command authorisation request, also return the command name in
1196 If this service is a ppp request, return the protocol name in
1199 If this service is not one of the standard, known ones, return its
1204 get_nas_svc(data, cmdname, protocol, svcname)
1205 struct author_data *data;
1206 char **cmdname, **protocol, **svcname;
1215 for (i = 0; i < data->num_in_args; i++) {
1216 nas_arg = data->input_args[i];
1218 if (STREQ(nas_arg, "service=shell")) {
1219 for (i = 0; i < data->num_in_args; i++) {
1220 nas_arg = data->input_args[i];
1221 if (strncmp(nas_arg, "cmd", strlen("cmd")) == 0) {
1222 /* A cmd=<nothing> means we are authorising exec startup */
1223 if ((int)strlen(nas_arg) <= 4)
1224 return (N_svc_exec);
1226 /* A non-null command means we are authorising a command */
1227 *cmdname = nas_arg + strlen("cmd") + 1;
1234 if (STREQ(nas_arg, "service=slip")) {
1235 return (N_svc_slip);
1237 if (STREQ(nas_arg, "service=arap")) {
1238 return (N_svc_arap);
1240 if (STREQ(nas_arg, "service=ppp")) {
1241 for (i = 0; i < data->num_in_args; i++) {
1242 nas_arg = data->input_args[i];
1243 if (strncmp(nas_arg, "protocol", strlen("protocol")) == 0) {
1244 *protocol = nas_arg + strlen("protocol") + 1;
1250 if (strncmp(nas_arg, "service=", strlen("service=")) ==0 ) {
1251 *svcname = nas_arg + strlen("service=");