int asnum_syntax (char *asstr, parse_info_t *obj) { u_long val; char *endptr = NULL; char *asval; errno = 0; /* To distinguish success/failure after call */ asval = asstr + 2; /* skip AS part of string */ val = strtoul(asval, &endptr, 10); /* Check for various possible errors */ if ((errno == ERANGE && val == ULONG_MAX) || (errno != 0 && val == 0)) { error_msg_queue (obj, "AS number contains out-of-range value\n", ERROR_MSG); return 0; } /* check for 64 bit architectures */ if (sizeof (uint) != sizeof (u_long)) { if (val > UINT_MAX) { error_msg_queue (obj, "AS number contains out-of-range value\n", ERROR_MSG); return 0; /* exceeds max 32-bit uint */ } } return 1; }
int rpsl_word_check (parse_info_t *pi, char *rp_name, predef_t *p, int show_emsg, char *parm) { char * t = parm; char ebuf[2048]; fprintf(dfile, "rpsl_word_check() arg=(%s)\n", parm); if( !isalpha((int)*t) ) { /* check first letter */ if(show_emsg) { snprintf(ebuf, 2048, "Invalid rpsl_word: %s must start with a letter", parm); error_msg_queue (pi, ebuf, ERROR_MSG); } return 1; } if ( !isalpha((int)*(t+strlen(t)-1) ) && !isdigit((int)*(t+strlen(t)-1) ) ) { /* check last letter, maybe save us */ if(show_emsg) { snprintf(ebuf, 2048, "Invalid rpsl_word: %s must end in a letter or digit", parm); error_msg_queue (pi, ebuf, ERROR_MSG); } return 1; /* from going through whole string */ } while(*++t) { if(!isalpha((int)*t) && !isdigit((int)*t) && *t != '-' && *t != '_' ) { if(show_emsg) { sprintf(ebuf, "Invalid rpsl_word: cannot contain character %c", *t); error_msg_queue (pi, ebuf, ERROR_MSG); } return 1; } } return 0; }
void name_syntax (parse_info_t *obj, char *hdl) { char *p, *q, *r = NULL, c; int i; p = q = hdl; for (i = 0; irrcheck_find_token (&p, &q) > 0; i++, *q = c) { c = *q; *q = '\0'; r = NULL; if (verbose) fprintf (dfile, "JW: field[%d]-(%s)\n", i, p); /* email names not allowed */ if (strchr (p, '@') != NULL) error_msg_queue (obj, "Syntax error. Looks like an email address", ERROR_MSG); /* check the basic structure and legal characters */ else if (regexec(&re[RE_NAME], p, (size_t) 0, NULL, 0)) { error_msg_queue (obj, "Syntax error in person name. Non-alphanumeric or other formating error.", ERROR_MSG); } /* check for abbreviation on first and last name */ else { r = p + strlen (p) - 1; if (i == 0 && *r == '.') error_msg_queue (obj, "Abbreviated first names not allowed", ERROR_MSG); } } if (r != NULL && *r == '.') error_msg_queue (obj, "Abbreviated last names not allowed", ERROR_MSG); /* legal names must have at least two components */ if (i < 2) error_msg_queue (obj, "Names must have at least two components or bad handle", ERROR_MSG); }
/* Given an inetnum address range (ie, inetnum: a1 - a2 or a1 > a2) * determine if a1 is greater than a1. * * Return: * 1 if a1 is numerically <= a2 (ie, no errors) * 0 if a1 is numerically greater than a2 (ie, an error). */ int inetnum_syntax (parse_info_t *obj, char *prefix1, char *prefix2) { u_char dst1[4], dst2[4]; u_int val1, val2; int i; if (irrd_inet_pton (AF_INET, prefix1, dst1) <= 0) { error_msg_queue (obj, "Malformed address in start of range", ERROR_MSG); return 0; } if (irrd_inet_pton (AF_INET, prefix2, dst2) <= 0) { error_msg_queue (obj, "Malformed address in end of range", ERROR_MSG); return 0; } val1 = val2 = 0; for (i = 0; i < 4; i++) { val1 |= dst1[i] << (24 - (i * 8)); val2 |= dst2[i] << (24 - (i * 8)); } if (val1 > val2) { error_msg_queue (obj, "Invalid address range", ERROR_MSG); return 0; } return 1; }
/* * ac - admin-c * ph - person * ro - role * ah - author * tc - tech-c * zc - zone-c */ void hdl_syntax (parse_info_t *obj, char *hdl) { char *tok_s, *p, *q; p = q = hdl; if (irrcheck_find_token (&p, &q) > 0) { if (verbose) fprintf (dfile, "JW: enter hdl_syntax(): %s %s\n", attr_name[obj->curr_attr], hdl); tok_s = p; /* see if we have a nic-hdl, illegal for role and person objs */ if (irrcheck_find_token (&p, &q) < 0) { if (is_nichdl (tok_s)) { if (obj->curr_attr == F_RO || obj->curr_attr == F_PN) error_msg_queue (obj, "Handles not allowed for \"person\" and \"role\" objects", ERROR_MSG); return; /* nic-hdl's legal for admin-c, tech-c, zone-c, author */ } } /* It's not a nic handle, so check for legal name syntax */ name_syntax (obj, hdl); } else /* should never get here */ error_msg_queue (obj, "Empty attribute removed", EMPTY_ATTR_MSG); }
int route_set_name_check (parse_info_t *pi, char *rp_name, predef_t *p, int show_emsg, char *parm) { /* parm is string to be checked */ char * t = parm; char ebuf[2048]; fprintf(dfile, "route_set_name_check() arg=(%s)\n", parm); if(strlen(parm) > 3) { if( *t == 'r' && *(t+1) == 't' && *(t+2) == '-') return(rpsl_word_check(pi, rp_name, p, show_emsg, (t+3))); else { if(show_emsg) { snprintf(ebuf, 2048, "Invalid route-set name: %s", parm); error_msg_queue (pi, ebuf, ERROR_MSG); } return 1; } } if(show_emsg) { snprintf(ebuf, 2048, "Invalid route-set name: %s", parm); error_msg_queue (pi, ebuf, ERROR_MSG); } return 1; }
int email_check (parse_info_t *pi, char *rp_name, predef_t *p, int show_emsg, char *email_addr) { char *q; char ebuf[2048]; if ((q = strchr (email_addr, '@')) == NULL) { if (show_emsg) { snprintf (ebuf, 2048, "Missing '@' in email address for attribute \"%s\"", rp_name); error_msg_queue (pi, ebuf, ERROR_MSG); } return 1; } if (strchr (q + 1, '@') != NULL) { if (show_emsg) { snprintf (ebuf, 2048, "Multiple '@'s found in email address for attribute \"%s\"", rp_name); error_msg_queue (pi, ebuf, ERROR_MSG); } return 1; } if (regexec (&re[RE_EMAIL3], email_addr, (size_t) 0, NULL, 0) || (regexec (&re[RE_EMAIL1], email_addr, (size_t) 0, NULL, 0) && regexec (&re[RE_EMAIL2], email_addr, (size_t) 0, NULL, 0))) { if (show_emsg) { snprintf (ebuf, 2048, "Malformed RFC822 email address for attribute \"%s\"", rp_name); error_msg_queue (pi, ebuf, ERROR_MSG); } return 1; } return 0; }
/* Canonicalize and check for errors a time interval value. * * prescibed syntax: * 'dddd hh:mm:ss eg, '0001 01:00:00' * * 'dddd' are the day's, 'hh' are hours, 'mm' are minutes and 'ss' are seconds. * Function checks for 'hh' < 24, 'mm' and 'ss' < 60. Function will attempt * to fix good values by adding or removing leading 0's as necessry. * * Input: * -data struct to allow error messages to be created (obj) * -days value (days) * -hours value (hours) * -minutes value (mins) * -seconds value (secs) * * Return: * -a canonicalized time interval if no errors were found * -NULL otherwise */ char *time_interval_syntax (parse_info_t *obj, char *days, char *hours, char *mins, char *secs) { int j; char buf[16], d[5], h[3], m[3], s[3]; /* days: '0000' */ d[0] = '\0'; ti_check (obj, 4, "Time interval (days) too long. " "Must be exactly 4 digits. eg, '0010'", days, d); /* hours: '00' and < 24 */ h[0] = '\0'; sscanf (hours, "%d", &j); if (j > 23) error_msg_queue (obj, "Time inverval (hours) to large > 23", ERROR_MSG); else ti_check (obj, 2, "Time interval (hours) too long. " "Must be exactly 2 digits. eg, '01'", hours, h); /* minutes: '00' and < 60 */ m[0] = '\0'; sscanf (mins, "%d", &j); if (j > 59) error_msg_queue (obj, "Time inverval (minutes) to large > 59", ERROR_MSG); else ti_check (obj, 2, "Time interval (minutes) too long. " "Must be exactly 2 digits. eg, '30'", mins, m); /* seconds: '00' and < 60 */ s[0] = '\0'; sscanf (secs, "%d", &j); if (j > 59) error_msg_queue (obj, "Time inverval (seconds) to large > 59", ERROR_MSG); else ti_check (obj, 2, "Time interval (seconds) too long. " "Must be exactly 2 digits. eg, '45'", secs, s); /* mal-formed time interval */ if (*d == '\0' || *h == '\0' || *m == '\0' || *s == '\0') return NULL; /* good time interval */ sprintf (buf, "%s %s:%s:%s", d, h, m, s); /* clean up */ free (days); free (hours); free (mins); free (secs); return strdup (buf); }
/* * so - source */ void source_syntax (char *source_name, parse_info_t *obj) { source_t *src; extern config_info_t ci; if ((src = is_sourcedb (source_name, ci.srcs)) != NULL) { if (!src->authoritative) error_msg_queue (obj, "Non-authoritative database", ERROR_MSG); } else error_msg_queue (obj, "Unknown database", ERROR_MSG); }
/* Return * * 1 if type check passes * 0 if there is a arg type mismatch */ int arg_type_check (parse_info_t *pi, char *rp_name, type_t *t, int show_emsg, enum ARG_CONTEXT context, char **arg) { char ebuf[2048]; /* check for non-list input to list arg and vice-versa */ if (t->list) { /* if (**arg != '{') { if (show_emsg) { snprintf (ebuf, 2048, "RP attribute \"%s\" list attribute expected", rp_name); error_msg_queue (pi, ebuf, ERROR_MSG); } return 0; } */ return 1; } else if (**arg == '{' && context == NON_LIST_TYPE) { if (show_emsg) { snprintf (ebuf, 2048, "RP attribute \"%s\" non-list argument expected", rp_name); error_msg_queue (pi, ebuf, ERROR_MSG); } return 0; } return 1; }
/* Return a time interval component adding or removing leading 0's as * necessary. * * Function will return the time value component in (outs) if no (ins) * can be represented in a field of (width) characters. Otherwise * (outs) is not changed and an error message will be registered. * * Input: * -data struct to allow error messages to be created (obj) * -string length of the time component (width) * -error message to be diplayed if the time component cannot * be trimmed to the proper length (err_msg) * -input time component (ins) * -return value time component in a string (width) characters long (outs) * * Return: * -time component in a string (width) characters long if there were no errors * -void (ie, do not change the (outs) value) */ void ti_check (parse_info_t *obj, int width, char *err_msg, char *ins, char *outs) { int i, j; char *p; /* time value is too short, pad with '0's */ if ((i = strlen (ins)) < width) { sprintf (outs, "%.*s%s", (width - i), "0000", ins); return; } /* time value is too long, * see if removing leading '0's will solve */ if (i > width) { for (p = ins; *p == '0'; p++); j = (int) (p - ins); if ((i - j) <= width) sprintf (outs, "%.*s%s", width - i + j, "0000", p); else error_msg_queue (obj, err_msg, ERROR_MSG); return; } /* good */ strcpy (outs, ins); }
int country_syntax (char *country, parse_info_t *obj) { if (is_country (country, countries) >= 0) return 1; error_msg_queue (obj, "Unknown country", ERROR_MSG); return 0; }
int get_fingerprint (parse_info_t *o, char *PGPPATH, pgp_data_t *pdat) { int pgp_ok = 1; if (pgp_fingerpr (default_trace, PGPPATH, pdat->hex_first->key, pdat)) { if (pdat->fingerpr_cnt > 1) { error_msg_queue (o, "Too many fingerprints in certificate", ERROR_MSG); pgp_ok = 0; } else o->u.kc.fingerpr = strdup (pdat->fp_first->key); } else { error_msg_queue (o, "Couldn't find fingerprint in certificate", ERROR_MSG); pgp_ok = 0; } return pgp_ok; }
int real_check (parse_info_t *pi, char *rp_name, predef_t *p, int show_emsg, char *parm) { char ebuf[2048]; double dval; fprintf(dfile, "real_check () arg=(%s) lower=(%f) upper=(%f)\n", parm, p->u.d.lower, p->u.d.upper); if (regexec(&re[RE_REAL], parm, (size_t) 0, NULL, 0)) { if (show_emsg) { snprintf (ebuf, 2048, "Non-numeric argument value found for RP attribute \"%s\"", rp_name); error_msg_queue (pi, ebuf, ERROR_MSG); } return 1; } /* predef_t doesn't have a float upper and lower...fix */ if (!p->use_bounds) return 0; dval = atof (parm); if (dval < p->u.d.lower) { if (show_emsg) { snprintf (ebuf, 2048, "Real value (%f) is less than lower bound (%f) for RP attribute " "\"%s\"", dval, p->u.d.lower, rp_name); error_msg_queue (pi, ebuf, ERROR_MSG); } return 1; } if (dval > p->u.d.upper) { if (show_emsg) { snprintf (ebuf, 2048, "Real value (%f) exceeds upper bound (%f) for RP attribute \"%s\"", dval, p->u.d.upper, rp_name); error_msg_queue (pi, ebuf, ERROR_MSG); } return 1; } return 0; }
void regex_syntax (char *reg_exp, parse_info_t *obj) { regex_t comp_re; if (regcomp (&comp_re, reg_exp, REG_EXTENDED|REG_NOSUB) != 0) { error_msg_queue (obj, "Illegal regular expression", ERROR_MSG); return; } regfree(&comp_re); }
/* Given a maintainer reference, '*mntner' (ie, a list member from a 'mnt-by' * attribute), check for names that begin with a reserved prefix (eg, 'rs-'). * * Return: * void * side effect: if a name begins with a reserved prefex, send an error msg. */ void mb_check (parse_info_t *o, char *mntner) { char buf[MAXLINE]; if (mntner == NULL) return; if (has_reserved_prefix (mntner)) { snprintf (buf, MAXLINE, "Maintainer reference begins with a reserved prefix (%s)\n", mntner); error_msg_queue (o, buf, ERROR_MSG); } }
/* * em - e-mail * mn - mnt-nfy * ny - notify * dt - upd-to */ int email_syntax (char *email_addr, parse_info_t *obj) { char *p; /*if (verbose) fprintf (dfile, "JW: email_syntax(%s)\n", email_addr);*/ if ((p = strchr (email_addr, '@')) == NULL) { error_msg_queue (obj, "Missing '@' in email address", ERROR_MSG); return 0; } if (strchr (p + 1, '@') != NULL) { error_msg_queue (obj, "Multiple '@' found in email address", ERROR_MSG); return 0; } if (regexec (&re[RE_EMAIL3], email_addr, (size_t) 0, NULL, 0) || (regexec (&re[RE_EMAIL1], email_addr, (size_t) 0, NULL, 0) && regexec (&re[RE_EMAIL2], email_addr, (size_t) 0, NULL, 0))) { error_msg_queue (obj, "Malformed RFC822 email address", ERROR_MSG); return 0; } return 1; }
/* boolean means either true or false */ int boolean_check (parse_info_t *pi, char *rp_name, predef_t *p, int show_emsg, char *parm) { char ebuf[2048]; fprintf(dfile, "boolean_check() arg=(%s)\n", parm); if (!strcasecmp(parm, "true") || !strcasecmp(parm, "false")) return 0; else { if (show_emsg) { snprintf(ebuf, 2048, "Invalid boolean value %s found in attribute \"%s\"", parm, rp_name); error_msg_queue (pi, ebuf, ERROR_MSG); } return 1; } }
/* check to make sure of ASCII characters */ int free_text_check (parse_info_t *pi, char *rp_name, predef_t *p, int show_emsg, char *parm) { char ebuf[2048]; int bad_arg; fprintf(dfile, "free_text_check() arg=(%s)\n", parm); for (; *parm && isascii(*parm); parm++); bad_arg = (*parm != '\0'); if (bad_arg && show_emsg) { snprintf(ebuf, 2048, "Non-ASCII character found in attribute \"%s\"", rp_name); error_msg_queue (pi, ebuf, ERROR_MSG); } return bad_arg; }
/* Given a comma seperated sources is (ie, rx-in: IRROrder(radb,ans,...)), * return an error if 'new_source' is already in the list 'sources_list'. * * Return * * 0 if new_source is already a member of 'sources_list' * or DB is now defined in irrd.conf file (ie, is now known) * 1 otherwise * */ int irrorder_syntax (parse_info_t *obj, char *sources_list, char *new_source) { char buf[MAXLINE], *p; /* See if we know of this DB if (strcasecmp (new_source, "radb") && strcasecmp (new_source, "mci") && strcasecmp (new_source, "canet") && strcasecmp (new_source, "bell") && strcasecmp (new_source, "ripe")) { sprintf (buf, "Unknown database \"%s\"", new_source); error_msg_queue (obj, buf, ERROR_MSG); return 1; }*/ /* See if we know of this DB if (is_sourcedb (new_source, ci.srcs) == NULL) { sprintf (buf, "Unknown database \"%s\"", new_source); error_msg_queue (obj, buf, ERROR_MSG); return 1; } */ /* Make sure the DB isn't duplicately defined */ if (sources_list != NULL && strlen (sources_list) < MAXLINE) { strcpy (buf, sources_list); p = strtok (buf, ","); while (p != NULL) { if (*p == ' ') p++; if (!strcmp (p, new_source)) { snprintf (buf, MAXLINE, "Duplicate database \"%s\"", new_source); error_msg_queue (obj, buf, ERROR_MSG); return 1; } p = strtok (NULL, ","); } } return 0; }
/* Given a short prefix (ie, no prefix length) or long prefix * (ie, prefix/length) return yes or no if 'string' is legal. * 'short_prefix' is a flag value describing 'string'. * First the prefix is checked and then the prefix length if * it is a long prefix. This routine *assumes* that the * prefix has four well-formed octets/compponents from the * scanner. * * Return: * 1 if 'string' is well-formed * 0 otherwise */ int _is_ipv4_prefix (parse_info_t *obj, char *string, int short_prefix) { u_char dst[4]; char *p = NULL, save[64]; int val = 0, i, j; if ((p = strchr (string, '/')) != NULL) { if (short_prefix) return 0; strncpy (save, string, 64); j = p - string; if (j < 2 || j > 60) { error_msg_queue (obj, "Malformed prefix", ERROR_MSG); return 0; } save [j] = '\0'; save [63] = '\0'; /* make sure we are null terminated */ string = save; } else if (!short_prefix) return 0; /* check the ip part */ if (irrd_inet_pton (AF_INET, string, dst) <= 0) { error_msg_queue (obj, "Malformed prefix", ERROR_MSG); return 0; } /* check the ip length part */ if (!short_prefix) { for (i = 0; i < 3 && *++p; i++) { if (!isdigit((int)*p)) { error_msg_queue (obj, "Non-numeric value in prefix mask", ERROR_MSG); return 0; } else val = val * 10 + *p - '0'; } /* don't want 005, 33, etc... */ if (i == 0 || i > 2 || val > 32 || (val < 10 && i == 2)) { error_msg_queue (obj, "Malformed prefix mask", ERROR_MSG); return 0; } /* check for prefix exceeding prefix mask */ if ((j = (val / 8)) < 4) { val -= 8 * j; dst[j] <<= val; for (i = j; i < 4; i++) { if (dst[i] != 0) { error_msg_queue (obj, "IP prefix exceeds prefix mask length", ERROR_MSG); return 0; } } } } return 1; }
/* We have parsed a 'certif:' attribute from a 'key-cert' object. * Now perform the check to make sure the hexid specified in the * 'key-cert:' attribute matches the hexid from the 'certif:' * attribute. We perform this check (and others) by adding the * 'certif:' attribute/PGP key block to a temp ring and parsing * the output from PGP. Additionally, we check the following: * * 1. make sure there is only 1 hexid in the key * 2. make sure there is at least 1 owner/uid specified * 3. make sure we get a 'Successful' return string from PGP * 4. call get_fingerprint () to get the key fingerprint * which checks to make sure there is only 1 fingerprint * * Return: * * file name of key certificate file if there were no errors found * - the file can then be used to easily add the PGP key to the * local ring * - the key fingerprint and owner(s)/uid(s) are saved to be * used for the corresponding 'key-cert' auto-generated fields * NULL otherwise */ char *hexid_check (parse_info_t *o) { #ifdef PGP char pgpinfn[256], tmp_pgp_dir[256], ebuf[1024]; FILE *pgpin; char_list_t *p; pgp_data_t pdat; int pgp_errors = 0, fd; #endif /* If we don't have PGP installed then there is nothing to do. */ #ifndef PGP error_msg_queue (o, "PGP is not installed on the system. Cannot perform operation.", ERROR_MSG); return NULL; #else /* make a tmp directory for the pgp rings */ umask (0022); strcpy (tmp_pgp_dir, "/var/tmp/pgp.XXXXXX"); if (mkdtemp (tmp_pgp_dir) == NULL) { error_msg_queue (o, "Internal error. Couldn't create temp directory for PGP\n", ERROR_MSG); return NULL; } /* create a file and put the key certificate into it */ strcpy (pgpinfn, "/var/tmp/irrsyntax.XXXXXX"); fd = mkstemp (pgpinfn); if ((pgpin = fdopen (fd, "w")) == NULL) { error_msg_queue (o, "Internal error. Could not check 'key-cert:' temp file creation error", ERROR_MSG); goto pgp_errors_jump; } fwrite (o->u.kc.certif, sizeof (char), strlen (o->u.kc.certif), pgpin); fclose (pgpin); /* add the certificate to a temp ring */ if (!pgp_add (default_trace, tmp_pgp_dir, pgpinfn, &pdat)) { error_msg_queue (o, "Couldn't add key-cert to ring. Didn't get successful reply from PGP", ERROR_MSG); goto pgp_errors_jump; } /* certificate checks */ /* do we have more than 1 hex ID? */ if (pdat.hex_cnt > 1) { error_msg_queue (o, "Too many public keys in certificate", ERROR_MSG); pgp_errors = 1; } /* does the hex ID of the 'key-cert' attr match the certificate hex ID ? */ else if (strcmp (pdat.hex_first->key, o->u.kc.kchexid)) { snprintf (ebuf, 1024, "Hex-ID mistmatch: 'key-cert:' (%s) 'certif:' (%s)\n", o->u.kc.kchexid, pdat.hex_first->key); error_msg_queue (o, ebuf, ERROR_MSG); pgp_errors = 1; } /* owner check */ else if (pdat.owner_first == NULL) { error_msg_queue (o, "No uid's/owners found in certificate", ERROR_MSG); pgp_errors = 1; } /* grab all the owners */ else { o->u.kc.owner_count = pdat.owner_cnt; for (p = pdat.owner_first; p != NULL; p = p->next) o->u.kc.owner = my_concat (o->u.kc.owner, p->key, 0); } /* get the key fingerprint */ if (!pgp_errors && !get_fingerprint (o, tmp_pgp_dir, &pdat)) pgp_errors = 1; if (o->u.kc.owner != NULL) if (verbose) fprintf (dfile, "owner count (%d) owner (%s)\n", o->u.kc.owner_count, o->u.kc.owner); if (o->u.kc.fingerpr != NULL) if (verbose) fprintf (dfile, "fingerpr (%s)\n", o->u.kc.fingerpr); /* end debug */ /* clean up */ pgp_free (&pdat); /* if we have errors then we won't need the key file */ if (pgp_errors) { pgp_errors_jump: rm_tmpdir (tmp_pgp_dir); /* can get rid of temporary directory */ remove (pgpinfn); return NULL; } rm_tmpdir (tmp_pgp_dir); /* can get rid of temporary directory */ /* leave pgp key for possible addition to local ring */ return strdup (pgpinfn); #endif }
/* * nh - nic-hdl */ void nichdl_syntax (char *nic_hdl, parse_info_t *obj) { if (!is_nichdl (nic_hdl)) error_msg_queue (obj, "Syntax error in NIC handle", ERROR_MSG); }
void md5pw_syntax (char *cryptpw, parse_info_t *obj) { if (regexec(&re[RE_MD5_PW], cryptpw, (size_t) 0, NULL, 0)) error_msg_queue (obj, "Illegal encrypted password ([./0-9A-Za-z$]{34})", ERROR_MSG); }
/* Given a 'date' (ie, YYMMDD) make sure the date is in proper * format and syntax. YY must be >= 1988. If the date is * in the future, change the date to today's date and return * the correct date. Skip the future check if 'skip_future_check' is set * (ie, withdrawn: attr) * * Return: * NULL if no errors in date and date is not in the future * today's date if no errors in date and date is in the future */ char *date_syntax (char *date, parse_info_t *obj, int skip_future_check) { char year[5]; char month[3]; char day[3]; char strdate[9]; char *now; int errors; /* ensure the date is 6 char's long and all numbers */ if (regexec(&re[RE_DATE], date, (size_t) 0, NULL, 0)) { error_msg_queue (obj, "Malformed date (/^YYYYMMDD$/)", WARN_OVERRIDE_MSG); error_msg_queue (obj, "Changing to today's date", WARN_OVERRIDE_MSG); sprintf (strdate, "%d", todays_date ()); return strdup (strdate); /* error_msg_queue (obj, "Malformed date (/^YYYYMMDD$/)", ERROR_MSG); return NULL; */ } errors = 0; /* check year part */ strncpy (year, date, 4); year[4] = '\0'; if (strncmp (year, "1988", 4) < 0) { error_msg_queue (obj, "Year part of date is too old (YYYYMMDD)", ERROR_MSG); errors++; } /* check month part */ strncpy (month, &date[4], 2); month[2] = '\0'; if ((strncmp (month, "01", 2) < 0) || (strncmp (month, "12", 2) > 0)) { error_msg_queue (obj, "Syntax error in month part of date (YYYYMMDD)", ERROR_MSG); errors++; } /* check day part */ strncpy (day, &date[6], 2); day[2] = '\0'; if ((strncmp (day, "01", 2) < 0) || (strncmp (day, "31", 2) > 0)) { error_msg_queue (obj, "Syntax error in day part of date (YYMMDD)", ERROR_MSG); errors++; } if (errors || skip_future_check) return NULL; if ((now = date_in_future (date)) != NULL) { /* error_msg_queue (obj, "Date is in the future, changed to today's date", WARN_OVERRIDE_MSG); */ return now; } return NULL; }