bin/dbupdate/dbupdate.c
/* [<][>][^][v][top][bottom][index][help] */
FUNCTIONS
This source file includes following functions.
- error_init
- delete_key
- import_key
- get_keyowner_fingerpr
- process_object
- process_file
- generate_upd_file
- create_lock_file
- remove_lock_file
- write_checkpoint
- remove_checkpoint
- main
1 /***************************************
2 $Revision: 1.15 $
3
4 DBupdate
5
6 Status: PARTIALLY REVIEWED, NOT TESTED
7
8 Author(s): Engin Gunduz
9
10 ******************/ /******************
11 Modification History:
12 engin (01/03/2000) Created.
13 denis (31/08/2001) Modified for new API
14 ******************/ /******************
15 Copyright (c) 2001,2002 RIPE NCC
16
17 All Rights Reserved
18
19 Permission to use, copy, modify, and distribute this software and its
20 documentation for any purpose and without fee is hereby granted,
21 provided that the above copyright notice appear in all copies and that
22 both that copyright notice and this permission notice appear in
23 supporting documentation, and that the name of the author not be
24 used in advertising or publicity pertaining to distribution of the
25 software without specific, written prior permission.
26
27 THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
28 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
29 AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
30 DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
31 AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
32 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
33 ***************************************/
34
35
36
37
38 #include <config.h>
39 #include "dbupdate.h"
40 #include "UP_extrnl_syntax.h"
41 #include "UP_subject.h"
42 #include "er_yacc_helper.h"
43 #include "erroutines.h"
44 #include "ca_configFns.h"
45 #include "ca_dictionary.h"
46 #include "ca_macros.h"
47 #include "ca_srcAttribs.h"
48 #include "notification.h"
49 #include "gpg.h"
50 #include "mail_parser.h"
51 #include "process.h"
52
53 #ifdef HAVE_SYS_PARAM_H
54 #include <sys/param.h>
55 #endif
56
57
58 int tracing = 0;
59 int test_mode = 0;
60 int supress_ack_notif = 0;
61 int print_out_ack = 0;
62
63 /* do we process a mail */
64 int reading_from_mail = 0;
65
66 /* are we processing networkupdate? */
67 int networkupdate = 0;
68
69 /* IP of the networkupdate client */
70 char * netupdclientIP = NULL;
71
72 /* two global variables to tally the processed objects */
73 int count_successful = 0;
74 int count_unsuccessful = 0;
75
76
77 /* sender of the mail, in case of a mail update */
78 char *update_mail_sender = NULL;
79 char *update_mail_subject = NULL;
80 char *update_mail_date = NULL;
81 char *update_mail_ID = NULL;
82 char *update_mail_cc = NULL;
83
84 /* re-direct to humail message */
85 char *header_type = NULL;
86 char *text_type = NULL;
87
88 /* required configuration variables */
89 char *tmpdir = NULL;
90 char *lockdir = NULL;
91 char *mailcmd = NULL;
92 char *notitxt = NULL;
93 char *successtxt = NULL;
94 char *failuretxt = NULL;
95 char *helpheader = NULL;
96 char *notimailtxt = NULL;
97 char *notinetworktxt = NULL;
98 char *fwtxt = NULL;
99 char *fwmailtxt = NULL;
100 char *mtfwheader = NULL;
101 char *mtfwtxt = NULL;
102 char *mailtxt = NULL;
103 char *acksig = NULL;
104 char *defmail = NULL;
105 char *updlog = NULL;
106 char *notiflog = NULL;
107 char *crosslog = NULL;
108 char *acklog = NULL;
109 char *forwlog = NULL;
110 char *humailbox = NULL;
111 char *autobox = NULL;
112 char *copyright_notice = NULL;
113 char *overridecryptedpw = NULL;
114 char *country = NULL;
115 char *countries[400];
116 char *nicsuffixes[7];
117 char *sources[100];
118 char *pgppath = NULL;
119 char *gpgcmd = NULL;
120 char *pgp_public_key_ring = NULL;
121 char *autodbmhelp = NULL;
122 char *update_host = NULL;
123 int update_port;
124 char *query_host = NULL;
125 int query_port;
126 char *cn_subject_add = NULL;
127 char *cn_subject_del = NULL;
128 char *cn_explain_add = NULL;
129 char *cn_explain_del = NULL;
130 char *cn_overlap_add = NULL;
131 char *cn_overlap_del = NULL;
132 char *cno_subject_add = NULL;
133 char *cno_subject_del = NULL;
134 char *cno_explain_add = NULL;
135 char *cno_explain_del = NULL;
136 char *cno_overlap_add = NULL;
137 char *cno_overlap_del = NULL;
138 char *allocmnt = NULL;
139 char *mheader = NULL;
140 char *DBhost = NULL;
141 int DBport;
142 char *DBuser = NULL;
143 char *DBname = NULL;
144 char *DBpasswd = NULL;
145 /* end of config variables */
146
147 char * fingerprint = NULL;
148 char * keyowner = NULL;
149
150 /* result of subject line processing is kept in the following struct. */
151 up_subject_struct subject_result;
152
153
154 /* hostname and pid are used all over the program, so we save them into these variables */
155 char hostname[MAXHOSTNAMELEN];
156 /* char * hostname; */
157 int pid;
158
159 /* name of the lock file, which is used for the crash recovery mechanism */
160 char * lock_file_name;
161
162 void error_init(int argc, char ** argv) {
/* [<][>][^][v][top][bottom][index][help] */
163
164 ER_init("dbupdate", 1);
165
166
167 } /* error_init() */
168
169
170
171
172
173
174 /* 'lockfile' struct is for keeping both the name of the lock file and the file descriptor
175 of it, which is open during the execution of dbupdate. We need the filedes to close it,
176 when dbupdate finishes, and the name to delete the file. */
177 typedef struct {
178 char * lockname;
179 int filedes;
180 } lockfilestruct;
181
182
183 lockfilestruct lockfile;
184
185
186
187 /* Deletes the key defined in the incoming object (a key-cert object)
188 from the public keyring. Returns NULL if there was no error,
189 returns an error message if there is an error */
190 char *delete_key(rpsl_object_t * obj)
/* [<][>][^][v][top][bottom][index][help] */
191 {
192 struct ImportKeyObject iKO;
193 char * obj_keyID;
194 char * key_cert_attr;
195 GList * templist;
196 GList * certiflist, * next;
197 u32 keyID;
198 char * key_file_name;
199 char ** lines;
200 int i;
201 FILE * key_file;
202 char * temp, * temp2;
203 char * error_string;
204 rpsl_attr_t *attr;
205
206 templist = get_attr_list(obj, "key-cert");
207 attr = (rpsl_attr_t *)(templist->data);
208 key_cert_attr = strdup((char *)(attr->value));
209 /* key_cert_attr = strdup( (char *)( ((rpsl_attr_t *)(templist->data))->value ) ); */
210 rpsl_attr_delete_list(templist);
211
212 key_file_name = (char *)malloc(strlen(tmpdir) + strlen("tmp-key.") + 32);
213 sprintf(key_file_name, "%s/tmp-key.%i", tmpdir, pid);
214
215 /* now we must write certif attribute(s) of this key-certif into the key_file_name */
216 /* get the certif first */
217 certiflist = get_attr_list(obj, "certif");
218 if (( key_file = fopen(key_file_name, "w")) == NULL)
219 {
220 ER_perror(FAC_UP, UP_CANTOPEN, "Can't open temporary file, %s", key_file_name);
221 exit(1);
222 }
223 for ( next = certiflist; next != NULL ; next = g_list_next(next) )
224 {
225 attr = (rpsl_attr_t *)(next->data);
226 lines = g_strsplit((char *)(attr->value), "\n", 0);
227 if (lines[0] == NULL)
228 { /* if this was an empty attribute, just print an empty line */
229 fprintf(key_file, "\n");
230 }
231 for (i = 0; lines[i] != NULL; i++)
232 {
233 temp = strdup(lines[i]);
234 if (i != 0 && temp[0] == '+')
235 { /* if it begins with a plus */
236 temp2 = strdup(temp + 1);
237 g_strstrip(temp2);
238 fprintf(key_file, "%s\n", temp2);
239 free(temp);free(temp2);
240 }
241 else
242 {
243 g_strstrip(temp);
244 fprintf(key_file, "%s\n", temp);
245 free(temp);
246 }
247 }
248 g_strfreev(lines);
249 }
250 fclose(key_file);
251 rpsl_attr_delete_list(certiflist);
252
253 strcpy(iKO.iFilename, key_file_name);
254
255 if (tracing)
256 {
257 printf("TRACING: delete_key: key_cert_attr: [%s]\n", key_cert_attr);
258 }
259
260 obj_keyID = strdup(key_cert_attr + strlen("PGPKEY-"));
261
262 if (tracing)
263 {
264 printf("TRACING: delete_key: obj_keyID: [%s]\n", obj_keyID);
265 }
266
267 keyID = strtoul(obj_keyID, NULL, 16);
268
269 if (tracing)
270 {
271 printf("TRACING: delete_key: keyID is: %u, %X\n", keyID, keyID);
272 }
273
274 strcpy(iKO.keyRing, pgp_public_key_ring);
275 PA_RemoveKey(&iKO);
276
277 if (tracing)
278 {
279 printf("TRACING: importKeyObj status:\n");
280 printf("TRACING: isValid: %d\n", iKO.rc);
281 }
282
283 /* clean-up: delete the file, free the char * */
284 unlink(key_file_name);
285 free(key_file_name);
286
287 if (iKO.rc == iKO_OK)
288 { /* if PA_RemoveKey returned OK */
289 return NULL;
290 }
291 else
292 { /* if PA_RemoveKey returned not OK */
293 switch (iKO.rc)
294 {
295 case iKO_UNCHANGED: error_string = strdup("the key is already in the keyring");break;
296 case iKO_NOUSERID: error_string = strdup("no user ID could be extracted");break;
297 case iKO_GENERAL: error_string = strdup("general PGP error");break;
298 case iKO_NOTVALIDUSERID: error_string = strdup("no valid user ID ");break;
299 case iKO_NOPUBLICKEY: error_string = strdup("no public key in the object");break;
300 case iKO_NODEFAULTPUBLICKEYRING: error_string = strdup("general PGP error");break;
301 case iKO_CRC_ERROR: error_string = strdup("CRC error in the certificate");break;
302 case iKO_NO_OPENPGP_DATA:error_string = strdup("no OpenPGP data in the object");break;
303 case iKO_NO_IN_FILES: error_string = strdup("general PGP error");break;
304 case iKO_GENERALFAILURE: error_string = strdup("general PGP error");break;
305 default: error_string = strdup("general PGP error");
306 }
307 return error_string;
308 }
309
310 }
311
312
313
314
315
316
317
318 /* Takes a key-certif object, extracts its 'certif' attribute and adds
319 the key into public keyring
320 If there is no problem, it returns NULL
321 If there is a problem, then it returns a string which contains an error
322 message */
323 char * import_key(rpsl_object_t *object)
/* [<][>][^][v][top][bottom][index][help] */
324 {
325 char * key_file_name;
326 char *value;
327 struct ImportKeyObject iKO;
328 GList * certiflist, * item, * templist;
329 FILE * key_file;
330 char keyID[9];
331 char * obj_keyID, * key_cert_attr;
332 char * error_string = NULL;
333
334 key_file_name = (char *)malloc(strlen(tmpdir) + strlen("tmp-key.") + 32);
335 sprintf(key_file_name, "%s/tmp-key.%i", tmpdir, pid );
336
337 /* now we must write certif attribute(s) of this key-certif into the key_file_name */
338 /* get the certif first */
339 certiflist = rpsl_object_get_attr(object, "certif");
340 if (( key_file = fopen(key_file_name, "w")) == NULL)
341 {
342 ER_perror(FAC_UP, UP_CANTOPEN, "Can't open temporary file, %s", key_file_name);
343 exit(1);
344 }
345 for( item = certiflist; item != NULL ; item = g_list_next(item) )
346 {
347 value = rpsl_attr_get_clean_value( (rpsl_attr_t *)(item->data) );
348 if (value == NULL)
349 { /* if this was an empty attribute, just print an empty line */
350 fprintf(key_file, "\n");
351 }
352 else
353 {
354 fprintf(key_file, "%s\n", value);
355 free(value);
356 }
357 }
358 fclose(key_file);
359 rpsl_attr_delete_list(certiflist);
360
361 strcpy(iKO.iFilename, key_file_name);
362 strcpy(iKO.keyRing, pgp_public_key_ring);
363 PA_ImportKey(&iKO);
364
365 if (tracing)
366 {
367 printf("importKeyObj status:\n");
368
369 printf("isValid: %d\n", iKO.rc);
370 printf("keyID: %08lX\n", (long)(iKO.keyID) );
371 }
372 snprintf(keyID, 9, "%08lX", iKO.keyID);
373
374 if (tracing)
375 {
376 printf("keyID: [%s]\n", keyID);
377 }
378
379 templist = rpsl_object_get_attr(object, "key-cert");
380 key_cert_attr = rpsl_attr_get_clean_value((rpsl_attr_t *)(templist->data));
381 rpsl_attr_delete_list(templist);
382
383 if (tracing)
384 {
385 printf("key_cert_attr: [%s]\n", key_cert_attr);
386 }
387 obj_keyID = strdup(key_cert_attr + strlen("PGPKEY-"));
388 free(key_cert_attr);
389 if (tracing)
390 {
391 printf("obj_keyID: [%s]\n", obj_keyID);
392 }
393
394 if (iKO.rc == iKO_OK && (strcasecmp(obj_keyID, keyID) == 0))
395 { /* if PA_ImportKey returned OK
396 and the real keyID is equal to the
397 keyID in the 'key-cert' attribute */
398 fingerprint = strdup(iKO.fingerPrint);
399 keyowner = strdup(iKO.keyOwner);
400
401 /* clean-up: delete the file, free the variable */
402 unlink(key_file_name);
403 free(key_file_name);
404
405 return NULL;
406 }
407 else
408 {
409 /* if PA_ImportKey returned not OK or obj_keyID, keyID didn't match */
410 if (iKO.rc != iKO_OK)
411 {
412 switch (iKO.rc)
413 {
414 case iKO_UNCHANGED: error_string = strdup("the key is already in the keyring");break;
415 case iKO_NOUSERID: error_string = strdup("no user ID could be extracted");break;
416 case iKO_GENERAL: error_string = strdup("general PGP error");break;
417 case iKO_NOTVALIDUSERID: error_string = strdup("no valid user ID ");break;
418 case iKO_NOPUBLICKEY: error_string = strdup("no public key in the object");break;
419 case iKO_NODEFAULTPUBLICKEYRING: error_string = strdup("general PGP error");break;
420 case iKO_CRC_ERROR: error_string = strdup("CRC error in the certificate");break;
421 case iKO_NO_OPENPGP_DATA:error_string = strdup("no OpenPGP data in the object");break;
422 case iKO_NO_IN_FILES: error_string = strdup("general PGP error");break;
423 case iKO_MULTIPLE_KEYS: error_string = strdup("multiple keys in key-cert object");break;
424 case iKO_GENERALFAILURE: error_string = strdup("general PGP error");break;
425 default: error_string = strdup("general PGP error");
426 }
427
428 /* clean-up: delete the file, free the variable */
429 unlink(key_file_name);
430 free(key_file_name);
431 return error_string;
432
433 }
434 else
435 {
436 error_string = (char *)malloc(1024);/* this should be enough */
437 sprintf(error_string, "Keyid for this certificate (%s) is not the same as the PGPKEY field (%s)",
438 keyID, obj_keyID);
439 /* roll-back: we encountered a problem, so we have to remove the key that
440 we've added */
441 PA_RemoveKey(&iKO);
442
443 /* clean-up: delete the file, free the variable */
444 unlink(key_file_name);
445 free(key_file_name);
446
447 free(obj_keyID);
448 return error_string;
449 }
450 }
451
452 }
453
454
455
456 /* Gets the keyowner and fingerprint of a PGP key
457 from the keycert object. The keycert object must already
458 be in the database (thus, in the keyring)
459 The fingerprint and keyowner will be saved in global variables */
460
461 void get_keyowner_fingerpr(rpsl_object_t *obj)
/* [<][>][^][v][top][bottom][index][help] */
462 {
463 GList * templist = NULL;
464 char * obj_keyID = NULL;
465 struct ImportKeyObject iKO;
466 u32 keyID;
467 char * key_cert_value;
468
469
470 templist = rpsl_object_get_attr(obj, "key-cert");
471 key_cert_value = rpsl_attr_get_clean_value((rpsl_attr_t *)(templist->data));
472 rpsl_attr_delete_list(templist);
473
474 if (tracing)
475 {
476 printf("get_keyowner_fingerpr: key_cert_attr is [%s]\n", key_cert_value);
477 }
478
479 obj_keyID = strdup(key_cert_value + strlen("PGPKEY-"));
480 if (tracing)
481 {
482 printf("get_keyowner_fingerpr: obj_keyID is [%s]\n", obj_keyID);
483 }
484
485 sscanf(obj_keyID, "%8X", &keyID);
486 if (tracing)
487 {
488 printf("get_keyowner_fingerpr: keyID is [%u]\n", keyID);
489 }
490
491 /* set appropriate fields of iKO */
492 iKO.keyID = keyID;
493 strcpy(iKO.keyRing, pgp_public_key_ring);
494
495 GetFingerPrint(&iKO);
496 fingerprint = strdup(iKO.fingerPrint);
497
498 GetKeyOwner(&iKO);
499 keyowner = strdup(iKO.keyOwner);
500
501 free(key_cert_value);
502 free(obj_keyID);
503
504 if(tracing)
505 {
506 if (fingerprint != NULL)
507 {
508 printf("get_keyowner_fingerpr: fingerprint is [%s]\n", fingerprint);
509 }
510 if (keyowner)
511 {
512 printf("get_keyowner_fingerpr: keyowner is [%s]\n", keyowner);
513 }
514 }
515 }
516
517
518
519
520
521
522 /* Checks the object's syntax, retrives the old version of it from the db,
523 and checks auth2. If everything is OK, then sends it to RIPdb, where referential
524 integrity is checked, and the object is really committed to the db.
525
526 Arguments:
527 char * incoming: The object,
528 credentials_struct credentials: The struct containing the credentials, such as
529 'From:' field of the e-mail update,
530 GHashTable * NIC_hdl_hash: A hash containing
531 char * ack_file_name: The file name, to be used to store ACK message
532 GHashTable * ntfy_hash,
533 GHashTable * forw_hash,
534 GHashTable * cross_hash: hashes that contain files that have notifications.
535 */
536
537
538
539 int process_object(char * incoming, credentials_struct credentials,
/* [<][>][^][v][top][bottom][index][help] */
540 GHashTable * NIC_hdl_hash, char * ack_file_name,
541 GHashTable * ntfy_hash, GHashTable * forw_hash, GHashTable * cross_hash)
542 {
543 rpsl_object_t *object = NULL;
544 rpsl_object_t *old_obj = NULL;
545 rpsl_object_t *external_syntax_obj = NULL;
546 rpsl_object_t *obj_with_AUTO_NIC_hdl = NULL;
547 rpsl_object_t *formatted_object = NULL;
548 rpsl_object_t *generated_obj = NULL;
549 const GList * error_list = NULL;
550 const GList * error_list_item = NULL;
551 const GList * attr_list = NULL;
552 const GList * attr_list_item = NULL;
553 const GList * attr_error_list = NULL;
554 const GList * attr_error_list_item = NULL;
555 char * old_version = NULL;
556 int result = 0;
557 char * result_from_import_key = NULL;
558 char * result_from_delete_key = NULL;
559 char * auto_nic = NULL;
560 char * changed_obj_str = NULL;
561 char *obj_with_AUTO_NIC_hdl_str;
562 char * assigned_NIC;
563 char * formatted_object_str;
564 const char * type;
565 char *lctype;
566 char * arg;
567 char * arg2;
568 char * generated_obj_str;
569 const char * value = NULL;
570 const char * name = NULL;
571 char * attribute = NULL;
572 int noclass;
573 char *key;
574 up_ripupd_result_struct * result_from_RIPupd;
575 external_syntax_struct * external_syntax_results;
576 gint elevel, ecode;
577 gchar *edescr = NULL;
578
579 arg = strdup(incoming);
580
581 object = rpsl_object_init(arg);
582 error_list = rpsl_object_errors(object);
583 if (tracing && error_list)
584 {
585 printf("TRACING: errors found on initial object parse\n");
586 for ( error_list_item = error_list; error_list_item != NULL; error_list_item = g_list_next(error_list_item) )
587 {
588 elevel = ((rpsl_error_t *)(error_list_item->data))->level;
589 ecode = ((rpsl_error_t *)(error_list_item->data))->code;
590 edescr = strdup(((rpsl_error_t *)(error_list_item->data))->descr);
591
592 printf("TRACING: level [%d] code [%d] [%s]\n", elevel, ecode, edescr);
593 free(edescr);
594 }
595 }
596 if ( error_list )
597 {
598 if ( ((rpsl_error_t *)(error_list->data))->code == RPSL_ERR_ONLYCOMMENTS )
599 return UP_NOOBJECT;
600 }
601
602 if ( !rpsl_object_has_error(object, RPSL_ERRLVL_ERROR)
603 && has_ref_to_AUTO_nic_hdl(object) )
604 { /* parsed with no systax errors */
605 if (tracing)
606 {
607 printf("TRACING: the object has ref to AUTO nic-hdl\n");
608 }
609
610 /* if this object has refs to AUTO NIC hdls*/
611 /* then first replace AUTO NIC hdls with assigned NIC hdls (in NIC_hdl_hash) */
612 if ((changed_obj_str = replace_refs_to_AUTO_NIC_hdl(object, NIC_hdl_hash, arg)) == NULL)
613 {
614 type = rpsl_object_get_class(object);
615
616 free(arg);
617 if ( UP_remove_override_attr(object) )
618 arg = rpsl_object_get_text(object,0);
619 else
620 {
621 /* there was an override attr in this object and it has not been removed */
622 arg = (char *)malloc(2);
623 strcpy(arg, ""); /* Don't include object in ack/notif msgs */
624 }
625
626 AK_add_to_ack(ack_file_name, "\nUpdate FAILED: [%s] Unknown AUTO NIC handle referenced\n%s\n",
627 type ? type : "unknown-type", arg);
628
629 rpsl_object_delete(object);
630 free(arg);
631 return UP_ANE; /* AUTO NIC hdl error */
632 }
633 else
634 { /* in this case, we must use changed_obj_str instead of arg */
635
636 free(arg);
637 arg = changed_obj_str;
638 };
639 }
640
641
642 if ( !rpsl_object_has_error(object, RPSL_ERRLVL_ERROR) )
643 {
644 /* parsed with no systax errors */
645 type = rpsl_object_get_class(object);
646 /* is the object to be deleted? */
647 if ( rpsl_object_is_deleted(object) )
648 {
649 old_version = get_old_version(object, arg);
650
651 if(old_version == NULL)
652 { /* the object doesn't exist in the db! */
653
654 if (tracing)
655 {
656 printf("TRACING: the object doesn't exist in the db\n");
657 }
658
659 free(arg);
660 if ( UP_remove_override_attr(object) )
661 arg = rpsl_object_get_text(object,0);
662 else
663 {
664 /* there was an override attr in this object and it has not been removed */
665 arg = (char *)malloc(2);
666 strcpy(arg, ""); /* Don't include object in ack/notif msgs */
667 }
668
669 AK_add_to_ack(ack_file_name, "\nDelete FAILED: [%s] %s\n%s\n***Error: Entry not found\n\n",
670 type, get_search_key(object, type), arg);
671
672 rpsl_object_delete(object);
673 free(arg);
674 return UP_NSO; /* no such object */
675 }
676 else
677 { /* the object is in the db */
678
679 if (tracing)
680 {
681 printf("TRACING: the object is in the db\n");
682 }
683
684 lctype = strdup(type);
685 g_strdown(lctype);
686 if ( identical(old_version, object) /* if the old & new versions are identical */
687 || (strcmp(lctype, "key-cert") == 0) /* or it is a key-cert object */
688 || (strcmp(lctype, "inet6num") == 0) ) /* or it is an inet6num object */
689 {
690 result = check_auth(NULL, object, type, credentials);
691 if(result == UP_AUTH_OK)
692 {
693 if (tracing)
694 {
695 printf("TRACING: Will send the obj to be deleted\n");
696 }
697 if(strcmp(type, "key-cert") == 0)
698 {
699 result_from_delete_key = delete_key(object);
700 }
701 else
702 {
703 result_from_delete_key = NULL;
704 }
705 /* if there was no problem with key deletion from the key-ring */
706 if (result_from_delete_key == NULL)
707 {
708 result_from_RIPupd = send_object_db(object, NULL, "DEL");
709 if (result_from_RIPupd->result == 0)
710 {
711 AK_add_to_ack(ack_file_name, "\nDelete OK: [%s] %s\n",
712 type, get_search_key(object, type));
713 NT_write_all_ntfs(old_version, NULL, NULL, tmpdir, ntfy_hash, forw_hash, cross_hash,
714 credentials.from);
715
716 rpsl_object_delete(object);
717 free(result_from_RIPupd);
718 free(arg);
719 free(old_version);
720 return UP_OK;
721 }
722 else
723 {
724 AK_add_to_ack(ack_file_name, "\nDelete FAILED: [%s] %s\n%s\n",
725 type, get_search_key(object, type),
726 result_from_RIPupd->error_str);
727
728 rpsl_object_delete(object);
729 free(result_from_RIPupd->error_str);
730 free(result_from_RIPupd);
731 free(arg);
732 free(old_version);
733 return UP_INT;
734 }
735 }
736 else
737 {
738 AK_add_to_ack(ack_file_name, "\nDelete FAILED: [%s] %s\n%s\n",
739 type, get_search_key(object, type),
740 result_from_delete_key);
741
742 rpsl_object_delete(object);
743 free(arg);
744 free(old_version);
745 free(result_from_delete_key);
746 return UP_INT;
747 }
748 }
749 else
750 { /* auth failed */
751 if (tracing)
752 {
753 printf("TRACING: Auth failed\n");
754 }
755
756 free(arg);
757 if ( UP_remove_override_attr(object) )
758 arg = rpsl_object_get_text(object,0);
759 else
760 {
761 /* there was an override attr in this object and it has not been removed */
762 arg = (char *)malloc(2);
763 strcpy(arg, ""); /* Don't include object in ack/notif msgs */
764 }
765
766 AK_add_to_ack(ack_file_name, "\nDelete FAILED: [%s] %s\nAuthorisation failed, request forwarded to maintainer.\n%s\n",
767 type, get_search_key(object, type), arg);
768 NT_write_all_frwds(old_version, NULL, tmpdir, ntfy_hash, forw_hash, cross_hash, credentials.from);
769
770 rpsl_object_delete(object);
771 free(arg);
772 free(old_version);
773 return UP_AUF; /* Auth failed */
774 }
775 } /* end of identical match */
776 else
777 { /* the new & old versions do not match */
778 free(arg);
779 if ( UP_remove_override_attr(object) )
780 arg = rpsl_object_get_text(object,0);
781 else
782 {
783 /* there was an override attr in this object and it has not been removed */
784 arg = (char *)malloc(2);
785 strcpy(arg, ""); /* Don't include object in ack/notif msgs */
786 }
787
788 AK_add_to_ack(ack_file_name, "\nDelete FAILED: [%s] %s\n%s\n***Error: new & old versions do not match\n",
789 type, get_search_key(object, type), arg);
790
791 rpsl_object_delete(object);
792 free(arg);
793 free(old_version);
794 return UP_NOM; /* new & old versions do not match */
795 }
796 } /* end of the object is in the db */
797 } /* end of the object is to be deleted */
798 else
799 { /* the object is _NOT_ to be deleted */
800
801 if (has_AUTO_NIC_hdl(object))
802 { /* if the object has an AUTO NIC hdl */
803 external_syntax_obj = rpsl_object_copy(object);
804 external_syntax_results = UP_check_external_syntax(external_syntax_obj);
805 if ( external_syntax_results->result != UP_EXTSYN_ERR
806 && external_syntax_results->result != UP_EXTSYN_ERR_WARN)
807 { /* if there is no error */
808 /* then its nic-hdl attribute must be modified so that RIPupdate
809 would understand that it must assign a NIC handle to it */
810 /* but first check the auth */
811 result = check_auth(external_syntax_obj, NULL, type, credentials);
812 if (result == UP_AUTH_OK)
813 {
814 if (tracing)
815 {
816 printf("TRACING: Will send the obj to be created with AUTO NIC hdl\n");
817 }
818 auto_nic = (char *)malloc(1024); /* should be enough for a NIC hdl */
819 obj_with_AUTO_NIC_hdl = replace_AUTO_NIC_hdl(external_syntax_obj, auto_nic);
820 if (tracing)
821 {
822 obj_with_AUTO_NIC_hdl_str = rpsl_object_get_text(obj_with_AUTO_NIC_hdl,0);
823 printf("TRACING: Called replace_AUTO_NIC_hdl, get [%s]\n", obj_with_AUTO_NIC_hdl_str);
824 printf("TRACING: Will send the obj to be added\n");
825 free(obj_with_AUTO_NIC_hdl_str);
826 obj_with_AUTO_NIC_hdl_str = NULL;
827 }
828 assigned_NIC = (char *)malloc(128); /* this should be enough for a NIC hdl */
829 result_from_RIPupd = send_object_db(obj_with_AUTO_NIC_hdl, assigned_NIC, "ADD");
830 if (result_from_RIPupd->result == 0)
831 {
832 AK_add_to_ack(ack_file_name, "\nNew OK: [%s] %s\n", type, assigned_NIC);
833
834 /* replace the AUTO nic hdl with the assigned one (for reporting purposes, in the notif mesg) */
835 formatted_object = UP_put_assigned_NIC(external_syntax_obj, assigned_NIC);
836
837 formatted_object_str = rpsl_object_get_text(formatted_object,0);
838 NT_write_all_ntfs(NULL, arg, formatted_object_str, tmpdir, ntfy_hash, forw_hash, cross_hash,
839 credentials.from);
840
841 result_from_RIPupd->result = 0;
842 if (tracing && assigned_NIC != NULL)
843 {
844 printf("TRACING: send_object_db returned [%s] as assigned NIC hdl\n", assigned_NIC);
845 }
846 if (assigned_NIC != NULL)
847 {
848 if (tracing)
849 {
850 printf("TRACING: auto_nic=[%s], assigned_NIC=[%s]\n", auto_nic, assigned_NIC);
851 }
852 g_hash_table_insert(NIC_hdl_hash, auto_nic, assigned_NIC);
853 if (tracing)
854 {
855 printf("TRACING: NIC_hdl_hash has %i pairs\n",g_hash_table_size(NIC_hdl_hash));
856 }
857 }
858
859 rpsl_object_delete(formatted_object);
860 rpsl_object_delete(obj_with_AUTO_NIC_hdl);
861 rpsl_object_delete(external_syntax_obj);
862 rpsl_object_delete(object);
863 free(result_from_RIPupd);
864 free(formatted_object_str);
865 free(external_syntax_results->new_obj);
866 /* free(external_syntax_results->error_str);*/
867 /* free(external_syntax_results->warning_str);*/
868 free(external_syntax_results);
869 free(arg);
870 return UP_OK;
871 }
872 else
873 {
874 if ( UP_remove_override_attr(object) )
875 arg2 = rpsl_object_get_text(object,0);
876 else
877 {
878 /* there was an override attr in this object and it has not been removed */
879 arg2 = (char *)malloc(2);
880 strcpy(arg2, ""); /* Don't include object in ack/notif msgs */
881 }
882
883 AK_add_to_ack(ack_file_name, "\nNew FAILED: [%s]\n%s\n%s\n",
884 type, arg2, result_from_RIPupd->error_str);
885
886 rpsl_object_delete(obj_with_AUTO_NIC_hdl);
887 rpsl_object_delete(external_syntax_obj);
888 rpsl_object_delete(object);
889 free(result_from_RIPupd);
890 free(external_syntax_results->new_obj);
891 free(external_syntax_results);
892 free(arg2);
893 free(arg);
894 return UP_INT;
895 }
896 }
897 else
898 {
899 /* auth failed ! */
900 if (tracing)
901 {
902 printf("TRACING: Auth failed\n");
903 }
904
905 if ( UP_remove_override_attr(object) )
906 arg2 = rpsl_object_get_text(object,0);
907 else
908 {
909 /* there was an override attr in this object and it has not been removed */
910 arg2 = (char *)malloc(2);
911 strcpy(arg2, ""); /* Don't include object in ack/notif msgs */
912 }
913
914 AK_add_to_ack(ack_file_name, "\nNew FAILED: [%s] %s\nAuthorisation failed, request forwarded to maintainer.\n%s\n",
915 type, get_search_key(object, type), arg2);
916 NT_write_all_frwds(NULL, arg, tmpdir, ntfy_hash, forw_hash, cross_hash, credentials.from);
917
918 rpsl_object_delete(external_syntax_obj);
919 rpsl_object_delete(object);
920 free(external_syntax_results->new_obj);
921 free(external_syntax_results);
922 free(arg2);
923 free(arg);
924 return UP_AUF; /* Auth failed */
925 }
926 }
927 else
928 { /* external syntax check failed */
929 if ( UP_remove_override_attr(object) )
930 arg2 = rpsl_object_get_text(object,0);
931 else
932 {
933 /* there was an override attr in this object and it has not been removed */
934 arg2 = (char *)malloc(2);
935 strcpy(arg2, ""); /* Don't include object in ack/notif msgs */
936 }
937
938 AK_add_to_ack(ack_file_name, "\nUpdate FAILED: [%s] %s\n%s%s\n",
939 type, get_search_key(object, type),
940 arg2, external_syntax_results->error_str);
941
942 rpsl_object_delete(external_syntax_obj);
943 rpsl_object_delete(object);
944 free(external_syntax_results->new_obj);
945 free(external_syntax_results);
946 free(arg2);
947 free(arg);
948 return UP_SYN;
949 }
950 } /* end of the object has an AUTO NIC hdl */
951 else
952 { /* process object without an AUTO NIC hdl */
953 old_version = get_old_version(object, arg);
954 if (old_version != NULL)
955 {
956 /* so, this is an update operation */
957 if ( (!reading_from_mail) ||
958 (subject_result.result != UP_SUBJ_NEW_ENFORCED))
959 {
960 /* If the user didn't enforce creation in the subject line */
961 external_syntax_obj = rpsl_object_copy(object);
962 external_syntax_results = UP_check_external_syntax(external_syntax_obj);
963 if ( external_syntax_results->result != UP_EXTSYN_ERR
964 && external_syntax_results->result != UP_EXTSYN_ERR_WARN)
965 {
966 /* if there is no error */
967 if ( identical(old_version, external_syntax_obj) != 1 )
968 {
969 /* if the old version & the new one are not identical */
970 old_obj = rpsl_object_init(old_version);
971 error_list = rpsl_object_errors(old_obj);
972 /***************************** DO SOME ERROR CHECKING / REPORTING HERE ***************/
973
974 result = check_auth(object, old_obj, type, credentials);
975 if (result == UP_AUTH_OK)
976 {
977 if (tracing)
978 {
979 printf("TRACING: Will send the obj to be updated\n");
980 }
981
982 generated_obj = rpsl_object_copy(external_syntax_obj);
983 if (strcasecmp(type, "key-cert") == 0)
984 {
985 get_keyowner_fingerpr(object);/* get keyowner and fingerprint,
986 save them into global vars */
987 generated_obj_str = UP_generate_kc_attrs(generated_obj);
988 free(external_syntax_results->new_obj);
989 external_syntax_results->new_obj = generated_obj_str;
990 }
991
992 /* XXX this will be put back when UP_generate_i6_attrs is ready*/
993 else if(strcasecmp(type, "inet6num") == 0)
994 {
995 generated_obj_str = UP_generate_i6_attrs(generated_obj);
996 free(external_syntax_results->new_obj);
997 external_syntax_results->new_obj = generated_obj_str;
998 }
999 /**/
1000 result_from_RIPupd = send_object_db(generated_obj, NULL, "UPD");
1001
1002 if ( UP_remove_override_attr(object) )
1003 arg2 = rpsl_object_get_text(object,0);
1004 else
1005 {
1006 /* there was an override attr in this object and it has not been removed */
1007 arg2 = (char *)malloc(2);
1008 strcpy(arg2, ""); /* Don't include object in ack/notif msgs */
1009 }
1010
1011 if (result_from_RIPupd->result == 0)
1012 {
1013 AK_add_to_ack(ack_file_name, "\nUpdate OK: [%s] %s\n",
1014 type, get_search_key(object, type));
1015
1016 NT_write_all_ntfs(old_version, arg, external_syntax_results->new_obj, tmpdir, ntfy_hash, forw_hash, cross_hash,
1017 credentials.from);
1018
1019 rpsl_object_delete(generated_obj);
1020 rpsl_object_delete(old_obj);
1021 rpsl_object_delete(external_syntax_obj);
1022 rpsl_object_delete(object);
1023 free(result_from_RIPupd);
1024 free(old_version);
1025 free(external_syntax_results->new_obj);
1026 free(external_syntax_results);
1027 free(arg2);
1028 free(arg);
1029 return UP_OK;
1030 }
1031 else
1032 {
1033 AK_add_to_ack(ack_file_name, "\nUpdate FAILED: [%s] %s\n%s\n%s\n",
1034 type, get_search_key(object, type),
1035 arg2, result_from_RIPupd->error_str);
1036
1037 rpsl_object_delete(generated_obj);
1038 rpsl_object_delete(old_obj);
1039 rpsl_object_delete(external_syntax_obj);
1040 rpsl_object_delete(object);
1041 free(result_from_RIPupd->error_str);
1042 free(result_from_RIPupd);
1043 free(old_version);
1044 free(external_syntax_results->new_obj);
1045 free(external_syntax_results);
1046 free(arg2);
1047 free(arg);
1048 return UP_INT;
1049 }
1050 }
1051 else if (result == UP_NAM)
1052 {
1053 /* name of a person/role object cannot be changed */
1054 if (tracing)
1055 {
1056 printf("TRACING: name of a person/role object cannot be changed\n");
1057 }
1058
1059 if ( UP_remove_override_attr(object) )
1060 arg2 = rpsl_object_get_text(object,0);
1061 else
1062 {
1063 /* there was an override attr in this object and it has not been removed */
1064 arg2 = (char *)malloc(2);
1065 strcpy(arg2, ""); /* Don't include object in ack/notif msgs */
1066 }
1067
1068 AK_add_to_ack(ack_file_name, "\nUpdate FAILED: [%s] %s\n%s\n***Error: Name of a person or role object cannot be changed.\n",
1069 type, get_search_key(object, type), arg2);
1070
1071 rpsl_object_delete(old_obj);
1072 rpsl_object_delete(external_syntax_obj);
1073 rpsl_object_delete(object);
1074 free(old_version);
1075 free(external_syntax_results->new_obj);
1076 free(external_syntax_results);
1077 free(arg2);
1078 free(arg);
1079 return UP_NAM; /* name of a person/role object cannot be changed */
1080
1081
1082 }
1083 else
1084 {
1085 /* auth failed ! */
1086 if (tracing)
1087 {
1088 printf("TRACING: Auth failed\n");
1089 }
1090
1091 if ( UP_remove_override_attr(object) )
1092 arg2 = rpsl_object_get_text(object,0);
1093 else
1094 {
1095 /* there was an override attr in this object and it has not been removed */
1096 arg2 = (char *)malloc(2);
1097 strcpy(arg2, ""); /* Don't include object in ack/notif msgs */
1098 }
1099
1100 AK_add_to_ack(ack_file_name, "\nUpdate FAILED: [%s] %s\nAuthorisation failed, request forwarded to maintainer.\n%s\n",
1101 type, get_search_key(object, type), arg2);
1102
1103 NT_write_all_frwds(old_version, arg, tmpdir, ntfy_hash, forw_hash, cross_hash, credentials.from);
1104
1105 rpsl_object_delete(old_obj);
1106 rpsl_object_delete(external_syntax_obj);
1107 rpsl_object_delete(object);
1108 free(old_version);
1109 free(external_syntax_results->new_obj);
1110 free(external_syntax_results);
1111 free(arg2);
1112 free(arg);
1113 return UP_AUF; /* Auth failed */
1114 }
1115
1116 }
1117 else
1118 { /* if the old and new versions of the object are the same */
1119 if (tracing)
1120 {
1121 printf("TRACING: The obj sent is identical to the one in the DB (NOOP)\n");
1122 }
1123
1124 AK_add_to_ack(ack_file_name, "\nUpdate NOOP: [%s] %s\n",
1125 type, get_search_key(object, type));
1126
1127 rpsl_object_delete(external_syntax_obj);
1128 rpsl_object_delete(object);
1129 free(old_version);
1130 free(external_syntax_results->new_obj);
1131 free(external_syntax_results);
1132 free(arg);
1133 return UP_OK;
1134 }
1135 }
1136 else
1137 { /* if there is an error in external syntax checks */
1138 if ( UP_remove_override_attr(object) )
1139 arg2 = rpsl_object_get_text(object,0);
1140 else
1141 {
1142 /* there was an override attr in this object and it has not been removed */
1143 arg2 = (char *)malloc(2);
1144 strcpy(arg2, ""); /* Don't include object in ack/notif msgs */
1145 }
1146
1147 AK_add_to_ack(ack_file_name, "\nUpdate FAILED: [%s] %s\n%s%s\n",
1148 type, get_search_key(object, type),
1149 arg2, external_syntax_results->error_str);
1150
1151 rpsl_object_delete(external_syntax_obj);
1152 rpsl_object_delete(object);
1153 free(old_version);
1154 free(external_syntax_results->new_obj);
1155 free(external_syntax_results);
1156 free(arg2);
1157 free(arg);
1158 return UP_SYN;
1159 }
1160 }
1161 else
1162 { /* if the user enforced creation (using NEW keyword) in the subject line */
1163 if ( UP_remove_override_attr(object) )
1164 arg2 = rpsl_object_get_text(object,0);
1165 else
1166 {
1167 /* there was an override attr in this object and it has not been removed */
1168 arg2 = (char *)malloc(2);
1169 strcpy(arg2, ""); /* Don't include object in ack/notif msgs */
1170 }
1171
1172 AK_add_to_ack(ack_file_name, "\nUpdate FAILED: [%s] %s\n%s\n"
1173 "***Error: Object already exists\n",
1174 type, get_search_key(object, type), arg2),
1175
1176 rpsl_object_delete(object);
1177 free(old_version);
1178 free(arg2);
1179 free(arg);
1180 return UP_INT;
1181
1182 }
1183 } /* end of this is an update operation */
1184 else
1185 { /* old_version == NULL, so, creation */
1186 external_syntax_obj = rpsl_object_copy(object);
1187 external_syntax_results = UP_check_external_syntax(external_syntax_obj);
1188 if ( external_syntax_results->result != UP_EXTSYN_ERR
1189 && external_syntax_results->result != UP_EXTSYN_ERR_WARN)
1190 {
1191 /* if there is no error */
1192 result = check_auth(object, NULL, type, credentials);
1193 if (result == UP_AUTH_OK)
1194 {
1195 if (tracing)
1196 {
1197 printf("TRACING: Will send the obj to be added\n");
1198 }
1199 /* if the object is a key-cert object, then we must import the PGP key */
1200 if ( strcmp(type, "key-cert") == 0 )
1201 {
1202 result_from_import_key = import_key(object);
1203 }
1204 else
1205 {
1206 result_from_import_key = NULL;
1207 }
1208 if (result_from_import_key == NULL)
1209 {
1210 /* no PGP problem */
1211 generated_obj = rpsl_object_copy(external_syntax_obj);
1212 if (strcasecmp(type, "key-cert") == 0)
1213 {
1214 /* if the object is a key-cert object */
1215 generated_obj_str = UP_generate_kc_attrs(generated_obj);
1216 free(external_syntax_results->new_obj);
1217 external_syntax_results->new_obj = generated_obj_str;
1218 }
1219 else if(strcasecmp(type, "inet6num") == 0)
1220 {
1221 /* if the object is an inet6num object */
1222 generated_obj_str = UP_generate_i6_attrs(generated_obj);
1223 free(external_syntax_results->new_obj);
1224 external_syntax_results->new_obj = generated_obj_str;
1225 }
1226 result_from_RIPupd = send_object_db(generated_obj, NULL, "ADD");
1227
1228 if (result_from_RIPupd->result == 0)
1229 {
1230 /* if there was no problem */
1231 AK_add_to_ack(ack_file_name, "\nNew OK: [%s] %s\n",
1232 type, get_search_key(object, type));
1233
1234 NT_write_all_ntfs(NULL, arg, external_syntax_results->new_obj, tmpdir,
1235 ntfy_hash, forw_hash, cross_hash, credentials.from);
1236
1237 rpsl_object_delete(generated_obj);
1238 rpsl_object_delete(external_syntax_obj);
1239 rpsl_object_delete(object);
1240 free(result_from_RIPupd);
1241 free(external_syntax_results->new_obj);
1242 free(external_syntax_results);
1243 free(arg);
1244 return UP_OK;
1245
1246 }
1247 else
1248 {
1249 AK_add_to_ack(ack_file_name, "\nNew FAILED: [%s] %s\n%s\n",
1250 type, get_search_key(object, type),
1251 result_from_RIPupd->error_str);
1252
1253 rpsl_object_delete(generated_obj);
1254 rpsl_object_delete(external_syntax_obj);
1255 rpsl_object_delete(object);
1256 free(result_from_RIPupd->error_str);
1257 free(result_from_RIPupd);
1258 free(external_syntax_results->new_obj);
1259 free(external_syntax_results);
1260 free(arg);
1261 return UP_INT;
1262 }
1263 }
1264 else
1265 {
1266 /* there was a problem with PGP key import */
1267 AK_add_to_ack(ack_file_name, "\nNew FAILED: [%s] %s\n%s\n",
1268 type, get_search_key(object, type),
1269 result_from_import_key);
1270
1271 rpsl_object_delete(external_syntax_obj);
1272 rpsl_object_delete(object);
1273 free(result_from_import_key);
1274 free(external_syntax_results->new_obj);
1275 free(external_syntax_results);
1276 free(arg);
1277 return UP_INT;
1278 }
1279 }
1280 else if (result == UP_FWD)
1281 {
1282 /* this was a maintainer or as-block creation request, so
1283 forward it to <HUMAILBOX> */
1284 if (tracing)
1285 {
1286 printf("TRACING: Maintainer or as-block or irt request will be forwarded to <HUMAILBOX>\n");
1287 }
1288
1289 if ( UP_remove_override_attr(object) )
1290 arg2 = rpsl_object_get_text(object,0);
1291 else
1292 {
1293 /* there was an override attr in this object and it has not been removed */
1294 arg2 = (char *)malloc(2);
1295 strcpy(arg2, ""); /* Don't include object in ack/notif msgs */
1296 }
1297
1298 AK_add_to_ack(ack_file_name, "\nNew FAILED: [%s] %s\n%s\n"
1299 "***Error: %s objects cannot be created automatically\n"
1300 "***Error: This object has been forwarded to %s\n"
1301 "***Error: for authorisation.\n"
1302 "***Error: No further action from your part is required\n",
1303 type, get_search_key(object, type),
1304 arg2, type, humailbox);
1305
1306 if ( ! strcmp(type, "mntner") )
1307 {
1308 header_type = strdup("Maintainer");
1309 text_type = strdup("maintainer");
1310 }
1311 else if ( ! strcmp(type, "as-block") )
1312 {
1313 header_type = strdup("as-block");
1314 text_type = strdup("as-block");
1315 }
1316 else if ( ! strcmp(type, "irt") )
1317 {
1318 header_type = strdup("irt");
1319 text_type = strdup("irt");
1320 }
1321 else
1322 {
1323 header_type = strdup("");
1324 text_type = strdup("");
1325 }
1326
1327 /* and forward this creation request to <HUMAILBOX> */
1328 NT_forw_create_req(external_syntax_results->new_obj);
1329
1330 rpsl_object_delete(external_syntax_obj);
1331 rpsl_object_delete(object);
1332 free(external_syntax_results->new_obj);
1333 free(external_syntax_results);
1334 free(arg2);
1335 free(arg);
1336 free(header_type);
1337 free(text_type);
1338 return UP_AUF;
1339 }
1340 else if (result == UP_HOF)
1341 {
1342 /* hierarchical authorisation failed */
1343 if (tracing)
1344 {
1345 printf("TRACING: Auth failed\n");
1346 }
1347
1348 if ( UP_remove_override_attr(object) )
1349 arg2 = rpsl_object_get_text(object,0);
1350 else
1351 {
1352 /* there was an override attr in this object and it has not been removed */
1353 arg2 = (char *)malloc(2);
1354 strcpy(arg2, ""); /* Don't include object in ack/notif msgs */
1355 }
1356
1357 AK_add_to_ack(ack_file_name, "\nNew FAILED: [%s] %s\nHierarchical authorisation failed, request forwarded to maintainer.\n%s\n",
1358 type, get_search_key(object, type), arg2);
1359
1360 NT_write_all_frwds(NULL, arg, tmpdir, ntfy_hash, forw_hash, cross_hash, credentials.from);
1361
1362 rpsl_object_delete(external_syntax_obj);
1363 rpsl_object_delete(object);
1364 free(external_syntax_results->new_obj);
1365 free(external_syntax_results);
1366 free(arg2);
1367 free(arg);
1368 return UP_AUF;
1369 }
1370 else
1371 {
1372 /* auth failed ! */
1373 if (tracing)
1374 {
1375 printf("TRACING: Auth failed\n");
1376 }
1377
1378 if ( UP_remove_override_attr(object) )
1379 arg2 = rpsl_object_get_text(object,0);
1380 else
1381 {
1382 /* there was an override attr in this object and it has not been removed */
1383 arg2 = (char *)malloc(2);
1384 strcpy(arg2, ""); /* Don't include object in ack/notif msgs */
1385 }
1386
1387 AK_add_to_ack(ack_file_name, "\nNew FAILED: [%s] %s\nAuthorisation failed, request forwarded to maintainer.\n%s\n",
1388 type, get_search_key(object, type), arg2);
1389
1390 NT_write_all_frwds(NULL, arg, tmpdir, ntfy_hash, forw_hash, cross_hash, credentials.from);
1391
1392 rpsl_object_delete(external_syntax_obj);
1393 rpsl_object_delete(object);
1394 free(external_syntax_results->new_obj);
1395 free(external_syntax_results);
1396 free(arg2);
1397 free(arg);
1398 return UP_AUF; /* Auth failed */
1399 }
1400 }
1401 else
1402 {
1403 if ( UP_remove_override_attr(object) )
1404 arg2 = rpsl_object_get_text(object,0);
1405 else
1406 {
1407 /* there was an override attr in this object and it has not been removed */
1408 arg2 = (char *)malloc(2);
1409 strcpy(arg2, ""); /* Don't include object in ack/notif msgs */
1410 }
1411
1412 AK_add_to_ack(ack_file_name, "\nNew FAILED: [%s] %s\n%s%s\n",
1413 type, get_search_key(object, type),
1414 arg2, external_syntax_results->error_str);
1415
1416 rpsl_object_delete(external_syntax_obj);
1417 rpsl_object_delete(object);
1418 free(external_syntax_results->new_obj);
1419 free(external_syntax_results);
1420 free(arg2);
1421 free(arg);
1422 return UP_SYN;
1423 }
1424 } /* end of creation */
1425 } /* end of process object without an AUTO NIC hdl */
1426 } /* end of the object is _not_ to be deleted */
1427 } /* end of parsed with no systax errors */
1428 else
1429 {
1430 /* even if obj doesn't parse properly, it may be a legacy object
1431 which the user wants to delete... */
1432 if (tracing)
1433 {
1434 printf("TRACING: Object didn't parse, check for legacy object deletion\n");
1435 }
1436 /* if it is for deletion */
1437 if (rpsl_object_is_deleted(object))
1438 {
1439 /* here delete it */
1440 type = rpsl_object_get_class(object);
1441 old_version = get_old_version(object, arg);
1442
1443 if (tracing)
1444 {
1445 printf("TRACING: old_version: [\n%s]\n arg: [\n%s]\n", old_version, arg);
1446 }
1447
1448 if (old_version == NULL)
1449 {
1450 /* the object doesn't exist in the db! */
1451 free(arg);
1452 if ( UP_remove_override_attr(object) )
1453 arg = rpsl_object_get_text(object,0);
1454 else
1455 {
1456 /* there was an override attr in this object and it has not been removed */
1457 arg = (char *)malloc(2);
1458 strcpy(arg, ""); /* Don't include object in ack/notif msgs */
1459 }
1460
1461 AK_add_to_ack(ack_file_name, "\nDelete FAILED: [%s] %s\n***Error: Entry not found\n\n%s\n",
1462 type, get_search_key(object, type), arg);
1463
1464 rpsl_object_delete(object);
1465 free(arg);
1466 return UP_NSO; /* no such object */
1467 }
1468 else
1469 {
1470
1471 if (tracing)
1472 {
1473 printf("TRACING: legacy object is in the database\n");
1474 }
1475
1476 /* the object is in the db */
1477 if ( identical(old_version, object) )
1478 {
1479 /* if the old & new versions are identical */
1480
1481 if (tracing)
1482 {
1483 printf("TRACING: old & new versions are identical\n");
1484 }
1485 result = check_auth(NULL, object, type, credentials);
1486 if (result == UP_AUTH_OK)
1487 {
1488 if (tracing)
1489 {
1490 printf("TRACING: Will send the obj to be deleted\n");
1491 }
1492 if (strcmp(type, "key-cert") == 0)
1493 {
1494 result_from_delete_key = delete_key(object);
1495 }
1496 else
1497 {
1498 result_from_delete_key = NULL;
1499 }
1500 /* if there was no problem with key deletion from the key-ring */
1501 if (result_from_delete_key == NULL)
1502 {
1503 result_from_RIPupd = send_object_db(object, NULL, "DEL");
1504 if (result_from_RIPupd->result == 0)
1505 {
1506 AK_add_to_ack(ack_file_name, "\nDelete OK: [%s] %s\n",
1507 type, get_search_key(object, type));
1508 NT_write_all_ntfs(old_version, NULL, NULL, tmpdir, ntfy_hash, forw_hash, cross_hash,
1509 credentials.from);
1510
1511 rpsl_object_delete(object);
1512 free(result_from_RIPupd);
1513 free(arg);
1514 free(old_version);
1515 return UP_OK;
1516 }
1517 else
1518 {
1519 AK_add_to_ack(ack_file_name, "\nDelete FAILED: [%s] %s\n%s\n",
1520 type, get_search_key(object, type),
1521 result_from_RIPupd->error_str);
1522
1523 rpsl_object_delete(object);
1524 free(result_from_RIPupd->error_str);
1525 free(result_from_RIPupd);
1526 free(arg);
1527 free(old_version);
1528 return UP_INT;
1529 }
1530 }
1531 else
1532 {
1533 AK_add_to_ack(ack_file_name, "\nDelete FAILED: [%s] %s\n%s\n",
1534 type, get_search_key(object, type), result_from_delete_key);
1535
1536 rpsl_object_delete(object);
1537 free(arg);
1538 free(old_version);
1539 free(result_from_delete_key);
1540 return UP_INT;
1541 }
1542 }
1543 else
1544 { /* auth failed */
1545 if (tracing)
1546 {
1547 printf("TRACING: Auth failed\n");
1548 }
1549
1550 if ( UP_remove_override_attr(object) )
1551 arg2 = rpsl_object_get_text(object,0);
1552 else
1553 {
1554 /* there was an override attr in this object and it has not been removed */
1555 arg2 = (char *)malloc(2);
1556 strcpy(arg2, ""); /* Don't include object in ack/notif msgs */
1557 }
1558
1559 AK_add_to_ack(ack_file_name, "\nDelete FAILED: [%s] %s\nAuthorisation failed, request forwarded to maintainer.\n%s\n",
1560 type, get_search_key(object, type), arg2);
1561 NT_write_all_frwds(arg, NULL, tmpdir, ntfy_hash, forw_hash, cross_hash, credentials.from);
1562
1563 rpsl_object_delete(object);
1564 free(arg2);
1565 free(arg);
1566 free(old_version);
1567 return UP_AUF; /* Auth failed */
1568 }
1569 } /* end of identical match */
1570 else
1571 {
1572 /* the new & old versions do not match */
1573 if ( UP_remove_override_attr(object) )
1574 arg2 = rpsl_object_get_text(object,0);
1575 else
1576 {
1577 /* there was an override attr in this object and it has not been removed */
1578 arg2 = (char *)malloc(2);
1579 strcpy(arg2, ""); /* Don't include object in ack/notif msgs */
1580 }
1581
1582 AK_add_to_ack(ack_file_name, "\nDelete FAILED: [%s] %s \n***Error: new & old versions do not match\n%s\n",
1583 type, get_search_key(object, type), arg2);
1584
1585 rpsl_object_delete(object);
1586 free(arg2);
1587 free(arg);
1588 free(old_version);
1589 return UP_NOM; /* new & old versions do not match */
1590 }
1591 } /* end of the object is in the db */
1592 } /* end of the object is to be deleted */
1593 else
1594 {
1595 /* syntax error AND not deletion */
1596 noclass = 0;
1597 for ( error_list_item = error_list; error_list_item != NULL; error_list_item = g_list_next(error_list_item) )
1598 {
1599 ecode = ((rpsl_error_t *)(error_list_item->data))->code;
1600 if ( ecode == RPSL_ERR_ONLYCOMMENTS || ecode == RPSL_ERR_BADCLASS
1601 || ecode == RPSL_ERR_BADCLASS )
1602 {
1603 noclass = 1;
1604 break;
1605 }
1606 }
1607 if ( UP_remove_override_attr(object) )
1608 arg2 = rpsl_object_get_text(object,0);
1609 else
1610 {
1611 /* there was an override attr in this object and it has not been removed */
1612 arg2 = (char *)malloc(2);
1613 strcpy(arg2, ""); /* Don't include object in ack/notif msgs */
1614 }
1615
1616 /* if ( ! noclass )
1617 {
1618 type = rpsl_object_get_class(object);
1619 key = get_search_key(object, type);
1620 AK_add_to_ack(ack_file_name, "\nUpdate FAILED: [%s] %s \n***Error: Syntax error in object\n",
1621 type, key ? key : "" );
1622 }
1623 else */
1624 AK_add_to_ack(ack_file_name, "\nUpdate FAILED: Syntax error in object\n");
1625
1626 if ( rpsl_object_has_error(object, RPSL_ERRLVL_CRIT) )
1627 {
1628 /* object not parsed so print out text version of object rather than attributes */
1629 AK_add_to_ack(ack_file_name, "%s\n", arg);
1630 }
1631 else
1632 {
1633 /* add attributes along with any attribute error messages */
1634 attr_list = rpsl_object_get_all_attr(object);
1635 for ( attr_list_item = attr_list; attr_list_item != NULL; attr_list_item = g_list_next(attr_list_item) )
1636 {
1637 name = rpsl_attr_get_name( (rpsl_attr_t *)(attr_list_item->data) );
1638 if ( strcasecmp(name, "override") != 0 )
1639 {
1640 /* don't include the override attibute, but still include override error messages */
1641 value = rpsl_attr_get_value( (rpsl_attr_t *)(attr_list_item->data) );
1642 attribute = (char *)malloc( strlen(name) + strlen(value) + 3);
1643 sprintf(attribute, "%s: %s", name, value);
1644 AK_add_to_ack(ack_file_name, "%s\n", attribute);
1645 free(attribute);
1646 }
1647 attr_error_list = rpsl_attr_errors( (rpsl_attr_t *)(attr_list_item->data) );
1648 for ( attr_error_list_item = attr_error_list; attr_error_list_item != NULL; attr_error_list_item = g_list_next(attr_error_list_item) )
1649 {
1650 if ( ((rpsl_error_t *)(attr_error_list_item->data))->level > RPSL_ERRLVL_DEBUG )
1651 AK_add_to_ack(ack_file_name, "***Error: %s\n", ((rpsl_error_t *)(attr_error_list_item->data))->descr);
1652 }
1653 }
1654 }
1655
1656 /* now add any object level error messages */
1657 error_list = rpsl_object_errors(object);
1658 for ( error_list_item = error_list; error_list_item != NULL; error_list_item = g_list_next(error_list_item) )
1659 {
1660 if ( ((rpsl_error_t *)(error_list_item->data))->level > RPSL_ERRLVL_DEBUG &&
1661 ((rpsl_error_t *)(error_list_item->data))->code != RPSL_ERR_BADATTR )
1662 {
1663 AK_add_to_ack(ack_file_name, "***Error: %s\n", ((rpsl_error_t *)(error_list_item->data))->descr);
1664 }
1665 }
1666
1667 AK_add_to_ack(ack_file_name, "\n");
1668
1669 rpsl_object_delete(object);
1670 free(arg);
1671 return UP_SYN; /* syntax error */
1672 }
1673 }
1674 }
1675
1676
1677
1678
1679
1680 /* processes the objects in the given file */
1681 void process_file(char * filename, credentials_struct credentials,
/* [<][>][^][v][top][bottom][index][help] */
1682 GHashTable * AUTO_NIC_hdl_hash, char * ack_file_name,
1683 GHashTable * ntfy_hash, GHashTable * forw_hash, GHashTable * cross_hash)
1684 {
1685 FILE * input_file;
1686 GSList *list_of_objects = NULL, *list_of_objects2 = NULL;
1687 GSList *next = NULL;
1688 int object_count = 0;
1689 char *object = NULL;
1690 char * line;
1691 char * lwrcase_line;
1692 int result = 0;
1693 rpsl_object_t *obj = NULL;
1694 const GList * error_list = NULL;
1695
1696
1697 line = (char *)malloc(1024);
1698
1699 if ((input_file = fopen(filename, "r")) == NULL)
1700 {
1701 ER_perror(FAC_UP, UP_CANTOPEN, "Couldn't open the file %s: %s\n", filename, strerror(errno));
1702 exit(1);
1703 }
1704
1705 while (fgets(line, 1024, input_file) != NULL)
1706 {
1707 /* first, if it is a pasword, save it, but do not regard it as an attrib */
1708 lwrcase_line = strdup(line);
1709 g_strdown(lwrcase_line);
1710 if (strstr(lwrcase_line, "password:") == lwrcase_line)
1711 {
1712 if (tracing)
1713 {
1714 printf("TRACING: This is a password\n");
1715 }
1716 credentials.password_list = g_slist_append(credentials.password_list,
1717 g_strstrip(strdup(line + strlen("password:"))));
1718 free(lwrcase_line);
1719 continue;
1720 }
1721 free(lwrcase_line);
1722
1723 line = UP_remove_EOLs(line); /* remove '\n's and '\r' first */
1724 /* remove trailing white space */
1725 line = g_strchomp(line);
1726 if (strlen(line) == 0)
1727 {
1728 /* then, this was an empty line */
1729 if (object != NULL)
1730 {
1731 list_of_objects = g_slist_append(list_of_objects, object);
1732 if (tracing)
1733 {
1734 printf("TRACING: added an object: [%s]\n", object);
1735 }
1736 object = NULL;
1737 }
1738 }
1739 else
1740 {
1741 if (object == NULL && strlen(line) != 0)
1742 {
1743 object = (char *)malloc(strlen(line) + 2);
1744 object = strcpy(object, line);
1745 object = strcat(object, "\n"); /* add EOL again (we removed it before) */
1746 }
1747 else
1748 {
1749 object = (char *)realloc(object, strlen(object) + strlen(line) + 2);
1750 object = strcat(object, line);
1751 object = strcat(object, "\n");
1752 }
1753 }
1754
1755 }
1756 fclose(input_file);
1757 free(line);
1758
1759 /* now, if at the very and of the input file there wasn't an
1760 empty line, we have to add the remaining object in the 'object'
1761 variable */
1762 if (object != NULL)
1763 {
1764 list_of_objects = g_slist_append(list_of_objects, object);
1765 object = NULL;
1766 }
1767
1768
1769 if (tracing)
1770 {
1771 printf("TRACING: Will process the objects in the list\n");
1772 }
1773 next = list_of_objects;
1774 object_count = 0;
1775 for ( next = list_of_objects; next != NULL ; next = g_slist_next(next) )
1776 {
1777 if (UP_is_object((char *)next->data))
1778 {
1779 /* if this looks like an object */
1780
1781 object_count++;
1782 if(tracing)
1783 {
1784 printf("TRACING: Got an object from the list\n");
1785 printf("[%s]\n", (char *)next->data );
1786 }
1787
1788 obj = rpsl_object_init( (char *)next->data );
1789 error_list = rpsl_object_errors(obj);
1790
1791 if ( ! rpsl_object_has_error(obj, RPSL_ERRLVL_ERROR) && has_ref_to_AUTO_nic_hdl(obj) )
1792 {
1793 /* if object has a reference to an auto- nichdl and no syntax errors
1794 then defer the processing to allow the auto- nichdl to be created first */
1795 if(tracing)
1796 {
1797 printf("TRACING: this object has a ref to an AUTO NIC hdl\n");
1798 }
1799 list_of_objects2 = g_slist_append(list_of_objects2, strdup((char *)next->data));
1800 }
1801 else
1802 {
1803 result = 0;
1804 result = process_object((char *)next->data, credentials, AUTO_NIC_hdl_hash, ack_file_name,
1805 ntfy_hash, forw_hash, cross_hash);
1806 /* keep a tally */
1807 if (result == UP_NOOBJECT)
1808 {
1809 /* do nothing and don't increment any counts */
1810 }
1811 else if (result == UP_OK)
1812 {
1813 count_successful++;
1814 }
1815 else
1816 {
1817 count_unsuccessful++;
1818 }
1819 }
1820
1821 rpsl_object_delete(obj);
1822 }
1823 else
1824 {
1825 /* this does not look like an object (a signature? some other text?) */
1826
1827 AK_add_to_ack(ack_file_name, "\nThe following paragraph does not look like an object,\n"
1828 "so ignoring it:\n%s\n", (char *)next->data);
1829 }
1830 }
1831
1832
1833 if (tracing)
1834 {
1835 printf("TRACING: list_of_objects2 has %d entries\n", g_slist_length(list_of_objects2));
1836 printf("TRACING: will start to process the second list\n");
1837 }
1838
1839 for ( next = list_of_objects2; next != NULL ; next = g_slist_next(next) )
1840 {
1841 if (tracing)
1842 {
1843 printf("TRACING: Will process object: %s\n", (char *)next->data);
1844 }
1845 result = process_object((char *)next->data, credentials, AUTO_NIC_hdl_hash, ack_file_name,
1846 ntfy_hash, forw_hash, cross_hash);
1847 /* keep a tally */
1848 if (result == UP_NOOBJECT)
1849 {
1850 /* do nothing and don't increment any counts */
1851 }
1852 else if (result == UP_OK)
1853 {
1854 count_successful++;
1855 }
1856 else
1857 {
1858 count_unsuccessful++;
1859 }
1860 }
1861 }/* process_file */
1862
1863
1864
1865
1866 /* Generates a unique file name and returns the full path of the filename
1867 for storing notification message. */
1868
1869 char * generate_upd_file()
/* [<][>][^][v][top][bottom][index][help] */
1870 {
1871 char * name;
1872
1873 /* allocate space for name. 32 should be enough for PID */
1874 name = (char*)malloc(strlen(tmpdir) + strlen("/dbupdate-tmp.") + 34 );
1875
1876 sprintf(name, "%s/dbupdate-tmp.%i", tmpdir, pid /*getpid()*/);
1877
1878 return name;
1879 }
1880
1881
1882 /* create_lock_file: creates a lock file in lockdir and locks it. This is a
1883 part of crash recovery. Must be called in the beginning of the run. At the
1884 end, the file must be removed. */
1885 /* The idea: Create the "lock" file, and lock it. When another process starts
1886 running, it checks the existing lock files. If some exists, then it checks
1887 if it is locked or not. It not locked, then assumes that the corresponding
1888 dbupdate is alredy running. If not locked, assumes that it has crashed.
1889 (note: when a process crashes, the kernel releases all the files locked by
1890 this process [by the OS])
1891 Problem: locking doesn't work properly on some NFS implementations. */
1892
1893 lockfilestruct create_lock_file(){
/* [<][>][^][v][top][bottom][index][help] */
1894
1895 lockfilestruct lock;
1896 int file;
1897 int length;
1898
1899 /* allocate space for file name */
1900 length = strlen(lockdir) + strlen(hostname) + 32;
1901 lock.lockname = (char *)malloc(length + 1);
1902
1903 snprintf(lock.lockname, length, "%s/dbupdate.%s.%ld", lockdir, hostname, pid /*getpid()*/);
1904
1905 /* we will lock the file, so we have to use open(), but not fopen() (see man
1906 page of lockf(3C)) */
1907 if(( file = open(lock.lockname, O_RDWR|O_CREAT)) == -1){
1908 ER_perror(FAC_UP, UP_CANTOPEN, "Can't open lock file, %s", lock.lockname);
1909 exit(1);
1910 }
1911
1912 if(lockf(file, F_LOCK, 0) == -1){
1913 ER_perror(FAC_UP, UP_CANTLOCK, "Can't lock the file, %s", lock.lockname);
1914 exit(1);
1915 };
1916
1917 lock.filedes = file;
1918
1919 return lock;
1920
1921 }
1922
1923
1924
1925
1926
1927 /* remove_lock_file(): unlocks and removes the file */
1928 void remove_lock_file(lockfilestruct lockfile){
/* [<][>][^][v][top][bottom][index][help] */
1929
1930 close(lockfile.filedes); /* this will remove the lock at the same time */
1931 unlink(lockfile.lockname);
1932
1933 }
1934
1935
1936
1937 /* writes the checkpoint file with the specified state */
1938 void write_checkpoint(int state){
/* [<][>][^][v][top][bottom][index][help] */
1939
1940 char * filename;
1941 char * tmpfilename;
1942 int length;
1943 FILE * file;
1944
1945 if(tracing){
1946 printf("TRACING: write_checkpoint, state=[%i]\n", state);
1947 }
1948 length = strlen(lockdir) + strlen(hostname) + 64;
1949 filename = (char *)malloc(length + 1);
1950 tmpfilename = (char *)malloc(length + 5);
1951
1952 snprintf(filename, length, "%s/dbupdate.checkpoint.%s.%ld", lockdir, hostname, pid );
1953 snprintf(tmpfilename, length, "%s/dbupdate.checkpoint.%s.%ld.tmp", lockdir, hostname, pid );
1954
1955 if(( file = fopen(tmpfilename, "w")) == NULL){
1956 /* fprintf(stderr, "Can't open temp checkpoint file, %s", tmpfilename); */
1957 ER_perror(FAC_UP, UP_CANTOPEN, "Can't open temp checkpoint file, %s", tmpfilename);
1958 exit(1);
1959 }
1960
1961 fprintf(file, "[STATE]\n%i\n", state);
1962
1963 fprintf(file, "[FLAGS]\n");
1964 /* should print the flags here */
1965
1966 fprintf(file, "[PARTS]\n");
1967 /* should print the parts (filenames) here */
1968
1969 fprintf(file, "[OBJECTS1]\n");
1970
1971 fprintf(file, "[OBJECTS2]\n");
1972
1973 fprintf(file, "[ACKFILE]\n");
1974
1975 fprintf(file, "[NOTIFFILES]\n");
1976
1977 fprintf(file, "[TIDS1]\n");
1978
1979 fprintf(file, "[TIDS2]\n");
1980
1981 fprintf(file, "[NICHDLHASH]\n");
1982
1983 fprintf(file, "[CURRENTOBJECT]\n");
1984
1985 fprintf(file, "[CURRENTPART]\n");
1986
1987
1988 fclose(file);
1989
1990 rename(tmpfilename, filename);
1991
1992 /* free the char *'s */
1993 free(tmpfilename);
1994 free(filename);
1995
1996 }
1997
1998
1999
2000
2001 /* removes check point file */
2002 void remove_checkpoint(){
/* [<][>][^][v][top][bottom][index][help] */
2003
2004 char * filename;
2005 int length;
2006
2007 if(tracing){
2008 printf("TRACING: remove_checkpoint\n");
2009 }
2010
2011 length = strlen(lockdir) + strlen(hostname) + 64;
2012 filename = (char *)malloc(length + 1);
2013
2014 snprintf(filename, length, "%s/dbupdate.checkpoint.%s.%ld", lockdir, hostname, pid );
2015
2016 unlink(filename);
2017
2018 /* free the char * */
2019 free(filename);
2020
2021 }
2022
2023
2024
2025
2026 /* main */
2027 int main(int argc, char **argv, char **envp){
/* [<][>][^][v][top][bottom][index][help] */
2028 /* init_and_set_options(argc, argv, envp); */
2029
2030 int i,j;
2031 char ** temp_vector;
2032 char * temp;
2033 char * temp_upd_file = NULL;
2034 char *input_file_name = NULL;
2035 GHashTable *AUTO_NIC_hdl_hash;
2036 credentials_struct credentials;
2037 FILE * upd_file;
2038 char c;
2039 char * mheader_replaced = NULL;
2040 char * mailtxt_replaced = NULL;
2041
2042 /* temp variables to read from conf */
2043 ca_updDbSource_t *upd_source_hdl;
2044
2045 GHashTable *ntfy_hash, *forw_hash, *cross_hash;
2046
2047
2048 char * ack_file_name;
2049 char *config_file_name = NULL;
2050
2051
2052 /* to use EP module */
2053 EP_Mail_DescrPtr p;
2054 EPTokenPtr pt;
2055 EPTokenPtr list_item;
2056 EPTokenKeysPtr ptk;
2057
2058 char * temp_keyid;
2059
2060 /* a variable to be used to know if the part is pgp_signed or not */
2061 int pgp_signed = 0;
2062
2063 int ch;
2064 char * to_address = NULL;
2065 char * subject = NULL;
2066 char * reply_to = NULL;
2067
2068
2069 /* create notification hashes */
2070 ntfy_hash = g_hash_table_new(g_str_hash, g_str_equal);
2071 forw_hash = g_hash_table_new(g_str_hash, g_str_equal);
2072 cross_hash = g_hash_table_new(g_str_hash, g_str_equal);
2073
2074 credentials.password_list = NULL;
2075 credentials.from = NULL;
2076
2077 AUTO_NIC_hdl_hash = g_hash_table_new(g_str_hash, g_str_equal);
2078
2079 /* initialise the rpsl dictionary */
2080 rpsl_load_dictionary(RPSL_DICT_FRONT_END);
2081
2082 while ((ch = getopt(argc, argv, "MtSTf:c:sn")) != -1){
2083 switch(ch) {
2084 case 'M':
2085 reading_from_mail = 1;
2086 break;
2087 case 'f':
2088 input_file_name = strdup(optarg);
2089 break;
2090 case 'c':
2091 config_file_name = strdup(optarg);
2092 break;
2093 case 't':
2094 tracing = 1;
2095 break;
2096 /* Test mode? In test mode, creation of mntners and as-blocks is possible, without overriding */
2097 case 'T':
2098 test_mode = 1;
2099 break;
2100 /* Supress acks and notifications? If yes, the acks and notifs will go to DEFMAIL config var */
2101 case 'S':
2102 supress_ack_notif = 1;
2103 break;
2104 /* Print out the ack to stdout? */
2105 case 's':
2106 print_out_ack = 1;
2107 break;
2108 /* are we processing networkupdate? (invoked via inetd) */
2109 case 'n':
2110 networkupdate = 1;
2111 break;
2112 case '?':
2113 default:
2114 printf("Unknown option\n"); exit(1);
2115 }
2116 }
2117
2118
2119 /* config stuff */
2120 /* if -c flag is given, use the named file as config file, otherwise use
2121 default filename */
2122 if ( config_file_name != NULL)
2123 {
2124 /*ca_readConfig(config_file_name, confVars, VARS);*/
2125 ca_init(config_file_name);
2126 free(config_file_name);
2127 }
2128 else
2129 {
2130 /*ca_readConfig("dbupdate.conf", confVars, VARS);*/
2131 ca_init("dbupdate.conf");
2132 }
2133
2134 error_init(argc, argv);
2135
2136
2137 tmpdir = ca_get_tmpdir;
2138 tmpdir = g_strstrip(tmpdir);
2139 lockdir = ca_get_lockdir;
2140 mailcmd = ca_get_mailcmd;
2141 mailcmd = g_strstrip(mailcmd);
2142 notitxt = ca_get_notitxt;
2143 mailtxt = ca_get_mailtxt;
2144 successtxt = ca_get_successtxt;
2145 failuretxt = ca_get_failuretxt;
2146 helpheader = ca_get_helpheader;
2147 defmail = ca_get_defmail; defmail = UP_remove_EOLs(defmail);
2148 crosslog = ca_get_crosslog;
2149 fwtxt = ca_get_fwtxt;
2150 acksig = ca_get_acksig;
2151 humailbox = ca_get_humailbox;
2152 humailbox = g_strstrip(humailbox);
2153 autobox = ca_get_autobox;
2154 overridecryptedpw = ca_get_overridecryptedpw;
2155 overridecryptedpw = g_strstrip(overridecryptedpw);
2156 updlog = ca_get_updlog;
2157 acklog = ca_get_acklog;
2158 notiflog = ca_get_notiflog;
2159 notimailtxt = ca_get_notimailtxt;
2160 notinetworktxt = ca_get_notinetworktxt;
2161 forwlog = ca_get_forwlog;
2162 fwmailtxt = ca_get_fwmailtxt;
2163 mtfwheader = ca_get_mtfwheader;
2164 mtfwtxt = ca_get_mtfwtxt;
2165 country = ca_get_country;
2166 pgppath = ca_get_pgppath;
2167 gpgcmd = ca_get_gpgcmd;
2168 autodbmhelp = ca_get_autodbmhelp;
2169 allocmnt = ca_get_allocmnt; allocmnt = UP_remove_EOLs(allocmnt);
2170 /* convert all '\t's, '\n's and '\r's in allocmnt to white spaces */
2171 for(i=0;i<strlen(allocmnt);i++){
2172 if(allocmnt[i] == '\r' || allocmnt[i] == '\n' || allocmnt[i] == '\t'){
2173 allocmnt[i] = ' ';
2174 }
2175 }
2176 cn_subject_add = ca_get_cn_subject_add; cn_subject_add = UP_remove_EOLs(cn_subject_add);
2177 cn_subject_del = ca_get_cn_subject_del; cn_subject_del = UP_remove_EOLs(cn_subject_del);
2178 cn_explain_add = ca_get_cn_explain_add;
2179 cn_explain_del = ca_get_cn_explain_del;
2180 cn_overlap_add = ca_get_cn_overlap_add;
2181 cn_overlap_del = ca_get_cn_overlap_del;
2182 cno_subject_add = ca_get_cno_subject_add; cno_subject_add = UP_remove_EOLs(cno_subject_add);
2183 cno_subject_del = ca_get_cno_subject_del; cno_subject_del = UP_remove_EOLs(cno_subject_del);
2184 cno_explain_add = ca_get_cno_explain_add;
2185 cno_explain_del = ca_get_cno_explain_del;
2186 cno_overlap_add = ca_get_cno_overlap_add;
2187 cno_overlap_del = ca_get_cno_overlap_del;
2188 copyright_notice = ca_get_pw_resp_header;
2189 mheader = ca_get_mheader;
2190 pgp_public_key_ring = (char *)malloc(strlen(pgppath) + strlen("/pubring.gpg") + 2);
2191 sprintf(pgp_public_key_ring ,"%s/pubring.gpg", pgppath);
2192 if(test_mode != 1){/* if it is not already set to 1 (from command line), read from config */
2193
2194 test_mode = ca_get_testmode;
2195 }
2196 /* retrieve source variables */
2197 upd_source_hdl = ca_get_UpdSourceHandle(CA_UPDSOURCE);
2198
2199 if(upd_source_hdl == NULL){
2200 printf("There must be one updateable source in the config file. Exiting.\n");
2201 ER_perror(FAC_UP, UP_CONFERR, "There must be one updateable source in"
2202 " the config file. Exiting.");
2203 exit(1);
2204 }else{
2205 if(tracing){
2206 printf("\nTRACING: The upd_source_hdl is: %s\n", upd_source_hdl->name);
2207 }
2208 sources[0] = strdup(upd_source_hdl->name);
2209 update_host = upd_source_hdl->whoisd_host;
2210 query_host = strdup(update_host);
2211 update_port = upd_source_hdl->updPort;
2212 query_port = upd_source_hdl->qryPort;
2213 DBhost = upd_source_hdl->updDb.host;
2214 DBport = upd_source_hdl->updDb.port;
2215 DBname = upd_source_hdl->updDb.dbName;
2216 DBuser = upd_source_hdl->updDb.user;
2217 DBpasswd = upd_source_hdl->updDb.password;
2218 }
2219
2220
2221 /* construct country array from country string variable */
2222
2223 temp_vector = g_strsplit(country, "\n", 0);
2224 for (i=0, j=0; temp_vector[i] != NULL; i++)
2225 {
2226 temp_vector[i] == g_strstrip(temp_vector[i]);
2227 if (strlen(temp_vector[i]) > 0)
2228 {
2229 countries[j] = strdup(temp_vector[i]);
2230 g_strup(countries[j++]);
2231 }
2232 }
2233 countries[j] = NULL; /* mark the end of array */
2234 g_strfreev(temp_vector);
2235 if (tracing)
2236 {
2237 printf("TRACING: number of countries [%i]\n", j);
2238 }
2239
2240 /* hard code the nicsuffixes for now, but should be a configurable variable */
2241
2242 nicsuffixes[0] = strdup("RIPE");
2243 nicsuffixes[1] = strdup("ORG");
2244 nicsuffixes[2] = strdup("ARIN");
2245 nicsuffixes[3] = strdup("RADB");
2246 nicsuffixes[4] = strdup("APNIC");
2247 nicsuffixes[5] = strdup("RIPN");
2248 nicsuffixes[6] = NULL;
2249
2250 if (tracing)
2251 {
2252 /* print out the config variables for debugging */
2253 printf("TMPDIR is: [%s]\n", tmpdir);
2254 printf("MAILCMD is: [%s]\n", mailcmd);
2255 printf("NOTITXT is: [%s]\n", notitxt);
2256 printf("CROSSLOG is: [%s]\n", crosslog);
2257 printf("FWTXT is: [%s]\n", fwtxt);
2258 printf("HUMAILBOX is: [%s]\n", humailbox);
2259 printf("AUTOBOX is: [%s]\n", autobox);
2260 printf("OVERRIDECRYPTEDPW is: [%s]\n", overridecryptedpw);
2261 printf("ACKLOG is: [%s]\n", acklog);
2262 printf("NOTIFLOG is: [%s]\n", notiflog);
2263 printf("FORWLOG is: [%s]\n", forwlog);
2264 printf("NOTIMAILTXT is: [%s]\n", notimailtxt);
2265 printf("FWMAILTXT is: [%s]\n", fwmailtxt);
2266 /* printf("COUNTRY is: [%s]\n", country); */
2267 printf("PGPPATH is: [%s]\n", pgppath);
2268 printf("UPDATE_HOST is: [%s]\n", update_host);
2269 printf("UPDATE_PORT is: [%i]\n", update_port);
2270 printf("QUERY_HOST is: [%s]\n", query_host);
2271 printf("QUERY_PORT is: [%i]\n", query_port);
2272 printf("LOCKDIR is: [%s]\n", lockdir);
2273 printf("TESTMODE is: [%i]\n", test_mode);
2274 printf("CNO_SUBJECT_ADD is: [%s]\n", cno_subject_add);
2275 printf("CNO_SUBJECT_DEL is: [%s]\n", cno_subject_del);
2276 }
2277 /* end of config stuff */
2278
2279
2280 /* set hostname global variable */
2281 gethostname(hostname, MAXHOSTNAMELEN);
2282
2283 /* set pid global variable */
2284 pid = getpid();
2285
2286 /* create the lock file and lock it */
2287 /* lockfile = create_lock_file(); */
2288
2289 /* initialize the parser */
2290 /* schema.initialize(); */
2291
2292
2293 /* Generate a name for temporary file for storing acks (AK_ack_file_name_generate
2294 also creates it) */
2295 ack_file_name = AK_ack_file_name_generate(tmpdir, ACK_FILE_PREFIX);
2296
2297 /* initialize credentials.pgp_key_list */
2298 credentials.pgp_key_list = NULL;
2299
2300
2301
2302 if (reading_from_mail)
2303 {
2304 if (input_file_name != NULL)
2305 {
2306 temp_upd_file = generate_upd_file();
2307 if (tracing)
2308 {
2309 printf("TRACING: temp_upd_file is [%s]\n", temp_upd_file);
2310 }
2311
2312 /* first log the input in the upd log file */
2313 UP_add_to_upd_log(input_file_name);
2314
2315
2316 MM_store(input_file_name, temp_upd_file, 0);
2317 p = EP_ParseMail(input_file_name, tmpdir, pgp_public_key_ring, gpgcmd);
2318
2319 }
2320 else
2321 { /* input_file_name == NULL */
2322 temp_upd_file = generate_upd_file();
2323 MM_store("-", temp_upd_file, 0);
2324
2325 /* first log the input in the upd log file */
2326 UP_add_to_upd_log(temp_upd_file);
2327
2328 p = EP_ParseMail(temp_upd_file, tmpdir, pgp_public_key_ring, gpgcmd);
2329
2330 }
2331
2332 /* write off the checkpoint file */
2333 write_checkpoint(1);
2334
2335 /* the new stuff using the EP module's interface */
2336
2337 if(p->from != NULL && p->from->field != NULL)
2338 {
2339 credentials.from = (char *)malloc(strlen(p->from->field) + strlen("From:") + 1);
2340 sprintf(credentials.from, "From:%s", p->from->field);
2341 credentials.from_email = strdup(p->from->field); /* This doesn't contain "From:" */
2342 /* cut off the '\n's and '\r's at the end */
2343 UP_remove_EOLs(credentials.from);
2344 UP_remove_EOLs(credentials.from_email);
2345
2346 /* now, there is a problem with EP module (or c-client): the p->from->field
2347 would contain only the first line if the "From" field has multiple lines.
2348 As a temp solution, we will add the second line (if it exists) explicitely */
2349 /* This is not a problem, it is the way the imap is written.
2350 It returns multiple lines as a linked list, so loop for all the lines */
2351 while ( (p->from = p->from->next) != NULL && p->from->field != NULL)
2352 { /* there is another line */
2353 credentials.from = (char *)realloc(credentials.from, strlen(credentials.from) + strlen(p->from->field) + 1);
2354 strcat(credentials.from, p->from->field);
2355 credentials.from_email = (char *)realloc(credentials.from_email, strlen(credentials.from_email) + strlen(p->from->field) + 1);
2356 strcat(credentials.from_email, p->from->field);
2357 UP_remove_EOLs(credentials.from);
2358 UP_remove_EOLs(credentials.from_email);
2359 }
2360 }
2361 else
2362 {
2363 credentials.from = strdup("");
2364 credentials.from_email = strdup("");
2365 }
2366
2367 update_mail_sender = strdup(credentials.from_email);
2368
2369 if (tracing)
2370 {
2371 printf("TRACING: From field is: [%s]\n", credentials.from);
2372 printf("TRACING: update_mail_sender is: [%s]\n", update_mail_sender);
2373 }
2374
2375
2376 if(p->cc != NULL && p->cc->field != NULL)
2377 {
2378 update_mail_cc = strdup(p->cc->field);
2379 /* cut off the '\n's and '\r's at the end */
2380 UP_remove_EOLs(update_mail_cc);
2381
2382 /* loop for all multiple lines */
2383 while ( (p->cc = p->cc->next) != NULL && p->cc->field != NULL)
2384 { /* there is another line */
2385 update_mail_cc = (char *)realloc(update_mail_cc, strlen(update_mail_cc) + strlen(p->cc->field) + 1);
2386 strcat(update_mail_cc, p->cc->field);
2387 UP_remove_EOLs(update_mail_cc);
2388 }
2389 }
2390 else
2391 update_mail_cc = strdup("");
2392
2393 if (tracing)
2394 {
2395 printf("TRACING: Cc field is: [%s]\n", update_mail_cc);
2396 }
2397
2398
2399 if(p->subject != NULL && p->subject->field != NULL)
2400 {
2401 subject = strdup(p->subject->field);
2402 /* cut off the '\n' and '\r' from the end */
2403 UP_remove_EOLs(subject);
2404
2405 /* loop for all multiple lines */
2406 while ( (p->subject = p->subject->next) != NULL && p->subject->field != NULL)
2407 { /* there is another line */
2408 subject = (char *)realloc(subject, strlen(subject) + strlen(p->subject->field) + 1);
2409 strcat(subject, p->subject->field);
2410 UP_remove_EOLs(subject);
2411 }
2412 }
2413 else
2414 subject = strdup("");
2415
2416 update_mail_subject = strdup(subject);
2417
2418 /* parse the subject line */
2419 subject_result = UP_subject_process(update_mail_subject);
2420
2421
2422 if(p->reply_to != NULL && p->reply_to->field != NULL)
2423 {
2424 reply_to = strdup(p->reply_to->field);
2425 /* cut off the '\n' and '\r' from the end */
2426 UP_remove_EOLs(reply_to);
2427
2428 /* loop for all multiple lines */
2429 while ( (p->reply_to = p->reply_to->next) != NULL && p->reply_to->field != NULL)
2430 { /* there is another line */
2431 reply_to = (char *)realloc(reply_to, strlen(reply_to) + strlen(p->reply_to->field) + 1);
2432 strcat(reply_to, p->reply_to->field);
2433 UP_remove_EOLs(reply_to);
2434 }
2435 }
2436 else
2437 reply_to = strdup("");
2438
2439
2440 to_address = find_email_address(credentials.from);
2441
2442 /* if Reply_To was available in the incoming header, then use it */
2443 if (strlen(reply_to) > 0)
2444 {
2445 to_address = (char *)realloc(to_address, strlen(reply_to) + 1);
2446 to_address = strcpy(to_address, reply_to);
2447 to_address = find_email_address(to_address); /* so that we take only the email address */
2448 }
2449
2450 if (p->message_id != NULL && p->message_id->field != NULL)
2451 {
2452 update_mail_ID = strdup(p->message_id->field);
2453 /* cut off the '\n' and '\r' from the end */
2454 UP_remove_EOLs(update_mail_ID);
2455
2456 /* loop for all multiple lines */
2457 while ( (p->message_id = p->message_id->next) != NULL && p->message_id->field != NULL)
2458 { /* there is another line */
2459 update_mail_ID = (char *)realloc(update_mail_ID, strlen(update_mail_ID) + strlen(p->message_id->field) + 1);
2460 strcat(update_mail_ID, p->message_id->field);
2461 UP_remove_EOLs(update_mail_ID);
2462 }
2463 }
2464 else
2465 update_mail_ID = strdup("");
2466
2467
2468 if(p->date != NULL && p->date->field != NULL)
2469 {
2470 update_mail_date = strdup(p->date->field);
2471 /* cut off the '\n' and '\r' from the end */
2472 UP_remove_EOLs(update_mail_date);
2473
2474 /* loop for all multiple lines */
2475 while ( (p->date = p->date->next) != NULL && p->date->field != NULL)
2476 { /* there is another line */
2477 update_mail_date = (char *)realloc(update_mail_date, strlen(update_mail_date) + strlen(p->date->field) + 1);
2478 strcat(update_mail_date, p->date->field);
2479 UP_remove_EOLs(update_mail_date);
2480 }
2481 }
2482 else
2483 update_mail_date = strdup("");
2484
2485 if (tracing)
2486 {
2487 printf("\nEP_ShowTree outputs:\n");
2488 EP_ShowTree(p->tree);
2489 }
2490
2491 pt = EP_GetTokens(p->tree, NULL, NULL);
2492
2493 if(tracing){
2494 /* Print the list out (debugging) */
2495 printf("\nEP_PrintTokens outputs:\n");
2496 EP_PrintTokens(pt);
2497 }
2498
2499 /* replace the global variables in mheader */
2500 mheader_replaced = UP_replace_globals(mheader);
2501 /* replace the global variables in mailtxt */
2502 mailtxt_replaced = UP_replace_globals(mailtxt);
2503
2504 /* If this wasn't only a help request, then we need to process the input */
2505 if(subject_result.result != UP_SUBJ_HELP_REQ){
2506
2507 /* ... and now process the items in the list */
2508 list_item = pt;
2509 while (list_item != NULL) {
2510 if(tracing){
2511 printf("\n\nWill process: %s, MIMEtype: %d\n", list_item->file, list_item->MIMEContentType);
2512 }
2513 /* initialize pgp_key_list (XXX This should be a proper freeing of the list) */
2514 credentials.pgp_key_list = NULL;
2515 ptk = list_item->keys;
2516 if(ptk != NULL){
2517 AK_add_to_ack(ack_file_name, "==== BEGIN PGP SIGNED PART (keyID(s):");
2518 pgp_signed = 1;
2519 while (ptk != NULL) {
2520 if(tracing){
2521 printf("TRACING: key: %.8X, isValid: %i\n",
2522 ptk->keyID, ptk->isValidPGPSignature);
2523 }
2524 temp_keyid = (char *)malloc(10);
2525 sprintf(temp_keyid, "%.8X", ptk->keyID);
2526 if(tracing){
2527 printf("TRACING: This key will be added to the list: [%s]\n", temp_keyid);
2528 }
2529 AK_add_to_ack(ack_file_name, " %s", temp_keyid);
2530 credentials.pgp_key_list = g_slist_append (credentials.pgp_key_list, temp_keyid);
2531 ptk = ptk->next;
2532 if(ptk != NULL){
2533 AK_add_to_ack(ack_file_name, ",");
2534 }else{
2535 AK_add_to_ack(ack_file_name, ") ====\n");
2536 }
2537 }
2538 }
2539 process_file(list_item->file, credentials,
2540 AUTO_NIC_hdl_hash, ack_file_name,
2541 ntfy_hash, forw_hash, cross_hash);
2542 if(pgp_signed){
2543 AK_add_to_ack(ack_file_name, "==== END PGP SIGNED PART ====\n\n");
2544 pgp_signed = 0;
2545 }
2546 list_item = list_item->next;
2547 }
2548
2549 }else{/* this was only a help request (inferred from the "Subject" line of the upd message) */
2550
2551 /* Print out the header of the acknowledgement */
2552 /* AK_add_to_ack(ack_file_name, "To: %s\n%s\n\nHelp file requested so body of message ignored.\n\n\n"
2553 "============================================================\n\n",
2554 to_address, mheader_replaced); */
2555 AK_add_to_ack(ack_file_name, "\n============================================================\n\n");
2556
2557 AK_add_file_to_ack(ack_file_name, autodbmhelp);
2558 AK_add_to_ack(ack_file_name, "\n============================================================\n\n");
2559
2560 }
2561
2562 EP_CleanTokens(pt);
2563
2564 EP_MailDescrCleanUp(p);
2565
2566 /* if we have created a temporary file for update, delete it */
2567 if(temp_upd_file != NULL){
2568
2569 unlink(temp_upd_file);
2570
2571 }
2572
2573 }else if(networkupdate){
2574
2575 /* process networkupdate. Since we use inetd, we just process stdin */
2576 process_networkupdate(credentials, AUTO_NIC_hdl_hash, ack_file_name,
2577 ntfy_hash, forw_hash, cross_hash);
2578
2579 }else{/* not reading from the mail message or from network */
2580 if(input_file_name != NULL){
2581
2582 /* first log the input in the upd log file */
2583 UP_add_to_upd_log(input_file_name);
2584
2585
2586 write_checkpoint(1);
2587 process_file(input_file_name, credentials,
2588 AUTO_NIC_hdl_hash, ack_file_name,
2589 ntfy_hash, forw_hash, cross_hash);
2590 }else{/* the filename is not given, so we have to write
2591 stdin to a temp file, and give it to process_file */
2592 temp_upd_file = generate_upd_file();
2593 if(tracing){
2594 printf("TRACING: main: temp_upd_file=%s\n", temp_upd_file);
2595 }
2596 if(( upd_file = fopen(temp_upd_file, "a")) == NULL){
2597 ER_perror(FAC_UP, UP_CANTOPENW, "Can't open ack file, %s", temp_upd_file);
2598 }
2599
2600 while((c = getchar()) != EOF){
2601 fprintf(upd_file, "%c",c);
2602 }
2603 fclose(upd_file);
2604
2605 write_checkpoint(1);
2606 process_file(temp_upd_file, credentials,
2607 AUTO_NIC_hdl_hash, ack_file_name,
2608 ntfy_hash, forw_hash, cross_hash);
2609 unlink(temp_upd_file);
2610
2611 }
2612
2613 }
2614
2615
2616 /* post-process and send the ack */
2617 if(reading_from_mail && to_address != NULL){
2618 AK_send_ack(ack_file_name, to_address, mailcmd);
2619 }
2620
2621 /* if our update wasn't a mail update OR we have been asked explicitely
2622 to print out the ack to the stdout, print it */
2623 if(!reading_from_mail || print_out_ack){
2624 AK_print_ack(ack_file_name);
2625 }
2626
2627 AK_log_ack(ack_file_name, acklog);
2628 AK_delete_ack(ack_file_name);
2629
2630 NT_send_ntfy_list(ntfy_hash, mailcmd);
2631 NT_log_ntfy_list(ntfy_hash, notiflog);
2632 NT_delete_ntfy_list(ntfy_hash);
2633
2634 NT_send_ntfy_list(forw_hash, mailcmd);
2635 NT_log_ntfy_list(forw_hash, forwlog);
2636 NT_delete_ntfy_list(forw_hash);
2637
2638
2639 NT_send_ntfy_list(cross_hash, mailcmd);
2640 NT_log_ntfy_list(cross_hash, crosslog);
2641 NT_delete_ntfy_list(cross_hash);
2642
2643 /* remove the lock file */
2644 /* remove_lock_file(lockfile); */
2645
2646
2647 /* remove checkpoint file */
2648 remove_checkpoint();
2649
2650 free(ack_file_name);
2651
2652 if (tracing)
2653 {
2654 printf("TRACING: END\n");
2655 }
2656
2657 return 0 ;
2658 }