/* * $Id: auth.c,v 1.9 2002/10/17 20:16:13 ljb Exp $ */ #include #include #include #include #include #include #include #include #ifdef HAVE_CRYPT_H #include #endif #include extern int verbose; #ifndef HAVE_CRYPT_H extern char *crypt (const char *, const char*); #endif /*JW: need to add support for RPSL comments within an object */ /* local yokel's */ static void maint_check (trace_t *tr, FILE *, int *, int *, trans_info_t *); static int determine_op_type (trace_t *tr, int *sockfd, FILE **fd_old, trans_info_t *ti, char *fname, int *num_trans, long *obj_pos); static enum AUTH_CODE perform_auth_check (trace_t *tr, int *, int, FILE *, long, FILE *, long, trans_info_t *, int *); static enum AUTH_CODE do_auth_check (trace_t *tr, char *, trans_info_t *); static FILE *get_db_object (trace_t *tr, int *num_trans, char *fname, int *sockfd, int obj_size, char *obj_type, char *obj_key, char *source, long *obj_pos); static enum AUTH_CODE auth_process (trace_t *tr, int op, int *sockfd, FILE *fd, long fpos, trans_info_t *ti, int *num_trans, char **mb_list, char **mb_exist_list); static enum AUTH_CODE mnt_by_exist (trace_t *tr, int *sockfd, trans_info_t *ti, char **mb_list, int *num_trans); static enum AUTH_CODE auth_ok (trace_t *tr, int op, int *sockfd, trans_info_t *ti, char *mntner, int *mntner_exists, int *num_trans); static int check_crypt_passwd (char *cleartxt, char *encrypted); static void update_trans_info (trace_t *tr, enum AUTH_CODE ret_code, trans_info_t *ti, int op, FILE *fd_new, long fpos, FILE *fd_old, long old_obj_pos); static enum AUTH_CODE mntner_mblist_check (trace_t *tr, int op, int *sockfd, trans_info_t *ti, int *num_trans, char **mb_list, char **mb_exist_list); /* String array's for debug output */ char *str_op[] = {"DEL", "ADD", "REPLACE"}; char *str_res[] = {"AUTH_FAIL_C", "AUTH_PASS_C", "OTHER_FAIL_C", "MNT_NO_EXIST_C", "DEL_NO_EXIST_C", "NOOP_C"}; /* do_auth_check () regex */ static char auth_val[] = "^[ \t]*([^ \t\n]+)[ \t]*([^ \t\n]+)?[ \t]*$"; static regex_t authre; /* Global object lookup structure * Briefly, our transaction file may have multiple * updates and so it may have the latest object * instance rather than IRRd. This linked list will keep * track of object keys and file pointer to object starts in * the transaction file (ie, the output file this routine generates). */ lookup_info_t gstart; /* Used by get_db_object(). Easier to decalare * global to this file as get_db_object() is nested * fairly deeply and frequently. */ static char *IRRd_HOST; static int IRRd_PORT; static char *SUPER_PASSWD; int auth_check (trace_t *tr, char *infname, char *outfname, char *irrd_host, int irrd_port, char *super_passwd) { int num_trans = 0, sockfd; long fin_offset, fout_offset; char buf[MAXLINE]; FILE *fin, *fout; trans_info_t ti; IRRd_HOST = irrd_host; IRRd_PORT = irrd_port; SUPER_PASSWD = super_passwd; /* open the input and output files */ if ((fin = myfopen (tr, infname, "r", "auth_check () input file"))== NULL) return(-1); if ((fout = myfopen (tr, outfname, "w+", "auth_check () output file")) == NULL) { fclose(fin); return (-1); } /* initialize the transaction list lookup struct */ gstart.first = gstart.last = NULL; /* regex for do_auth_check () */ regcomp(&authre, auth_val, (REG_EXTENDED|REG_ICASE)); while (fgets (buf, MAXLINE - 1, fin) != NULL) { if (strncmp (HDR_START, buf, strlen (HDR_START) - 1)) continue; if (parse_header (tr, fin, &fin_offset, &ti)) trace (NORM, tr, "ERROR: auth_check () parse_header error!\n"); /* JW need to take some logical course of action later: * return 0; illegal hdr field found or EOF * (ie, no object after hdr): want to construct legal hdr * with "OTHERFAIL" initialized */ /* perform the actual maintainer checking */ if (!ti.syntax_errors) maint_check (tr, fin, &sockfd, &num_trans, &ti); /* write the header info for this trans object */ print_hdr_struct (fout, &ti); /* copy the current object after the header info */ fout_offset = ftell (fout); write_trans_obj (tr, fin, fin_offset, fout, MAX_IRRD_OBJ_SIZE, update_has_errors (&ti)); /* print a blank line seperator between objects */ if (EOF == fputs ("\n", fout)) trace (ERROR, tr, "ERROR: auth () writing object to file (%s)\n", strerror (errno)); /* update the transaction lookup list (see gstart) */ trans_list_update (tr, &gstart, &ti, fout, fout_offset); free_ti_mem (&ti); } if (num_trans) { end_irrd_session (tr, sockfd); close_connection (sockfd); close (sockfd); } /* return trans list memory */ free_trans_list (tr, &gstart); fflush (fout); fclose (fout); fclose (fin); return (1); } /* Contol the process of determining if the user has authorization to update * the object. The function determines the operation (ie ADD, DEL, REPLACE), * checks for update authorization and set's the notify/forward addr's for * notify. * * Return: * (via the 'ti' struct) * -notify/forward addr's * -file with old object (for DEL and REPLACE op's) * -authorization outcome */ void maint_check (trace_t *tr, FILE *fd_new, int *sockfd, int *num_trans, trans_info_t *ti) { int op; enum AUTH_CODE ret_code; FILE *fd_old = NULL; long fpos, old_obj_pos; char old_fname[256]; /* save obj file pos to restore on exit */ fpos = ftell (fd_new); /* determine the operation type, ie, DEL, ADD, or REPLACE */ if ((op = determine_op_type (tr, sockfd, &fd_old, ti, old_fname, num_trans, &old_obj_pos)) < 0) return; if (*sockfd < 0) { if (fd_old != NULL) { fclose (fd_old); remove (old_fname); } ti->otherfail = strdup ("IRRd connection refused. Abort transaction!"); return; } /* Perform the authorization check. fd_new points to the DEL, ADD, * or REPLACE object in the input file. fd_old has a copy * of the object to be DEL'd or REPLACE'd (for ADD fd_old is NULL). */ ret_code = perform_auth_check (tr, sockfd, op, fd_old, old_obj_pos, fd_new, fpos, ti, num_trans); /* fold the transaction outcome/ret_code info into the object header struct */ update_trans_info (tr, ret_code, ti, op, fd_new, fpos, fd_old, old_obj_pos); /* Notify will get: a file name (ie, old object came from * IRRd/DB) or a file pos (ie, a number; object came from our * output/transaction file) for REPLACE and DEL operations. */ if (fd_old != NULL) { if (old_obj_pos == 0L) { ti->old_obj_fname = strdup (old_fname); fclose (fd_old); } else { sprintf (old_fname, "%ld", old_obj_pos); ti->old_obj_fname = strdup (old_fname); } } /* restore fpos to the begining of object */ fseek (fd_new, fpos, SEEK_SET); } /* * Determine the operation type, ie, ADD, DEL, or REPLACE. * If a delete field is provided by the user the OP: field * value will be set to DEL. Otherwise the OP: field will * be empty. */ int determine_op_type (trace_t *tr, int *sockfd, FILE **fd_old, trans_info_t *ti, char *fname, int *num_trans, long *obj_pos) { int op = -1; *fd_old = get_db_object (tr, num_trans, fname, sockfd, FULL_OBJECT, ti->obj_type, ti->obj_key, ti->source, obj_pos); /* ADD or REPLACE */ if (ti->op == NULL) { if (*fd_old == NULL) { op = iADD; set_op_type (ti->op, ADD_OP); } else { op = iREPLACE; set_op_type (ti->op, REPLACE_OP); } } else if (!strcmp (ti->op, DEL_OP)) op = iDEL; else if (ti->op != NULL) fprintf (stderr, "ERROR: determine_op_type () unrecognized op (%s)...\n", ti->op); /*fprintf (dfile, "return determine_op_type () (%d)\n", op);*/ return op; } /* Control the process of determining authorization. The function is * passed an 'op' (ie, DEL, ADD, REPLACE) and 1 or 2 non-empty object * files; an authorization code is returned. On return the mnt_nfy * list (AUTH_PASS_C) or the upd_to list (AUTH_FAIL_C) will be complete * (ie, from all referenced maintainers). It is the calling routines * onus to remove mnt_nfy/upd_to addr's based on the return code. * * Return: * All legal 'enum AUTH_CODE' return codes are possible (see auth.h) * The 'ti' struct 'ti->forward' and 'ti->notify' may be updated. */ enum AUTH_CODE perform_auth_check (trace_t *tr, int *sockfd, int op, FILE *fd_old, long fpos_old, FILE *fd_new, long fpos_new, trans_info_t *ti, int *num_trans) { enum AUTH_CODE ret_code = AUTH_FAIL_C; char *mb_list = NULL, *mb_list2 = NULL, *mb_exist_list = NULL; /*fprintf (dfile, "\n---Enter perform_auth_check () op-(%s)...\n", str_op[op]);*/ if (op != iADD) { if (fd_old == NULL) return DEL_NO_EXIST_C; if (op == iREPLACE && noop_check (tr, fd_old, fpos_old, fd_new, fpos_new)) return NOOP_C; /* Determine authorization */ if ((ret_code = auth_process (tr, iDEL, sockfd, fd_old, fpos_old, ti, num_trans, &mb_list, &mb_exist_list)) != AUTH_PASS_C) goto FREE_MEM; } if (op != iDEL) { if (op == iADD && /* Determine authorization */ (ret_code = auth_process (tr, iADD, sockfd, fd_new, fpos_new, ti, num_trans, &mb_list2, &mb_exist_list)) != AUTH_PASS_C) goto FREE_MEM; /* Next section makes sure all new maintainer references exist */ /* Remove possible self-mntner reference from new maint submission's */ if (op == iADD && mb_list2 != NULL && !strcmp (ti->obj_type, "mntner")) { /*fprintf (dfile, "remove possible maintainer reference from maint (%s) list (%s)\n", ti->obj_key, mb_list2);*/ mb_list2 = filter_duplicates (tr, mb_list2, ti->obj_key); } /* For speed up, remove maintainers found in authorization determination */ if (op == iREPLACE && ti->mnt_by[0] != '\0') { mb_list2 = strdup (ti->mnt_by); /* filter out all mntner ref's in mb_list2 that are in mb_exist_list */ mb_list2 = filter_duplicates (tr, mb_list2, mb_exist_list); } /* Maintainer references for new objects must exist */ if ((ret_code = mnt_by_exist (tr, sockfd, ti, &mb_list2, num_trans)) != AUTH_PASS_C) goto FREE_MEM; mb_list = filter_duplicates (tr, mb_list, mb_list2); } /* For remaining members of mb_list (ie, DEL and REPLACE), get * the maintainer and pick off "mnt-nfy" fields, add the new email * addrs to ti->notify */ if (mb_list != NULL) { mnt_by_exist (tr, sockfd, ti, &mb_list, num_trans); ti->maint_no_exist = free_mem (ti->maint_no_exist); } FREE_MEM: free_mem (mb_list); free_mem (mb_list2); free_mem (mb_exist_list); /*fprintf (dfile, "perform_auth_check () returns-(%d)\n---\n\n", ret_code);*/ return ret_code; } /* This routine collects all maintainer references collected from an ADD or REPLACE * object and check's if they exist. For each referenced maintainer the * mnt-nfy's are collected in ti->notify. * * Return: * AUTH_PASS_C if all mb_list members exist and ti->notify is appended * with mnt_nfy's from the referenced maintainer's. * * MNT_NO_EXIST_C if one or more of the mb_list members do not exist * and are returned in ti->maint_no_exist. */ enum AUTH_CODE mnt_by_exist (trace_t *tr, int *sockfd, trans_info_t *ti, char **mb_list, int *num_trans) { char *p, *q, c; char fname[256], *ret_list = NULL, *mnt_nfy_list; long obj_pos; FILE *fd; /* if (*mb_list == NULL) fprintf (dfile, "enter mb_by_exist () mb_list is NULL\n"); else fprintf (dfile, "enter mnt_by_exist (%s)\n", *mb_list); */ p = q = *mb_list; while (find_token (&p, &q) > 0) { c = *q; *q = '\0'; /*fprintf (dfile, "mnt_by_exist () see if (%s) exists\n", p);*/ if ((fd = get_db_object (tr, num_trans, fname, sockfd, SHORT_OBJECT, "mntner", p, ti->source, &obj_pos)) == NULL) { ret_list = myconcat (ret_list, p); /*fprintf (dfile, "mnt_by_exist () (%s) does not exist; aggregate list (%s)\n", p, ret_list);*/ } else { if (ret_list == NULL) { mnt_nfy_list = cull_attribute (tr, fd, obj_pos, (u_int) MNT_NFY_ATTR); ti->notify = myconcat (ti->notify, mnt_nfy_list); /*if (mnt_nfy_list != NULL) fprintf (dfile,"mnt_by_exist () (%s) exist's; adding notify (%s)\n", p, mnt_nfy_list); if (ti->notify != NULL) fprintf (dfile,"mnt_by_exist () (%s) aggregate notify list\n", ti->notify);*/ free_mem (mnt_nfy_list); } /* don't delete objects in our output file */ if (obj_pos == 0L) { fclose (fd); remove (fname); } } *q = c; } if (ret_list != NULL) { ti->maint_no_exist = myconcat (ti->maint_no_exist, ret_list); /*fprintf (dfile, " mnt_by_exist ret_code (MNT_NO_EXIST_C)\n");*/ return MNT_NO_EXIST_C; } /*fprintf (dfile, " mnt_by_exist ret_code (AUTH_PASS_C)\n");*/ *mb_list = free_mem (*mb_list); return AUTH_PASS_C; } /* Control the process of determining if one of the maintainer's referenced * in this object passes authorization. * * Return: * one of the 'enum AUTH_CODE's (see irrauth.h) */ enum AUTH_CODE auth_process (trace_t *tr, int op, int *sockfd, FILE *fd, long fpos, trans_info_t *ti, int *num_trans, char **mb_list, char **mb_exist_list) { enum AUTH_CODE auth_ret; if (op == iADD) { if (ti->mnt_by != NULL) *mb_list = strdup (ti->mnt_by); else *mb_list = NULL; } else *mb_list = cull_attribute (tr, fd, fpos, (u_int) MNT_BY_ATTR); if (ti->override) { if (check_crypt_passwd (ti->override, SUPER_PASSWD)) return AUTH_PASS_C; else { trace (NORM, tr, "** Auth failure -- override password did not match\n"); return BAD_OVERRIDE_C; } } /* bounce out maintainer add/delete requests unless you * know the super user override password */ if (op == iADD && !strcmp (ti->obj_type, "mntner")) return NEW_MNT_ERROR_C; if (op == iDEL && !strcmp (ti->obj_type, "mntner") && !strcmp(ti->op, DEL_OP) && *mb_list != NULL) { auth_ret = mntner_mblist_check (tr, op, sockfd, ti, num_trans, mb_list, mb_exist_list); if (auth_ret == AUTH_PASS_C) return DEL_MNT_ERROR_C; else return auth_ret; } if (*mb_list == NULL) { if (op == iADD) /* new submissions must have a valid maint */ return AUTH_FAIL_C; else /* if there are junk objects in the DB we must go along :( */ return AUTH_PASS_C; } /* see if one of the referenced mntner's pass authorization */ return mntner_mblist_check (tr, op, sockfd, ti, num_trans, mb_list, mb_exist_list); } /* Given a maintainer reference (*mntner), this function passes the * auth: lines from the maintainer to do_auth_check () for authorization. * mnt_nfy and upd_to fields are also collected in ti->notify and ti->forward. * * Return: * AUTH_PASS_C if authorisation passes. The mny_nfy references from * all the maintainers it took to establish authorisation (ie, some * mnt_nfy ref's may still need to be collected) are appended to 'ti->notify'. * * AUTH_FAIL_C if authorisation could not be obtained. In this case * ti->forward will have all upd_to: ref's. * * MNT_NO_EXIST_C if the referenced maintainer does not exist. */ enum AUTH_CODE auth_ok (trace_t *tr, int op, int *sockfd, trans_info_t *ti, char *mntner, int *mntner_exists, int *num_trans) { int in_attr = 0, skip = 0; long obj_pos, fpos; FILE *fd; enum AUTH_CODE ret_code = AUTH_FAIL_C; char buf[MAXLINE], fname[256], *q; if ((fd = get_db_object (tr, num_trans, fname, sockfd, SHORT_OBJECT, "mntner", mntner, ti->source, &obj_pos)) == NULL) { trace (NORM, tr, "Maintainer (%s) does not exist. Authorization fails!\n", mntner); *mntner_exists = 0; if (op == iADD) return MNT_NO_EXIST_C; else return AUTH_FAIL_C; } else { /*fprintf (dfile, "auth_ok () say's (%s) exists, so gather notify's/auth: lines...\n", mntner);*/ *mntner_exists = 1; /* save the fpos to restore on exit */ fpos = ftell (fd); fseek (fd, obj_pos, SEEK_SET); while (fgets (buf, MAXLINE - 1, fd) != NULL && buf[0] != '\n') { if ((in_attr = find_attr (tr, buf, in_attr, (u_int) (AUTH_ATTR|MNT_NFY_ATTR|UPD_TO_ATTR), &q))) { /*fprintf (dfile, "auth_ok () find_attr: (%s)\n", q);*/ if (in_attr == AUTH_ATTR) { if (!skip && (ret_code = do_auth_check (tr, q, ti)) == AUTH_PASS_C) skip = 1; } else if (in_attr == MNT_NFY_ATTR) ti->notify = myconcat (ti->notify, q); else ti->forward = myconcat (ti->forward, q); } } /* JW later it would be better to keep file around till the * end for possible reuse */ /* ie, don't close and remove our output file */ if (obj_pos == 0L) { fclose (fd); remove (fname); } else fseek (fd, fpos, SEEK_SET); } /* fprintf (dfile, "auth_ok () ret_code-(%d)\n", ret_code);*/ return ret_code; } /* Place a copy of the referenced DB object into file 'fname' should the * DB object exist. The object can come from our transaction output file * (latest copy) or from IRRd. 'obj_size' can be FULL_OBJECT or SHORT_OBJECT. * SHORT_OJBECT will return only auth, mnt_nfy, mb_by, and notify fields. * * Return: * Stream file pointer to the object if it was retrieved successfully * and the name of the file in 'fname'. * NULL otherwise. */ FILE *get_db_object (trace_t *tr, int *num_trans, char *fname, int *sockfd, int obj_size, char *obj_type, char *obj_key, char *source, long *obj_pos) { obj_lookup_t *obj; /*fprintf (dfile, "\n---\nenter get_db_object () key-(%s)\n", obj_key);*/ /* see if the object is in our trans obj list first */ if ((obj = find_trans_object (tr, &gstart, source, obj_type, obj_key)) != NULL) { /* object has been deleted */ if (obj->state == 0) return NULL; else { /*fprintf (dfile, "get_db_object () found trans obj (%s) fpos (%ld)\n", obj_key, obj->fpos);*/ *obj_pos = obj->fpos; return obj->fd; } } /* The object was not in our transaction list, get it from IRRd. */ *obj_pos = 0L; strcpy (fname, tmpfntmpl); return IRRd_fetch_obj (tr, fname, num_trans, sockfd, obj_size, obj_type, obj_key, source, MAX_IRRD_OBJ_SIZE, IRRd_HOST, IRRd_PORT); } enum AUTH_CODE do_auth_check (trace_t *tr, char *auth_line, trans_info_t *ti) { char *p, *q; int auth_tokens; regex_t re; regmatch_t authrm[3]; enum AUTH_CODE ret_code; /*fprintf (dfile, "do_auth_check () found an auth token-(%s)\n", auth_line);*/ /* See if the line is a well-formed 'auth: ...' attr */ if (0 != regexec (&authre, auth_line, 3, authrm, 0)) return AUTH_FAIL_C; /* first token in 'auth:' attr */ p = auth_line + authrm[1].rm_so; *(auth_line + authrm[1].rm_eo) = 0; /* see if there second token */ if (authrm[2].rm_so != -1) auth_tokens = 2; else auth_tokens = 1; /* PGPKEY-XXXXXXXX auth check */ if (!strncasecmp ("PGPKEY-", p, 7)) { if (auth_tokens == 1 && ti->pgp_key != NULL && /* the PGP key from PGP does not have the 'PGPKEY-' prefix * so we compare the hexid part of the PGPKEY-(xxxxxxxx) only * to the hexid of from the PGPV output */ !strncasecmp (ti->pgp_key, p + 7, 8)) return AUTH_PASS_C; return AUTH_FAIL_C; } #ifdef ALLOW_AUTH_NONE /* NONE auth check - this is deprecated */ if (!strncasecmp ("NONE", p, 4)) { /*fprintf (dfile, "do_auth_check () auth NONE!\n");*/ if (auth_tokens == 1) return AUTH_PASS_C; return AUTH_FAIL_C; } #endif /* This is bad if this test is true */ if (auth_tokens == 1) return AUTH_FAIL_C; /* second token in 'auth:' attr */ q = auth_line + authrm[2].rm_so; *(auth_line + authrm[2].rm_eo) = 0; /* assume the worst :) */ ret_code = AUTH_FAIL_C; /* MAIL-FROM auth check */ if (!strncasecmp ("MAIL-FROM", p, 9) && ti->sender_addrs != NULL) { /*fprintf (dfile, "do_auth_check () from-(%s) auth from-(%s)\n", ti->sender_addrs, p);*/ if (!regcomp (&re, q, REG_EXTENDED|REG_NOSUB|REG_ICASE)) { if (!regexec(&re, ti->sender_addrs, (size_t) 0, NULL, 0)) ret_code = AUTH_PASS_C; regfree (&re); } return ret_code; } /* CRYPT-PW auth check */ if (!strncasecmp ("CRYPT-PW", p, 8) && ti->crypt_pw != NULL) { /*fprintf (dfile, "do_auth_check () cleartxt passwd-(%s) crypt passwd-(%s)\n",ti->crypt_pw, p);*/ if (check_crypt_passwd (ti->crypt_pw, q)) return AUTH_PASS_C; return AUTH_FAIL_C; } /* We are in bad shape if we get here */ return AUTH_FAIL_C; } /* Determine if the cleartxt password matches the encrypted password. * * Return: * 1 if cleartxt password is a match * 0 otherwise */ int check_crypt_passwd (char *cleartxt, char *encrypted) { if (cleartxt == NULL || encrypted == NULL) return 0; return !strcmp ((char *) crypt (cleartxt, encrypted), encrypted); } /* Fold the transaction outcome into the 'ti' struct. The 'ti' struct * info will be translated into object header text in the output file for * notify. This function also performs the final notify/forward address * processing (which is dependent on the transaction outcome/'ret_code'). * * Return: * void */ void update_trans_info (trace_t *tr, enum AUTH_CODE ret_code, trans_info_t *ti, int op, FILE *fd_new, long fpos, FILE *fd_old, long old_obj_pos) { char *obj_notifies; if (ret_code == AUTH_PASS_C) { /*fprintf (dfile, ">>>>>>>enter ret_code AUTH_PASS_C process...\n");*/ if (op != iDEL) { /* JW can take out of this works && (obj_notifies = cull_attribute (dfile, fd_new, fpos, (u_int) (NOTIFY_ATTR|MNT_NFY_ATTR))) != NULL) { ti->notify = myconcat (ti->notify, obj_notifies); free_mem (obj_notifies); */ ti->notify = myconcat (ti->notify, ti->check_notify); ti->notify = myconcat (ti->notify, ti->check_mnt_nfy); } /* fprintf (dfile, "checking old/del object for notify's\n");*/ if (fd_old != NULL && (obj_notifies = cull_attribute (tr, fd_old, old_obj_pos, (u_int) NOTIFY_ATTR)) != NULL) { ti->notify = myconcat (ti->notify, obj_notifies); free_mem (obj_notifies); } /*if (ti->notify != NULL) fprintf (dfile, "ret_code AUTH_PASS_C notify list (%s)\n", ti->notify);*/ } else if (ret_code == DEL_NO_EXIST_C) ti->del_no_exist = 1; else if (ret_code == NOOP_C) { set_op_type (ti->op, NOOP_OP); } else if (ret_code == AUTH_FAIL_C) { ti->authfail = 1; /* Don't notify upd-to's on ADD operations */ if (op == iADD) ti->forward = free_mem (ti->forward); } else if (ret_code == NEW_MNT_ERROR_C) ti->new_mnt_error = 1; else if (ret_code == DEL_MNT_ERROR_C) ti->del_mnt_error = 1; else if (ret_code == BAD_OVERRIDE_C) ti->bad_override = 1; if (CLEAR_NOTIFY & ret_code) ti->notify = free_mem (ti->notify); if (CLEAR_FORWARD & ret_code) ti->forward = free_mem (ti->forward); /* Bookeeping: remove trans fields not needed by notify */ if (ret_code != BAD_OVERRIDE_C) ti->override = free_mem (ti->override); ti->check_notify = free_mem (ti->check_notify); ti->check_mnt_nfy = free_mem (ti->check_mnt_nfy); } /* Given a mnt_by: list from an object, control the process of * determining if any of the referenced maintainers pass authorization. * * Return: * One of the legal 'enum AUTH_CODE's * Function will also remove the mntner references from 'mb_list' * that were checked in the process of determining authorization. * Remaining members of 'mb_list' will need to be checked for mnt_nfy * references (when authorization passes). If authorization fails, * all referenced 'upd_to:'s will have been gathered in 'ti->forward'. */ enum AUTH_CODE mntner_mblist_check (trace_t *tr, int op, int *sockfd, trans_info_t *ti, int *num_trans, char **mb_list, char **mb_exist_list) { char *p, *q, c; int mntner_exists; enum AUTH_CODE ret_code = AUTH_FAIL_C; /* see if any of the referenced maintainers pass auth */ p = q = *mb_list; while (find_token (&p, &q) > 0) { c = *q; *q = '\0'; /*fprintf (dfile, "auth_process () check maint-(%s)\n", p);*/ ret_code = auth_ok (tr, op, sockfd, ti, p, &mntner_exists, num_trans); /*fprintf (dfile, "auth_process () auth_ok ret_code-(%d)\n", ret_code);*/ /* Save mntner's that exist to avoid expensive duplicate lookups */ if (mntner_exists) *mb_exist_list = myconcat (*mb_exist_list, p); if (ret_code == MNT_NO_EXIST_C) { if (op == iADD) { ti->maint_no_exist = myconcat (ti->maint_no_exist, p); break; } ret_code = AUTH_FAIL_C; } *q = c; /* trim down the mb_list for later gathering of mnt_nfy's */ if (ret_code == AUTH_PASS_C) { if (find_token (&p, &q) > 0) q = strdup (p); else q = NULL; free_mem (*mb_list); *mb_list = q; break; } } return ret_code; }