bin/dbupdate/dbupdate.cc
/* [<][>][^][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.89 $
3
4 DBupdate
5
6 Status: NOT REVIEWED, TESTED
7
8 Author(s): Engin Gunduz
9
10 ******************/ /******************
11 Modification History:
12 engin (01/03/2000) Created.
13 ******************/ /******************
14 Copyright (c) 2001 RIPE NCC
15
16 All Rights Reserved
17
18 Permission to use, copy, modify, and distribute this software and its
19 documentation for any purpose and without fee is hereby granted,
20 provided that the above copyright notice appear in all copies and that
21 both that copyright notice and this permission notice appear in
22 supporting documentation, and that the name of the author not be
23 used in advertising or publicity pertaining to distribution of the
24 software without specific, written prior permission.
25
26 THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
27 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
28 AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
29 DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
30 AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
31 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
32 ***************************************/
33
34
35
36
37 #include <config.h>
38 #include "dbupdate.h"
39 #include "UP_extrnl_syntax.h"
40 #include "UP_subject.h"
41 #include "er_yacc_helper.h"
42 #include "erroutines.h"
43 #include "ca_configFns.h"
44 #include "ca_dictionary.h"
45 #include "ca_macros.h"
46 #include "ca_srcAttribs.h"
47 #include "notification.h"
48 #include "gpg.h"
49 #include "mail_parser.h"
50 #include "process.h"
51
52 #ifdef HAVE_SYS_PARAM_H
53 #include <sys/param.h>
54 #endif
55
56
57 int tracing = 0;
58 int test_mode = 0;
59 int supress_ack_notif = 0;
60 int print_out_ack = 0;
61
62 /* do we process a mail */
63 int reading_from_mail = 0;
64
65 /* are we processing networkupdate? */
66 int networkupdate = 0;
67
68 /* IP of the networkupdate client */
69 char * netupdclientIP = NULL;
70
71 /* two global variables to tally the processed objects */
72 int count_successful = 0;
73 int count_unsuccessful = 0;
74
75
76 /* sender of the mail, in case of a mail update */
77 char *update_mail_sender = NULL;
78 char *update_mail_subject = NULL;
79 char *update_mail_date = NULL;
80 char *update_mail_ID = NULL;
81 char *update_mail_cc = NULL;
82
83 /* required configuration variables */
84 char *tmpdir = NULL;
85 char *lockdir = NULL;
86 char *mailcmd = NULL;
87 char *notitxt = NULL;
88 char *successtxt = NULL;
89 char *failuretxt = NULL;
90 char *notimailtxt = NULL;
91 char *notinetworktxt = NULL;
92 char *fwtxt = NULL;
93 char *fwmailtxt = NULL;
94 char *mtfwheader = NULL;
95 char *mtfwtxt = NULL;
96 char *mailtxt = NULL;
97 char *acksig = NULL;
98 char *defmail = NULL;
99 char *updlog = NULL;
100 char *notiflog = NULL;
101 char *crosslog = NULL;
102 char *acklog = NULL;
103 char *forwlog = NULL;
104 char *humailbox = NULL;
105 char *autobox = NULL;
106 char *copyright_notice = NULL;
107 char *overridecryptedpw = NULL;
108 char *country = NULL;
109 char *countries[400];
110 char *sources[100];
111 char *pgppath = NULL;
112 char *gpgcmd = NULL;
113 char *pgp_public_key_ring = NULL;
114 char *autodbmhelp = NULL;
115 char *update_host = NULL;
116 int update_port;
117 char *query_host = NULL;
118 int query_port;
119 char *cn_subject_add = NULL;
120 char *cn_subject_del = NULL;
121 char *cn_explain_add = NULL;
122 char *cn_explain_del = NULL;
123 char *cn_overlap_add = NULL;
124 char *cn_overlap_del = NULL;
125 char *cno_subject_add = NULL;
126 char *cno_subject_del = NULL;
127 char *cno_explain_add = NULL;
128 char *cno_explain_del = NULL;
129 char *cno_overlap_add = NULL;
130 char *cno_overlap_del = NULL;
131 char *allocmnt = NULL;
132 char *mheader = NULL;
133 char *DBhost = NULL;
134 int DBport;
135 char *DBuser = NULL;
136 char *DBname = NULL;
137 char *DBpasswd = NULL;
138 /* end of config variables */
139
140 char * fingerprint = NULL;
141 char * keyowner = NULL;
142
143 /* result of subject line processing is kept in the following struct. */
144 up_subject_struct subject_result;
145
146
147 /* hostname and pid are used all over the program, so we save them into these variables */
148 char hostname[MAXHOSTNAMELEN];
149 //char * hostname;
150 int pid;
151
152 /* name of the lock file, which is used for the crash recovery mechanism */
153 char * lock_file_name;
154
155 void error_init(int argc, char ** argv) {
/* [<][>][^][v][top][bottom][index][help] */
156
157 ER_init("dbupdate", 1);
158
159
160 } /* error_init() */
161
162
163
164
165
166
167 /* 'lockfile' struct is for keeping both the name of the lock file and the file descriptor
168 of it, which is open during the execution of dbupdate. We need the filedes to close it,
169 when dbupdate finishes, and the name to delete the file. */
170 typedef struct {
171 char * lockname;
172 int filedes;
173 } lockfilestruct;
174
175
176 lockfilestruct lockfile;
177
178
179
180 /* Deletes the key defined in the incoming object (a key-cert object)
181 from the public keyring. Returns NULL if there was no error,
182 returns an error message if there is an error */
183 char * delete_key(char * obj){
/* [<][>][^][v][top][bottom][index][help] */
184
185 struct ImportKeyObject iKO;
186 char * obj_keyID;
187 char * key_cert_attr;
188 GSList * templist, * certiflist, * next;
189 u32 keyID;
190 char * tempfile;
191 char ** lines;
192 int i;
193 FILE * key_file;
194 char * temp, * temp2;
195 char * error_string;
196
197 templist = get_attr_list(obj, "key-cert");
198 key_cert_attr = strdup((char *)templist->data);
199 g_slist_free(templist);
200
201 tempfile = (char *)malloc(strlen(tmpdir) + strlen("tmp-key.") + 32);
202 sprintf(tempfile, "%s/tmp-key.%i", tmpdir, pid /*getpid()*/);
203
204 /* now we must write certif attribute(s) of this key-certif into the tempfile */
205 /* get the certif first */
206 certiflist = get_attr_list(obj, "certif");
207 if(( key_file = fopen(tempfile, "w")) == NULL){
208 ER_perror(FAC_UP, UP_CANTOPEN, "Can't open temporary file, %s", tempfile);
209 exit(1);
210 }
211 for( next = certiflist; next != NULL ; next = g_slist_next(next) ){
212 lines = g_strsplit((char *)next->data, "\n", 0);
213 if(lines[0] == NULL){/* if this was an empty attribute, just print an empty line */
214 fprintf(key_file, "\n");
215 }
216 for(i = 0; lines[i] != NULL; i++){
217 temp = strdup(lines[i]);
218 if(i != 0 && temp[0] == '+'){/* if it begins with a plus */
219 temp2 = strdup(temp + 1);
220 g_strstrip(temp2);
221 fprintf(key_file, "%s\n", temp2);
222 free(temp);free(temp2);
223 }else{
224 g_strstrip(temp);
225 fprintf(key_file, "%s\n", temp);
226 free(temp);
227 }
228 }
229 g_strfreev(lines);
230 }
231 fclose(key_file);
232 g_slist_free(certiflist);
233
234 strcpy(iKO.iFilename, tempfile);
235
236 if(tracing){
237 printf("TRACING: delete_key: key_cert_attr: [%s]\n", key_cert_attr);
238 }
239
240 obj_keyID = strdup(key_cert_attr + strlen("PGPKEY-"));
241
242 if(tracing){
243 printf("TRACING: delete_key: obj_keyID: [%s]\n", obj_keyID);
244 }
245
246 keyID = strtoul(obj_keyID, NULL, 16);
247
248 if(tracing){
249 printf("TRACING: delete_key: keyID is: %u, %X\n", keyID, keyID);
250 }
251
252
253
254 strcpy(iKO.keyRing, pgp_public_key_ring);
255 PA_RemoveKey(&iKO);
256
257 if(tracing){
258 printf("TRACING: importKeyObj status:\n");
259 printf("TRACING: isValid: %d\n", iKO.rc);
260 }
261
262
263
264 unlink(tempfile);
265 if(iKO.rc == iKO_OK){/* if PA_RemoveKey returned OK */
266 return NULL;
267 }else{/* if PA_RemoveKey returned not OK */
268 switch(iKO.rc){
269 case iKO_UNCHANGED: error_string = strdup("the key is already in the keyring");break;
270 case iKO_NOUSERID: error_string = strdup("no user ID could be extracted");break;
271 case iKO_GENERAL: error_string = strdup("general PGP error");break;
272 case iKO_NOTVALIDUSERID: error_string = strdup("no valid user ID ");break;
273 case iKO_NOPUBLICKEY: error_string = strdup("no public key in the object");break;
274 case iKO_NODEFAULTPUBLICKEYRING: error_string = strdup("general PGP error");break;
275 case iKO_CRC_ERROR: error_string = strdup("CRC error in the certificate");break;
276 case iKO_NO_OPENPGP_DATA:error_string = strdup("no OpenPGP data in the object");break;
277 case iKO_NO_IN_FILES: error_string = strdup("general PGP error");break;
278 case iKO_GENERALFAILURE: error_string = strdup("general PGP error");break;
279 default: error_string = strdup("general PGP error");
280 }
281 return error_string;
282 }
283
284 return NULL;
285 }
286
287
288 /* Takes a key-certif object, extracts its 'certif' attribute and adds
289 the key into public keyring
290 If there is no problem, it returns NULL
291 If there is a problem, then it returns a string which contains an error
292 message */
293 char * import_key(char *obj){
/* [<][>][^][v][top][bottom][index][help] */
294
295 char * tempfile;
296 struct ImportKeyObject iKO;
297 GSList * certiflist, * next, * templist;
298 FILE * key_file;
299 char keyID[9];
300 char * obj_keyID, * key_cert_attr;
301 char * error_string = NULL;
302 char ** lines;
303 int i;
304 char * temp, * temp2;
305
306 tempfile = (char *)malloc(strlen(tmpdir) + strlen("tmp-key.") + 32);
307 sprintf(tempfile, "%s/tmp-key.%i", tmpdir, pid );
308
309 /* now we must write certif attribute(s) of this key-certif into the tempfile */
310 /* get the certif first */
311 certiflist = get_attr_list(obj, "certif");
312 if(( key_file = fopen(tempfile, "w")) == NULL){
313 ER_perror(FAC_UP, UP_CANTOPEN, "Can't open temporary file, %s", tempfile);
314 exit(1);
315 }
316 for( next = certiflist; next != NULL ; next = g_slist_next(next) ){
317 lines = g_strsplit((char *)next->data, "\n", 0);
318 if(lines[0] == NULL){/* if this was an empty attribute, just print an empty line */
319 fprintf(key_file, "\n");
320 }
321 for(i = 0; lines[i] != NULL; i++){
322 temp = strdup(lines[i]);
323 if(i != 0 && temp[0] == '+'){/* if it begins with a plus */
324 temp2 = strdup(temp + 1);
325 g_strstrip(temp2);
326 fprintf(key_file, "%s\n", temp2);
327 free(temp);free(temp2);
328 }else{
329 g_strstrip(temp);
330 fprintf(key_file, "%s\n", temp);
331 free(temp);
332 }
333 }
334 g_strfreev(lines);
335 }
336 fclose(key_file);
337 g_slist_free(certiflist);
338
339 strcpy(iKO.iFilename, tempfile);
340 strcpy(iKO.keyRing, pgp_public_key_ring);
341 PA_ImportKey(&iKO);
342
343 if(tracing){
344 printf("importKeyObj status:\n");
345
346 printf("isValid: %d\n", iKO.rc);
347 printf("keyID: %08lX\n", iKO.keyID);
348 }
349 snprintf(keyID, 9, "%08lX", iKO.keyID);
350
351 if(tracing){
352 printf("keyID: [%s]\n", keyID);
353 }
354
355 unlink(tempfile);
356 free(tempfile);
357
358
359 templist = get_attr_list(obj, "key-cert");
360 key_cert_attr = strdup((char *)templist->data);
361 g_slist_free(templist);
362
363 if(tracing){
364 printf("key_cert_attr: [%s]\n", key_cert_attr);
365 }
366 obj_keyID = strdup(key_cert_attr + strlen("PGPKEY-"));
367 if(tracing){
368 printf("obj_keyID: [%s]\n", obj_keyID);
369 }
370 if(iKO.rc == iKO_OK && (strcasecmp(obj_keyID, keyID) == 0)){/* if PA_ImportKey returned OK
371 and the real keyID is equal to the
372 keyID in the 'key-cert' attribute */
373 fingerprint = strdup(iKO.fingerPrint);
374 keyowner = strdup(iKO.keyOwner);
375 return NULL;
376 }else{/* if PA_ImportKey returned not OK or obj_keyID, keyID didn't match */
377 if(iKO.rc != iKO_OK){
378 switch(iKO.rc){
379 case iKO_UNCHANGED: error_string = strdup("the key is already in the keyring");break;
380 case iKO_NOUSERID: error_string = strdup("no user ID could be extracted");break;
381 case iKO_GENERAL: error_string = strdup("general PGP error");break;
382 case iKO_NOTVALIDUSERID: error_string = strdup("no valid user ID ");break;
383 case iKO_NOPUBLICKEY: error_string = strdup("no public key in the object");break;
384 case iKO_NODEFAULTPUBLICKEYRING: error_string = strdup("general PGP error");break;
385 case iKO_CRC_ERROR: error_string = strdup("CRC error in the certificate");break;
386 case iKO_NO_OPENPGP_DATA:error_string = strdup("no OpenPGP data in the object");break;
387 case iKO_NO_IN_FILES: error_string = strdup("general PGP error");break;
388 case iKO_GENERALFAILURE: error_string = strdup("general PGP error");break;
389 default: error_string = strdup("general PGP error");
390 }
391 return error_string;
392 }else{
393 error_string = (char *)malloc(1024);/* this should be enough */
394 sprintf(error_string, "Keyid for this certificate (%s) is not the same as the PGPKEY field (%s)",
395 keyID, obj_keyID);
396 return error_string;
397 }
398 }
399
400 }
401
402
403
404
405
406 /* Gets the keyowner and fingerprint of a PGP key
407 from the keycert object. The keycert object must already
408 be in the database (thus, in the keyring)
409 The fingerprint and keyowner will be saved in global variables */
410
411 void get_keyowner_fingerpr(char *obj){
/* [<][>][^][v][top][bottom][index][help] */
412
413 GSList * templist = NULL;
414 char * obj_keyID = NULL;
415 struct ImportKeyObject iKO;
416 u32 keyID;
417 char * key_cert_attr;
418
419
420 templist = get_attr_list(obj, "key-cert");
421 key_cert_attr = strdup((char *)templist->data);
422 g_slist_free(templist);
423
424 if(tracing){
425 printf("get_keyowner_fingerpr: key_cert_attr is [%s]\n", key_cert_attr);
426 }
427 obj_keyID = strdup(key_cert_attr + strlen("PGPKEY-"));
428 if(tracing){
429 printf("get_keyowner_fingerpr: obj_keyID is [%s]\n", obj_keyID);
430 }
431
432 sscanf(obj_keyID, "%8X", &keyID);
433 if(tracing){
434 printf("get_keyowner_fingerpr: keyID is [%s]\n", keyID);
435 }
436
437 /* set appropriate fields of iKO */
438 iKO.keyID = keyID;
439 strcpy(iKO.keyRing, pgp_public_key_ring);
440
441 GetFingerPrint(&iKO);
442 fingerprint = strdup(iKO.fingerPrint);
443
444 GetKeyOwner(&iKO);
445 keyowner = strdup(iKO.keyOwner);
446
447
448 if(tracing){
449 if(fingerprint != NULL){
450 printf("get_keyowner_fingerpr: fingerprint is [%s]\n", fingerprint);
451 }
452 if(keyowner){
453 printf("get_keyowner_fingerpr: keyowner is [%s]\n", keyowner);
454 }
455 }
456 }
457
458
459
460
461
462
463 /* Checks the object's syntax, retrives the old version of it from the db,
464 and checks auth2. If everything is OK, then sends it to RIPdb, where referential
465 integrity is checked, and the object is really committed to the db.
466
467 Arguments:
468 char * arg: The object,
469 credentials_struct credentials: The struct containing the credentials, such as
470 'From:' field of the e-mail update,
471 GHashTable * NIC_hdl_hash: A hash containing
472 char * ack_file_name: The file name, to be used to store ACK message
473 */
474
475
476
477 int process_object(char * incoming, credentials_struct credentials,
/* [<][>][^][v][top][bottom][index][help] */
478 GHashTable * NIC_hdl_hash, char * ack_file_name,
479 GHashTable * ntfy_hash, GHashTable * forw_hash, GHashTable * cross_hash){
480
481 bool code = true;
482 Object *o;
483 char * old_version = NULL;
484 o = new Object;
485 int result = 0;
486 up_ripupd_result_struct * result_from_RIPupd;
487 char * result_from_import_key = NULL;
488 char * result_from_delete_key = NULL;
489 char * auto_nic = NULL;
490 char * changed_obj = NULL;
491 char * obj_with_AUTO_NIC_hdl;
492 char * assigned_NIC;
493 char * formatted_object;
494 char * type;
495 char * arg;
496 char * arg2;
497 char * generated_object;
498 char *search_key = NULL;
499 external_syntax_struct * external_syntax_results;
500
501
502 char * value = NULL;/* these two are for */
503 Attr * attr; /* ack messages only */
504
505 arg = strdup(incoming);
506
507 if(has_ref_to_AUTO_nic_hdl(arg)){/* if this object has refs to AUTO NIC hdls*/
508 /* then first replace AUTO NIC hdls with assigned NIC hdls (in NIC_hdl_hash) */
509 if((changed_obj = replace_refs_to_AUTO_NIC_hdl(changed_obj, arg, NIC_hdl_hash)) == NULL){
510 /* try to parse the object only for reporting purposes */
511 o->scan_silent(arg,strlen(arg));
512 AK_add_to_ack(ack_file_name, "\nUpdate FAILED: [%s] Unknown AUTO NIC handle referenced\n%s\n",
513 (o && o->type) ? o->type->getName() : "unknown-type", delete_override(arg));
514 delete(o);
515 return UP_ANE; /* AUTO NIC hdl error */
516
517 }else{ /* in this case, we must use changed_obj instead of arg */
518
519 free(arg);
520 arg = changed_obj;
521
522 };
523 }
524
525
526 code = o->scan_silent(arg,strlen(arg));
527 if(code){
528 type = get_class_type(o);
529 /* is the object to be deleted? */
530 if(o->isDeleted){
531 old_version = get_old_version(arg);
532 if(old_version == NULL){ /* the object doesn't exist in the db! */
533 search_key = get_search_key(o, o->type->getName(), arg);
534 if ( search_key == NULL )
535 search_key = "";
536 AK_add_to_ack(ack_file_name, "\nDelete FAILED: [%s] %s\n%s\n***Error: Entry not found\n\n",
537 o->type->getName(), search_key, delete_override(arg));
538 return UP_NSO; /* no such object */
539 }else {/* the object is in the db */
540 if(identical(old_version, arg) /* if the old & new versions are identical */
541 || (strcmp(o->type->getName(), "key-cert") == 0) /* or it is a key-cert object */
542 || (strcmp(o->type->getName(), "inet6num") == 0)){/* or it is an inet6num object */
543 result = check_auth(NULL, arg, o->type->getName(), credentials);
544 if(result == UP_AUTH_OK){
545 if(tracing) {
546 printf("TRACING: Will send the obj to be deleted\n");
547 }
548 if(strcmp(type, "key-cert") == 0){
549 result_from_delete_key = delete_key(arg);
550 }else{
551 result_from_delete_key = NULL;
552 }
553 /* if there was no problem with key deletion from the key-ring */
554 if(result_from_delete_key == NULL){
555 result_from_RIPupd = send_object_db(arg, NULL, "DEL");
556 if(result_from_RIPupd->result == 0){
557 AK_add_to_ack(ack_file_name, "\nDelete OK: [%s] %s\n",
558 o->type->getName(), get_search_key(o, o->type->getName(), arg));
559 NT_write_all_ntfs(old_version, NULL, NULL, tmpdir, ntfy_hash, forw_hash, cross_hash,
560 credentials.from);
561 return UP_OK;
562 }else{
563 AK_add_to_ack(ack_file_name, "\nDelete FAILED: [%s] %s\n%s\n",
564 o->type->getName(), get_search_key(o, o->type->getName(), arg),
565 result_from_RIPupd->error_str);
566 return UP_INT;
567 }
568 result_from_RIPupd->result = 0;
569 }else{
570 AK_add_to_ack(ack_file_name, "\nDelete FAILED: [%s] %s\n%s\n",
571 o->type->getName(), get_search_key(o, o->type->getName(), delete_override(arg)),
572 result_from_delete_key);
573 return UP_INT;
574 }
575 }else{ /* auth failed */
576 if(tracing) {
577 printf("TRACING: Auth failed\n");
578 }
579
580 AK_add_to_ack(ack_file_name, "\nDelete FAILED: [%s] %s\nAuthorisation failed, request forwarded to maintainer.\n%s\n",
581 o->type->getName(), get_search_key(o, o->type->getName(), arg), delete_override(arg));
582 NT_write_all_frwds(arg, NULL, tmpdir, ntfy_hash, forw_hash, cross_hash, credentials.from);
583 return UP_AUF; /* Auth failed */
584 }
585 }else{/* the new & old versions do not match */
586 AK_add_to_ack(ack_file_name, "\nDelete FAILED: [%s] %s\n%s\n***Error: new & old versions do not match\n",
587 o->type->getName(), get_search_key(o, o->type->getName(), arg), delete_override(arg));
588 return UP_NOM; /* new & old versions do not match */
589 }
590 }
591 }else {/* the object is _not_ to be deleted */
592
593 if(has_AUTO_NIC_hdl(arg)){/* if the object has an AUTO NIC hdl */
594 external_syntax_results = UP_check_external_syntax(o, arg);
595 if( external_syntax_results->result != UP_EXTSYN_ERR
596 && external_syntax_results->result != UP_EXTSYN_ERR_WARN){/* if there is no error */
597 /* then its nic-hdl attribute must be modified so that RIPupdate
598 would understand that it must assign a NIC handle to it */
599 /* but first check the auth */
600 result = check_auth(arg, NULL, o->type->getName(), credentials);
601 if(result == UP_AUTH_OK){
602 if(tracing) {
603 printf("TRACING: Will send the obj to be created with AUTO NIC hdl\n");
604 }
605 auto_nic = (char *)malloc(1024); /* should be enough for a NIC hdl */
606 obj_with_AUTO_NIC_hdl = replace_AUTO_NIC_hdl(external_syntax_results->new_obj, auto_nic);
607 if(tracing) {
608 printf("TRACING: Called replace_AUTO_NIC_hdl, get [%s]\n", obj_with_AUTO_NIC_hdl);
609 printf("TRACING: Will send the obj to be added\n");
610 }
611 assigned_NIC = (char *)malloc(128); /* this should be enough for a NIC hdl */
612 result_from_RIPupd = send_object_db(obj_with_AUTO_NIC_hdl, assigned_NIC, "ADD");
613 if(result_from_RIPupd->result == 0){
614 AK_add_to_ack(ack_file_name, "\nNew OK: [%s] %s\n",
615 o->type->getName(), assigned_NIC);
616 /* replace the AUTO nic hdl with the assigned one (for reporting purposes, in the notif mesg) */
617 formatted_object = UP_put_assigned_NIC(external_syntax_results->new_obj, assigned_NIC);
618 formatted_object = delete_override(formatted_object);
619 arg2 = delete_override(arg);
620 NT_write_all_ntfs(NULL, arg2, formatted_object, tmpdir, ntfy_hash, forw_hash, cross_hash,
621 credentials.from);
622
623 result_from_RIPupd->result = 0;
624 if(tracing && assigned_NIC != NULL) {
625 printf("TRACING: send_object_db returned [%s] as assigned NIC hdl\n", assigned_NIC);
626 }
627 if(assigned_NIC != NULL){
628 if(tracing){
629 printf("TRACING: auto_nic=[%s], assigned_NIC=[%s]\n", auto_nic, assigned_NIC);
630 }
631 g_hash_table_insert(NIC_hdl_hash, auto_nic, assigned_NIC);
632 if(tracing){
633 printf("TRACING: NIC_hdl_hash has %i pairs\n",g_hash_table_size(NIC_hdl_hash));
634 }
635 }
636
637 return UP_OK;
638 }else{
639 AK_add_to_ack(ack_file_name, "\nNew FAILED: [%s]\n%s\n%s\n",
640 o->type->getName(), delete_override(arg),
641 result_from_RIPupd->error_str);
642 return UP_INT;
643 }
644
645 }else{
646 /* auth failed ! */
647 if(tracing) {
648 printf("TRACING: Auth failed\n");
649 }
650
651 AK_add_to_ack(ack_file_name, "\nNew FAILED: [%s] %s\nAuthorisation failed, request forwarded to maintainer.\n%s\n",
652 o->type->getName(), get_search_key(o, o->type->getName(), arg), delete_override(arg));
653 arg2 = delete_override(arg);
654 NT_write_all_frwds(NULL, arg2, tmpdir, ntfy_hash, forw_hash, cross_hash, credentials.from);
655 return UP_AUF; /* Auth failed */
656 }
657 }else{/* external syntax check failed */
658 AK_add_to_ack(ack_file_name, "\nUpdate FAILED: [%s] %s\n%s%s\n",
659 o->type->getName(), get_search_key(o, o->type->getName(), arg),
660 delete_override(arg), external_syntax_results->error_str);
661 return UP_SYN;
662 }
663 }
664 else{
665 old_version = get_old_version(arg);
666 if(old_version != NULL){/* so, this is an update operation */
667 if( (!reading_from_mail) ||
668 (subject_result.result != UP_SUBJ_NEW_ENFORCED)){/* If the user didn't enforce
669 creation in the subject line */
670 external_syntax_results = UP_check_external_syntax(o, arg);
671 if( external_syntax_results->result != UP_EXTSYN_ERR
672 && external_syntax_results->result != UP_EXTSYN_ERR_WARN){/* if there is no error */
673 /* if the old version & the new one are not identical */
674 if(identical(old_version, arg) != 1){
675 result = check_auth(arg, old_version, o->type->getName(), credentials);
676 if(result == UP_AUTH_OK){
677 if(tracing) {
678 printf("TRACING: Will send the obj to be updated\n");
679 }
680
681 if(strcasecmp(o->type->getName(), "key-cert") == 0){
682 get_keyowner_fingerpr(arg);
683 generated_object = UP_generate_kc_attrs(o, arg);
684 external_syntax_results->new_obj = generated_object;
685 }
686
687 result_from_RIPupd = send_object_db(external_syntax_results->new_obj, NULL, "UPD");
688 if(result_from_RIPupd->result == 0){
689 AK_add_to_ack(ack_file_name, "\nUpdate OK: [%s] %s\n",
690 o->type->getName(), get_search_key(o, o->type->getName(), arg));
691 arg2 = delete_override(arg);
692 NT_write_all_ntfs(old_version, arg2, NULL, tmpdir, ntfy_hash, forw_hash, cross_hash,
693 credentials.from);
694 return UP_OK;
695 }else{
696 AK_add_to_ack(ack_file_name, "\nUpdate FAILED: [%s] %s\n%s\n%s\n",
697 o->type->getName(), get_search_key(o, o->type->getName(), arg),
698 delete_override(arg), result_from_RIPupd->error_str);
699 return UP_INT;
700 }
701 result_from_RIPupd->result = 0;
702 }else if(result == UP_NAM){
703 /* name of a person/role object cannot be changed */
704 if(tracing) {
705 printf("TRACING: name of a person/role object cannot be changed\n");
706 }
707
708 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",
709 o->type->getName(), get_search_key(o, o->type->getName(), arg), delete_override(arg));
710 arg2 = delete_override(arg);
711 return UP_NAM; /* name of a person/role object cannot be changed */
712
713
714 }
715 else{
716 /* auth failed ! */
717 if(tracing) {
718 printf("TRACING: Auth failed\n");
719 }
720
721 AK_add_to_ack(ack_file_name, "\nUpdate FAILED: [%s] %s\nAuthorisation failed, request forwarded to maintainer.\n%s\n",
722 o->type->getName(), get_search_key(o, o->type->getName(), arg), delete_override(arg));
723 arg2 = delete_override(arg);
724 NT_write_all_frwds(old_version, arg2, tmpdir, ntfy_hash, forw_hash, cross_hash, credentials.from);
725 return UP_AUF; /* Auth failed */
726 }
727
728 }else{/* if the old and new versions of the object are the same */
729 if(tracing) {
730 printf("TRACING: The obj sent is identical to the one in the DB (NOOP)\n");
731 }
732 AK_add_to_ack(ack_file_name, "\nUpdate NOOP: [%s] %s\n",
733 o->type->getName(), get_search_key(o, o->type->getName(), arg));
734 return UP_OK;
735
736 }
737 }else{/* if there is an error in external syntax checks */
738 AK_add_to_ack(ack_file_name, "\nUpdate FAILED: [%s] %s\n%s%s\n",
739 o->type->getName(), get_search_key(o, o->type->getName(), arg),
740 delete_override(arg), external_syntax_results->error_str);
741 return UP_SYN;
742 }
743
744 }else{/* if the user enforced creation (using NEW keyword) in the subject line */
745
746 AK_add_to_ack(ack_file_name, "\nUpdate FAILED: [%s] %s\n%s\n"
747 "***Error: Object already exists\n",
748 o->type->getName(), get_search_key(o, o->type->getName(), arg),
749 delete_override(arg));
750 return UP_INT;
751
752 }
753 }else { /* old_version == NULL, so, creation */
754 external_syntax_results = UP_check_external_syntax(o, arg);
755 if( external_syntax_results->result != UP_EXTSYN_ERR
756 && external_syntax_results->result != UP_EXTSYN_ERR_WARN){/* if there is no error */
757 result = check_auth(arg, NULL, o->type->getName(), credentials);
758 if(result == UP_AUTH_OK){
759 if(tracing) {
760 printf("TRACING: Will send the obj to be added\n");
761 }
762 /* if the object is a key-cert object, then we must import the PGP key */
763 if(strcmp(type, "key-cert") == 0){
764 result_from_import_key = import_key(arg);
765 }else{
766 result_from_import_key = NULL;
767 }
768 if(result_from_import_key == NULL){/* no PGP problem */
769 if(strcmp(type, "key-cert") == 0){/* if the object is a key-cert object */
770
771 generated_object = UP_generate_kc_attrs(o, arg);
772 result_from_RIPupd = send_object_db(generated_object, NULL, "ADD");
773 }else{
774
775 result_from_RIPupd = send_object_db(external_syntax_results->new_obj, NULL, "ADD");
776
777 }
778 if(result_from_RIPupd->result == 0){/* if there was no problem */
779 AK_add_to_ack(ack_file_name, "\nNew OK: [%s] %s\n",
780 o->type->getName(), get_search_key(o, o->type->getName(), arg));
781 arg2 = delete_override(arg);
782 NT_write_all_ntfs(NULL, arg2, NULL, tmpdir, ntfy_hash, forw_hash, cross_hash,
783 credentials.from);
784 return UP_OK;
785
786 }else{
787 AK_add_to_ack(ack_file_name, "\nNew FAILED: [%s] %s\n%s\n",
788 o->type->getName(), get_search_key(o, o->type->getName(), arg),
789 result_from_RIPupd->error_str);
790 return UP_INT;
791 }
792 result_from_RIPupd = 0;
793 }else{/* there was a problem with PGP key import */
794 AK_add_to_ack(ack_file_name, "\nNew FAILED: [%s] %s\n%s\n",
795 o->type->getName(), get_search_key(o, o->type->getName(), arg),
796 result_from_import_key);
797 return UP_INT;
798 }
799 }else if(result == UP_FWD){ /* this was a maintainer or as-block creation request, so
800 forward it to <HUMAILBOX> */
801
802 if(tracing){
803
804 printf("TRACING: Maintainer or as-block request will be forwarded to <HUMAILBOX>\n");
805
806 }
807
808 AK_add_to_ack(ack_file_name, "\nNew FAILED: [%s] %s\n%s\n"
809 "***Error: %s objects cannot be created automatically\n"
810 "***Error: This object has been forwarded to %s\n"
811 "***Error: for authorisation.\n"
812 "***Error: No further action from your part is required\n",
813 o->type->getName(), get_search_key(o, o->type->getName(), arg),
814 delete_override(external_syntax_results->new_obj), o->type->getName(), humailbox);
815
816 /* and forward this creation request to <HUMAILBOX> */
817 NT_forw_create_req(external_syntax_results->new_obj);
818
819 return UP_AUF;
820
821
822 }else if(result == UP_HOF){/* hierarchical authorisation failed */
823 if(tracing) {
824 printf("TRACING: Auth failed\n");
825 }
826
827 AK_add_to_ack(ack_file_name, "\nNew FAILED: [%s] %s\n%s\n***Error: Hierarchical authorisation"
828 " failed, request forwarded to maintainer.\n",
829 o->type->getName(), get_search_key(o, o->type->getName(), arg), delete_override(arg));
830 arg2 = delete_override(arg);
831 NT_write_all_frwds(NULL, arg2, tmpdir, ntfy_hash, forw_hash, cross_hash, credentials.from);
832 return UP_AUF;
833
834
835 }else{
836 /* auth failed ! */
837 if(tracing) {
838 printf("TRACING: Auth failed\n");
839 }
840
841 AK_add_to_ack(ack_file_name, "\nNew FAILED: [%s] %s\nAuthorisation failed, request forwarded to maintainer.\n%s\n",
842 o->type->getName(), get_search_key(o, o->type->getName(), arg), delete_override(arg));
843 arg2 = delete_override(arg);
844 NT_write_all_frwds(NULL, arg2, tmpdir, ntfy_hash, forw_hash, cross_hash, credentials.from);
845 return UP_AUF; /* Auth failed */
846 }
847 }else{
848 AK_add_to_ack(ack_file_name, "\nNew FAILED: [%s] %s\n%s%s\n",
849 o->type->getName(), get_search_key(o, o->type->getName(), arg),
850 delete_override(arg), external_syntax_results->error_str);
851 return UP_SYN;
852 }
853 }
854 }
855
856 }
857 }else{/* even if obj doesn't parse properly, it may be a legacy object
858 which the user wants to delete... */
859 if(tracing){
860 printf("TRACING: Object didn't parse\n");
861 }
862 /* if it is for deletion */
863 if(o->isDeleted){
864 /* here delete it */
865 old_version = get_old_version(arg);
866 if(old_version == NULL){ /* the object doesn't exist in the db! */
867 search_key = get_search_key(o, o->type->getName(), arg);
868 if ( search_key == NULL )
869 search_key = "";
870 AK_add_to_ack(ack_file_name, "\nDelete FAILED: [%s] %s\n%s\n***Entry not found\n\n",
871 o->type->getName(), search_key, delete_override(arg));
872 return UP_NSO; /* no such object */
873 }else {/* the object is in the db */
874 if(identical(old_version, arg)){/* if the old & new versions are identical */
875 result = check_auth(NULL, old_version, o->type->getName(), credentials);
876 if(result == UP_AUTH_OK){
877 if(tracing) {
878 printf("TRACING: Will send the obj to be deleted\n");
879 }
880 if(strcmp(type, "key-cert") == 0){
881 result_from_delete_key = delete_key(arg);
882 }else{
883 result_from_delete_key = NULL;
884 }
885 /* if there was no problem with key deletion from the key-ring */
886 if(result_from_delete_key == NULL){
887 result_from_RIPupd = send_object_db(arg, NULL, "DEL");
888 if(result_from_RIPupd->result == 0){
889 AK_add_to_ack(ack_file_name, "\nDelete OK: [%s] %s\n",
890 o->type->getName(), get_search_key(o, o->type->getName(), arg));
891 NT_write_all_ntfs(arg, NULL, NULL, tmpdir, ntfy_hash, forw_hash, cross_hash,
892 credentials.from);
893 return UP_OK;
894 }else{
895 AK_add_to_ack(ack_file_name, "\nDelete FAILED: [%s] %s\n%s\n",
896 o->type->getName(), get_search_key(o, o->type->getName(), arg),
897 result_from_RIPupd->error_str);
898 return UP_INT;
899 }
900 result_from_RIPupd = 0;
901 }else{
902 AK_add_to_ack(ack_file_name, "\nDelete FAILED: [%s] %s\n%s\n",
903 o->type->getName(), get_search_key(o, o->type->getName(), arg), result_from_delete_key);
904 return UP_INT;
905 }
906 }else{ /* auth failed */
907 if(tracing) {
908 printf("TRACING: Auth failed\n");
909 }
910
911 AK_add_to_ack(ack_file_name, "\nDelete FAILED: [%s] %s\nAuthorisation failed, request forwarded to maintainer.\n%s\n",
912 o->type->getName(), get_search_key(o, o->type->getName(), arg), delete_override(arg));
913 NT_write_all_frwds(arg, NULL, tmpdir, ntfy_hash, forw_hash, cross_hash, credentials.from);
914 return UP_AUF; /* Auth failed */
915 }
916 }else{/* the new & old versions do not match */
917 AK_add_to_ack(ack_file_name, "\nDelete FAILED: new & old versions do not match\n%s\n", delete_override(arg));
918 return UP_NOM; /* new & old versions do not match */
919 }
920 }
921
922 }else{/* syntax error AND not deletion */
923 AK_add_to_ack(ack_file_name, "\nUpdate FAILED: Syntax error in object\n");
924
925 if(o->attrs.head() != NULL){
926 for(attr = o->attrs.head(); attr; attr = o->attrs.next(attr)){
927 if(attr->len > 0 &&
928 ( attr->type == NULL || (attr->type != NULL && strcasecmp(attr->type->name(), "override") != 0)) ){
929 value = (char*)malloc(attr->len);
930 strncpy(value, (char *)(arg+attr->offset) ,
931 attr->len - 1);
932 value[attr->len - 1] = '\0';
933 AK_add_to_ack(ack_file_name, "%s\n", value);
934 if(!attr->errors.empty()){
935 AK_add_to_ack_string(ack_file_name, attr->errors);
936 }
937 free(value);
938 }else{
939 if(!attr->errors.empty()){
940 AK_add_to_ack_string(ack_file_name, attr->errors);
941 }
942 }
943 }
944 }
945 if(o->has_error){
946 AK_add_to_ack_string(ack_file_name, o->errors);
947 }
948 AK_add_to_ack(ack_file_name, "\n");
949
950 return UP_SYN; /* syntax error */
951 }
952 }
953 }
954
955
956
957
958
959 /* processes the objects in the given file */
960 void process_file(char * filename, credentials_struct credentials,
/* [<][>][^][v][top][bottom][index][help] */
961 GHashTable * AUTO_NIC_hdl_hash, char * ack_file_name,
962 GHashTable * ntfy_hash, GHashTable * forw_hash, GHashTable * cross_hash){
963
964 FILE * input_file;
965 GSList *list_of_objects = NULL, *list_of_objects2 = NULL;
966 GSList *next = NULL;
967 int object_count = 0;
968 char *object = NULL;
969 char * line;
970 char * lwrcase_line;
971 int result = 0;
972 struct VerifySignObject vSO, *pvSO;
973
974
975
976 line = (char *)malloc(1024);
977
978 if((input_file = fopen(filename, "r")) == NULL){
979 ER_perror(FAC_UP, UP_CANTOPEN, "Couldn't open the file %s: %s\n", filename, strerror(errno));
980 exit(1);
981 }
982
983
984 while(fgets(line, 1023, input_file) != NULL){
985 /* first, if it is a pasword, save it, but do not regard it as an attrib */
986 lwrcase_line = strdup(line);
987 g_strdown(lwrcase_line);
988 if(strstr(lwrcase_line, "password:") == lwrcase_line){
989 if(tracing){
990 printf("TRACING: This is a password\n");
991 }
992 credentials.password_list = g_slist_append(credentials.password_list,
993 g_strstrip(strdup(line + strlen("password:"))));
994 continue;
995 }
996 free(lwrcase_line);
997
998 line = UP_remove_EOLs(line); /* remove '\n's and '\r' first */
999 /* remove trailing white space */
1000 line = g_strchomp(line);
1001 if(strlen(line) == 0){/* then, this was an empty line */
1002 if(object != NULL){
1003 list_of_objects = g_slist_append(list_of_objects, object);
1004 if(tracing){
1005 printf("TRACING: added an object: [%s]\n", object);
1006 }
1007 object = NULL;
1008 }
1009 }else{
1010 if(object == NULL && strlen(line) != 0){
1011 object = (char *)malloc(strlen(line) + 2);
1012 object = strcpy(object, line);
1013 object = strcat(object, "\n"); /* add EOL again (we removed it before) */
1014 }
1015 else{
1016 object = (char *)realloc(object, strlen(object) + strlen(line) + 2);
1017 object = strcat(object, line);
1018 object = strcat(object, "\n");
1019 }
1020 }
1021
1022 }
1023 fclose(input_file);
1024
1025 /* now, if at the very and of the input file there wasn't an
1026 empty line, we have to add the remaining object in the 'object'
1027 variable */
1028 if(object != NULL){
1029 list_of_objects = g_slist_append(list_of_objects, object);
1030 object = NULL;
1031 }
1032
1033
1034
1035 if(tracing) {
1036 printf("TRACING: Will process the objects in the list\n");
1037 }
1038 next = list_of_objects;
1039 object_count = 0;
1040 for( next = list_of_objects; next != NULL ; next = g_slist_next(next) ){
1041
1042 if(UP_is_object((char *)next->data)){/* if this looks like an object */
1043
1044 object_count++;
1045
1046 if(tracing) {
1047 cout << "TRACING: Got an object from the list" << endl;
1048 cout << (char *)next->data << endl;
1049 }
1050
1051 if(has_ref_to_AUTO_nic_hdl((char *)next->data)){/* defer the processing */
1052 if(tracing) {
1053 printf("TRACING: this object has a ref to an AUTO NIC hdl\n");
1054 }
1055 list_of_objects2 = g_slist_append(list_of_objects2, strdup((char *)next->data));
1056 }else{
1057 result = 0;
1058 result = process_object((char *)next->data, credentials, AUTO_NIC_hdl_hash, ack_file_name,
1059 ntfy_hash, forw_hash, cross_hash);
1060 /* keep a tally */
1061 if(result == UP_OK){
1062 count_successful++;
1063 }else{
1064 count_unsuccessful++;
1065 }
1066
1067 }
1068 }else{/* this does not look like an object (a signature? some other text?) */
1069
1070 AK_add_to_ack(ack_file_name, "\nThe following paragraph does not look like an object,\n"
1071 "so ignoring it:\n%s\n", (char *)next->data);
1072
1073 }
1074 }
1075
1076
1077 if(tracing) {
1078 printf("TRACING: list_of_objects2 has %d entries\n", g_slist_length(list_of_objects2));
1079 }
1080
1081 if(tracing) {
1082 printf("TRACING: will start to process the second list\n");
1083 }
1084
1085 for( next = list_of_objects2; next != NULL ; next = g_slist_next(next) ){
1086 if(tracing) {
1087 printf("TRACING: Will process object: %s\n", (char *)next->data);
1088 }
1089 result = process_object((char *)next->data, credentials, AUTO_NIC_hdl_hash, ack_file_name,
1090 ntfy_hash, forw_hash, cross_hash);
1091 /* keep a tally */
1092 if(result == UP_OK){
1093 count_successful++;
1094 }else{
1095 count_unsuccessful++;
1096 }
1097
1098 }
1099
1100 }/* process_file */
1101
1102
1103
1104
1105
1106
1107 /* Generates a unique file name and returns the full path of the filename
1108 for storing notification message. */
1109
1110 char * generate_upd_file(){
/* [<][>][^][v][top][bottom][index][help] */
1111
1112 char * name;
1113
1114 /* allocate space for name. 32 should be enough for PID */
1115 name = (char*)malloc(strlen(tmpdir) + strlen("/dbupdate-tmp.") + 32 );
1116
1117 sprintf(name, "%s/dbupdate-tmp.%i", tmpdir, pid /*getpid()*/);
1118
1119
1120 return name;
1121
1122 }
1123
1124
1125 /* create_lock_file: creates a lock file in lockdir and locks it. This is a
1126 part of crash recovery. Must be called in the beginning of the run. At the
1127 end, the file must be removed. */
1128 /* The idea: Create the "lock" file, and lock it. When another process starts
1129 running, it checks the existing lock files. If some exists, then it checks
1130 if it is locked or not. It not locked, then assumes that the corresponding
1131 dbupdate is alredy running. If not locked, assumes that it has crashed.
1132 (note: when a process crashes, the kernel releases all the files locked by
1133 this process [by the OS])
1134 Problem: locking doesn't work properly on some NFS implementations. */
1135
1136 lockfilestruct create_lock_file(){
/* [<][>][^][v][top][bottom][index][help] */
1137
1138 lockfilestruct lock;
1139 int file;
1140 int length;
1141
1142 /* allocate space for file name */
1143 length = strlen(lockdir) + strlen(hostname) + 32;
1144 lock.lockname = (char *)malloc(length + 1);
1145
1146 snprintf(lock.lockname, length, "%s/dbupdate.%s.%ld", lockdir, hostname, pid /*getpid()*/);
1147
1148 /* we will lock the file, so we have to use open(), but not fopen() (see man
1149 page of lockf(3C)) */
1150 if(( file = open(lock.lockname, O_RDWR|O_CREAT)) == -1){
1151 ER_perror(FAC_UP, UP_CANTOPEN, "Can't open lock file, %s", lock.lockname);
1152 exit(1);
1153 }
1154
1155 if(lockf(file, F_LOCK, 0) == -1){
1156 ER_perror(FAC_UP, UP_CANTLOCK, "Can't lock the file, %s", lock.lockname);
1157 exit(1);
1158 };
1159
1160 lock.filedes = file;
1161
1162 return lock;
1163
1164 }
1165
1166
1167
1168
1169
1170 /* remove_lock_file(): unlocks and removes the file */
1171 void remove_lock_file(lockfilestruct lockfile){
/* [<][>][^][v][top][bottom][index][help] */
1172
1173 close(lockfile.filedes); /* this will remove the lock at the same time */
1174 unlink(lockfile.lockname);
1175
1176 }
1177
1178
1179
1180 /* writes the checkpoint file with the specified state */
1181 void write_checkpoint(int state){
/* [<][>][^][v][top][bottom][index][help] */
1182
1183 char * filename;
1184 char * tmpfilename;
1185 int length;
1186 FILE * file;
1187
1188 if(tracing){
1189 printf("TRACING: write_checkpoint, state=[%i]\n", state);
1190 }
1191 length = strlen(lockdir) + strlen(hostname) + 64;
1192 filename = (char *)malloc(length + 1);
1193 tmpfilename = (char *)malloc(length + 5);
1194
1195 snprintf(filename, length, "%s/dbupdate.checkpoint.%s.%ld", lockdir, hostname, pid );
1196 snprintf(tmpfilename, length, "%s/dbupdate.checkpoint.%s.%ld.tmp", lockdir, hostname, pid );
1197
1198 if(( file = fopen(tmpfilename, "w")) == NULL){
1199 //fprintf(stderr, "Can't open temp checkpoint file, %s", tmpfilename);
1200 ER_perror(FAC_UP, UP_CANTOPEN, "Can't open temp checkpoint file, %s", tmpfilename);
1201 exit(1);
1202 }
1203
1204 fprintf(file, "[STATE]\n%i\n", state);
1205
1206 fprintf(file, "[FLAGS]\n");
1207 /* should print the flags here */
1208
1209 fprintf(file, "[PARTS]\n");
1210 /* should print the parts (filenames) here */
1211
1212 fprintf(file, "[OBJECTS1]\n");
1213
1214 fprintf(file, "[OBJECTS2]\n");
1215
1216 fprintf(file, "[ACKFILE]\n");
1217
1218 fprintf(file, "[NOTIFFILES]\n");
1219
1220 fprintf(file, "[TIDS1]\n");
1221
1222 fprintf(file, "[TIDS2]\n");
1223
1224 fprintf(file, "[NICHDLHASH]\n");
1225
1226 fprintf(file, "[CURRENTOBJECT]\n");
1227
1228 fprintf(file, "[CURRENTPART]\n");
1229
1230
1231 fclose(file);
1232
1233 rename(tmpfilename, filename);
1234
1235 /* free the char *'s */
1236 free(tmpfilename);
1237 free(filename);
1238
1239 }
1240
1241
1242
1243
1244 /* removes check point file */
1245 void remove_checkpoint(){
/* [<][>][^][v][top][bottom][index][help] */
1246
1247 char * filename;
1248 int length;
1249 FILE * file;
1250
1251 if(tracing){
1252 printf("TRACING: remove_checkpoint\n");
1253 }
1254
1255 length = strlen(lockdir) + strlen(hostname) + 64;
1256 filename = (char *)malloc(length + 1);
1257
1258 snprintf(filename, length, "%s/dbupdate.checkpoint.%s.%ld", lockdir, hostname, pid );
1259
1260 unlink(filename);
1261
1262 /* free the char * */
1263 free(filename);
1264
1265 }
1266
1267
1268
1269
1270
1271
1272
1273 /* main */
1274 void main(int argc, char **argv, char **envp){
/* [<][>][^][v][top][bottom][index][help] */
1275 //init_and_set_options(argc, argv, envp);
1276
1277 int count = 0;
1278 int i,j;
1279 int no_of_updateables = 0;
1280 char ** temp_vector;
1281 char * temp;
1282 char * temp_upd_file = NULL;
1283 char *input_file_name = NULL;
1284 GHashTable *AUTO_NIC_hdl_hash;
1285 credentials_struct credentials;
1286 FILE * upd_file;
1287 char c;
1288 char * mheader_replaced = NULL;
1289 char * mailtxt_replaced = NULL;
1290
1291 /* temp variables to read from conf */
1292 char * source = NULL, * canupd = NULL;
1293 ca_dbSource_t *source_hdl;
1294 ca_updDbSource_t *upd_source_hdl;
1295
1296 GHashTable *ntfy_hash, *forw_hash, *cross_hash;
1297
1298
1299 char *mail_command_line, * ack_file_name;
1300 char *config_file_name = NULL;
1301
1302
1303
1304 /* to use EP module */
1305 EP_Mail_DescrPtr p;
1306 EPTokenPtr pt;
1307 EPTokenPtr list_item;
1308 EPTokenKeysPtr ptk;
1309
1310 char * temp_keyid;
1311
1312 /* a variable to be used to know if the part is pgp_signed or not */
1313 int pgp_signed = 0;
1314
1315 long debug = 0;
1316
1317
1318 /* create notification hashes */
1319 ntfy_hash = g_hash_table_new(g_str_hash, g_str_equal);
1320 forw_hash = g_hash_table_new(g_str_hash, g_str_equal);
1321 cross_hash = g_hash_table_new(g_str_hash, g_str_equal);
1322
1323 credentials.password_list = NULL;
1324 credentials.from = NULL;
1325 int ch;
1326 char * to_address = NULL;
1327 char * subject = NULL;
1328 char * reply_to = NULL;
1329
1330 AUTO_NIC_hdl_hash = g_hash_table_new(g_str_hash, g_str_equal);
1331
1332
1333
1334
1335 while ((ch = getopt(argc, argv, "MtSTf:c:sn")) != -1){
1336 switch(ch) {
1337 case 'M':
1338 reading_from_mail = 1;
1339 break;
1340 case 'f':
1341 input_file_name = strdup(optarg);
1342 break;
1343 case 'c':
1344 config_file_name = strdup(optarg);
1345 break;
1346 case 't':
1347 tracing = 1;
1348 break;
1349 /* Test mode? In test mode, creation of mntners and as-blocks is possible, without overriding */
1350 case 'T':
1351 test_mode = 1;
1352 break;
1353 /* Supress acks and notifications? If yes, the acks and notifs will go to DEFMAIL config var */
1354 case 'S':
1355 supress_ack_notif = 1;
1356 break;
1357 /* Print out the ack to stdout? */
1358 case 's':
1359 print_out_ack = 1;
1360 break;
1361 /* are we processing networkupdate? (invoked via inetd) */
1362 case 'n':
1363 networkupdate = 1;
1364 break;
1365 case '?':
1366 default:
1367 printf("Unknown option\n"); exit(1);
1368 }
1369 }
1370
1371
1372 /* config stuff */
1373 /* if -c flag is given, use the named file as config file, otherwise use
1374 default filename */
1375 if( config_file_name != NULL){
1376 /*ca_readConfig(config_file_name, confVars, VARS);*/
1377 ca_init(config_file_name);
1378 }else{
1379 /*ca_readConfig("dbupdate.conf", confVars, VARS);*/
1380 ca_init("dbupdate.conf");
1381 }
1382
1383 error_init(argc, argv);
1384
1385
1386 tmpdir = ca_get_tmpdir;
1387 tmpdir = g_strstrip(tmpdir);
1388 lockdir = ca_get_lockdir;
1389 mailcmd = ca_get_mailcmd;
1390 mailcmd = g_strstrip(mailcmd);
1391 notitxt = ca_get_notitxt;
1392 mailtxt = ca_get_mailtxt;
1393 successtxt = ca_get_successtxt;
1394 failuretxt = ca_get_failuretxt;
1395 defmail = ca_get_defmail; defmail = UP_remove_EOLs(defmail);
1396 crosslog = ca_get_crosslog;
1397 fwtxt = ca_get_fwtxt;
1398 acksig = ca_get_acksig;
1399 humailbox = ca_get_humailbox;
1400 humailbox = g_strstrip(humailbox);
1401 autobox = ca_get_autobox;
1402 overridecryptedpw = ca_get_overridecryptedpw;
1403 overridecryptedpw = g_strstrip(overridecryptedpw);
1404 updlog = ca_get_updlog;
1405 acklog = ca_get_acklog;
1406 notiflog = ca_get_notiflog;
1407 notimailtxt = ca_get_notimailtxt;
1408 notinetworktxt = ca_get_notinetworktxt;
1409 forwlog = ca_get_forwlog;
1410 fwmailtxt = ca_get_fwmailtxt;
1411 mtfwheader = ca_get_mtfwheader;
1412 mtfwtxt = ca_get_mtfwtxt;
1413 country = ca_get_country;
1414 pgppath = ca_get_pgppath;
1415 gpgcmd = ca_get_gpgcmd;
1416 autodbmhelp = ca_get_autodbmhelp;
1417 allocmnt = ca_get_allocmnt; allocmnt = UP_remove_EOLs(allocmnt);
1418 /* convert all '\t's, '\n's and '\r's in allocmnt to white spaces */
1419 for(i=0;i<strlen(allocmnt);i++){
1420 if(allocmnt[i] == '\r' || allocmnt[i] == '\n' || allocmnt[i] == '\t'){
1421 allocmnt[i] = ' ';
1422 }
1423 }
1424 cn_subject_add = ca_get_cn_subject_add; cn_subject_add = UP_remove_EOLs(cn_subject_add);
1425 cn_subject_del = ca_get_cn_subject_del; cn_subject_del = UP_remove_EOLs(cn_subject_del);
1426 cn_explain_add = ca_get_cn_explain_add;
1427 cn_explain_del = ca_get_cn_explain_del;
1428 cn_overlap_add = ca_get_cn_overlap_add;
1429 cn_overlap_del = ca_get_cn_overlap_del;
1430 cno_subject_add = ca_get_cno_subject_add; cno_subject_add = UP_remove_EOLs(cno_subject_add);
1431 cno_subject_del = ca_get_cno_subject_del; cno_subject_del = UP_remove_EOLs(cno_subject_del);
1432 cno_explain_add = ca_get_cno_explain_add;
1433 cno_explain_del = ca_get_cno_explain_del;
1434 cno_overlap_add = ca_get_cno_overlap_add;
1435 cno_overlap_del = ca_get_cno_overlap_del;
1436 copyright_notice = ca_get_pw_resp_header;
1437 mheader = ca_get_mheader;
1438 pgp_public_key_ring = (char *)malloc(strlen(pgppath) + strlen("/pubring.gpg") + 2);
1439 sprintf(pgp_public_key_ring ,"%s/pubring.gpg", pgppath);
1440 if(test_mode != 1){/* if it is not already set to 1 (from command line), read from config */
1441
1442 test_mode = ca_get_testmode;
1443 }
1444 /* retrieve source variables */
1445 upd_source_hdl = ca_get_UpdSourceHandle(CA_UPDSOURCE);
1446
1447 if(upd_source_hdl == NULL){
1448 printf("There must be one updateable source in the config file. Exiting.\n");
1449 ER_perror(FAC_UP, UP_CONFERR, "There must be one updateable source in"
1450 " the config file. Exiting.");
1451 exit(1);
1452 }else{
1453 if(tracing){
1454 printf("\nTRACING: The upd_source_hdl is: %s\n", upd_source_hdl->name);
1455 }
1456 sources[0] = strdup(upd_source_hdl->name);
1457 update_host = upd_source_hdl->whoisd_host;
1458 query_host = strdup(update_host);
1459 update_port = upd_source_hdl->updPort;
1460 query_port = upd_source_hdl->qryPort;
1461 DBhost = upd_source_hdl->updDb.host;
1462 DBport = upd_source_hdl->updDb.port;
1463 DBname = upd_source_hdl->updDb.dbName;
1464 DBuser = upd_source_hdl->updDb.user;
1465 DBpasswd = upd_source_hdl->updDb.password;
1466 }
1467
1468
1469
1470 /* construct country array from country string variable */
1471
1472 temp_vector = g_strsplit(country, "\n", 0);
1473 for(i=0, j=0; temp_vector[i] != NULL; i++){
1474 temp_vector[i] == g_strstrip(temp_vector[i]);
1475 if(strlen(temp_vector[i]) > 0){
1476 countries[j] = strdup(temp_vector[i]);
1477 g_strup(countries[j]);
1478 j++;
1479 }
1480 }
1481 countries[j] = NULL; /* mark the end of array */
1482
1483 if(tracing){
1484 /* print out the config variables for debugging */
1485 printf("TRACING: countries[%i] = NULL\n", j);
1486
1487 printf("TMPDIR is: [%s]\n", tmpdir);
1488 printf("MAILCMD is: [%s]\n", mailcmd);
1489 printf("NOTITXT is: [%s]\n", notitxt);
1490 printf("CROSSLOG is: [%s]\n", crosslog);
1491 printf("FWTXT is: [%s]\n", fwtxt);
1492 printf("HUMAILBOX is: [%s]\n", humailbox);
1493 printf("AUTOBOX is: [%s]\n", autobox);
1494 printf("OVERRIDECRYPTEDPW is: [%s]\n", overridecryptedpw);
1495 printf("ACKLOG is: [%s]\n", acklog);
1496 printf("NOTIFLOG is: [%s]\n", notiflog);
1497 printf("FORWLOG is: [%s]\n", forwlog);
1498 printf("NOTIMAILTXT is: [%s]\n", notimailtxt);
1499 printf("FWMAILTXT is: [%s]\n", fwmailtxt);
1500 printf("COUNTRY is: [%s]\n", country);
1501 printf("PGPPATH is: [%s]\n", pgppath);
1502 printf("UPDATE_HOST is: [%s]\n", update_host);
1503 printf("UPDATE_PORT is: [%i]\n", update_port);
1504 printf("QUERY_HOST is: [%s]\n", query_host);
1505 printf("QUERY_PORT is: [%i]\n", query_port);
1506 printf("LOCKDIR is: [%s]\n", lockdir);
1507 printf("TESTMODE is: [%i]\n", test_mode);
1508 printf("CNO_SUBJECT_ADD is: [%s]\n", cno_subject_add);
1509 printf("CNO_SUBJECT_DEL is: [%s]\n", cno_subject_del);
1510 }
1511 /* end of config stuff */
1512
1513
1514 /* set hostname global variable */
1515 gethostname(hostname, MAXHOSTNAMELEN);
1516
1517 /* set pid global variable */
1518 pid = getpid();
1519
1520 /* create the lock file and lock it */
1521 //lockfile = create_lock_file();
1522
1523
1524 /* initialize the parser */
1525 schema.initialize();
1526
1527
1528 /* Generate a name for temporary file for storing acks (AK_ack_file_name_generate
1529 also creates it) */
1530 ack_file_name = AK_ack_file_name_generate(tmpdir, ACK_FILE_PREFIX);
1531
1532 /* initialize credentials.pgp_key_list */
1533 credentials.pgp_key_list = NULL;
1534
1535
1536
1537
1538 if(reading_from_mail){
1539 if(input_file_name != NULL){
1540 temp_upd_file = generate_upd_file();
1541 if(tracing){
1542 printf("TRACING: temp_upd_file is [%s]\n", temp_upd_file);
1543 }
1544
1545 /* first log the input in the upd log file */
1546 UP_add_to_upd_log(input_file_name);
1547
1548
1549 MM_store(input_file_name, temp_upd_file, 0);
1550 p = EP_ParseMail(input_file_name, tmpdir, pgp_public_key_ring, gpgcmd);
1551
1552 }else{/* input_file_name == NULL */
1553 temp_upd_file = generate_upd_file();
1554 MM_store("-", temp_upd_file, 0);
1555
1556 /* first log the input in the upd log file */
1557 UP_add_to_upd_log(temp_upd_file);
1558
1559 p = EP_ParseMail(temp_upd_file, tmpdir, pgp_public_key_ring, gpgcmd);
1560
1561 }
1562
1563 /* write off the checkpoint file */
1564 write_checkpoint(1);
1565
1566 /* the new stuff using the EP module's interface */
1567 if(tracing){
1568 printf("\nTRACING: From field is: [%s]\n", p->from->field);
1569 if(p->from->next != NULL){
1570 printf("TRACING: From field (second line) is: [%s]\n", p->from->next->field);
1571 }
1572 }
1573
1574 temp = (char *)malloc(strlen(p->from->field) + strlen("From: ") + 1);
1575 sprintf(temp, "From: %s", p->from->field);
1576 /* cut off the '\n's and '\r's at the end of temp */
1577 UP_remove_EOLs(temp);
1578
1579 /* now, there is a problem with EP module (or c-client): the p->from->field
1580 would contain only the first line if the "From" field has multiple lines.
1581 As a temp solution, we will add the second line (if it exists) explicitely */
1582 if(p->from->next != NULL){/* if the second line exists */
1583 temp = (char *)realloc(temp, strlen(temp) + strlen(p->from->next->field) + 2);
1584 snprintf(temp, strlen(temp) + strlen(p->from->next->field) + 2,
1585 "%s %s", temp, p->from->next->field);
1586 }
1587 UP_remove_EOLs(temp);
1588
1589
1590 credentials.from = temp;
1591 credentials.from_email = strdup(p->from->field); /* This doesn't contain "From:" */
1592 if(p->from->next != NULL){ /* if the second line exists */
1593 credentials.from_email = (char *)realloc(credentials.from_email, strlen(credentials.from_email) +
1594 strlen(p->from->next->field) + 2);
1595 snprintf(credentials.from_email, strlen(credentials.from_email) +
1596 strlen(p->from->next->field) + 2,
1597 "%s %s", credentials.from_email, p->from->next->field);
1598 }
1599 UP_remove_EOLs(credentials.from_email);
1600
1601
1602 update_mail_sender = strdup(credentials.from_email);
1603 update_mail_sender = UP_remove_EOLs(update_mail_sender);
1604
1605 if(tracing){
1606 printf("\nTRACING: update_mail_sender is: [%s]\n", update_mail_sender);
1607 }
1608
1609
1610 if(p->subject != NULL && p->subject->field != NULL){
1611 subject = strdup(p->subject->field);
1612 }else{
1613 subject = strdup("");
1614 }
1615
1616 /* cut off the '\n' and '\r' from the end */
1617 UP_remove_EOLs(subject);
1618
1619 update_mail_subject = strdup(subject);
1620
1621 /* parse the subject line */
1622 subject_result = UP_subject_process(update_mail_subject);
1623
1624
1625 if(p->reply_to != NULL && p->reply_to->field != NULL){
1626 reply_to = strdup(p->reply_to->field);
1627 }else{
1628 reply_to = strdup("");
1629 }
1630
1631
1632 /* cut off the '\n' and '\r' from the end */
1633 UP_remove_EOLs(reply_to);
1634
1635
1636 to_address = find_email_address(credentials.from);
1637
1638 /* if Reply_To was available in the incoming header, then use it */
1639 if(strlen(reply_to) > 0){
1640 to_address = (char *)realloc(to_address, strlen(reply_to) + 1);
1641 to_address = strcpy(to_address, reply_to);
1642 to_address = find_email_address(to_address); /* so that we take only the email address */
1643 }
1644
1645 if(p->message_id != NULL && p->message_id->field != NULL){
1646 update_mail_ID = strdup(p->message_id->field);
1647 }else{
1648 update_mail_ID = strdup("");
1649 }
1650
1651 /* cut off the '\n' and '\r' from the end */
1652 UP_remove_EOLs(update_mail_ID);
1653
1654
1655 if(p->date != NULL && p->date->field != NULL){
1656 update_mail_date = strdup(p->date->field);
1657 }else{
1658 update_mail_date = strdup("");
1659 }
1660
1661 /* cut off the '\n' and '\r' from the end */
1662 UP_remove_EOLs(update_mail_date);
1663
1664
1665 if(tracing){
1666 printf("\nEP_ShowTree outputs:\n");
1667 EP_ShowTree(p->tree);
1668 }
1669
1670 pt = EP_GetTokens(p->tree, NULL, NULL);
1671
1672 if(tracing){
1673 /* Print the list out (debugging) */
1674 printf("\nEP_PrintTokens outputs:\n");
1675 EP_PrintTokens(pt);
1676 }
1677
1678 /* replace the global variables in mheader */
1679 mheader_replaced = UP_replace_globals(mheader);
1680 /* replace the global variables in mailtxt */
1681 mailtxt_replaced = UP_replace_globals(mailtxt);
1682
1683 /* If this wasn't only a help request, then we need to process the input */
1684 if(subject_result.result != UP_SUBJ_HELP_REQ){
1685
1686 /* ... and now process the items in the list */
1687 list_item = pt;
1688 while (list_item != NULL) {
1689 if(tracing){
1690 printf("\n\nWill process: %s, MIMEtype: %d\n", list_item->file, list_item->MIMEContentType);
1691 }
1692 /* initialize pgp_key_list (XXX This should be a proper freeing of the list) */
1693 credentials.pgp_key_list = NULL;
1694 ptk = list_item->keys;
1695 if(ptk != NULL){
1696 AK_add_to_ack(ack_file_name, "==== BEGIN PGP SIGNED PART (keyID(s):");
1697 pgp_signed = 1;
1698 while (ptk != NULL) {
1699 if(tracing){
1700 printf("TRACING: key: %.8X, isValid: %i\n",
1701 ptk->keyID, ptk->isValidPGPSignature);
1702 }
1703 temp_keyid = (char *)malloc(10);
1704 sprintf(temp_keyid, "%.8X", ptk->keyID);
1705 if(tracing){
1706 printf("TRACING: This key will be added to the list: [%s]\n", temp_keyid);
1707 }
1708 AK_add_to_ack(ack_file_name, " %s", temp_keyid);
1709 credentials.pgp_key_list = g_slist_append (credentials.pgp_key_list, temp_keyid);
1710 ptk = ptk->next;
1711 if(ptk != NULL){
1712 AK_add_to_ack(ack_file_name, ",");
1713 }else{
1714 AK_add_to_ack(ack_file_name, ") ====\n");
1715 }
1716 }
1717 }
1718 process_file(list_item->file, credentials,
1719 AUTO_NIC_hdl_hash, ack_file_name,
1720 ntfy_hash, forw_hash, cross_hash);
1721 if(pgp_signed){
1722 AK_add_to_ack(ack_file_name, "==== END PGP SIGNED PART ====\n\n");
1723 pgp_signed = 0;
1724 }
1725 list_item = list_item->next;
1726 }
1727
1728 }else{/* this was only a help request (inferred from the "Subject" line of the upd message) */
1729
1730 /* Print out the header of the acknowledgement */
1731 AK_add_to_ack(ack_file_name, "To: %s\n%s\n\nHelp file requested so body of message ignored.\n\n\n"
1732 "============================================================\n\n",
1733 to_address, mheader_replaced);
1734
1735 AK_add_file_to_ack(ack_file_name, autodbmhelp);
1736 AK_add_to_ack(ack_file_name, "\n============================================================");
1737
1738 }
1739
1740 EP_CleanTokens(pt);
1741
1742 EP_MailDescrCleanUp(p);
1743
1744 /* if we have created a temporary file for update, delete it */
1745 if(temp_upd_file != NULL){
1746
1747 unlink(temp_upd_file);
1748
1749 }
1750
1751 }else if(networkupdate){
1752
1753 /* process networkupdate. Since we use inetd, we just process stdin */
1754 process_networkupdate(credentials, AUTO_NIC_hdl_hash, ack_file_name,
1755 ntfy_hash, forw_hash, cross_hash);
1756
1757 }else{/* not reading from the mail message or from network */
1758 if(input_file_name != NULL){
1759
1760 /* first log the input in the upd log file */
1761 UP_add_to_upd_log(input_file_name);
1762
1763
1764 write_checkpoint(1);
1765 process_file(input_file_name, credentials,
1766 AUTO_NIC_hdl_hash, ack_file_name,
1767 ntfy_hash, forw_hash, cross_hash);
1768 }else{/* the filename is not given, so we have to write
1769 stdin to a temp file, and give it to process_file */
1770 temp_upd_file = generate_upd_file();
1771 if(tracing){
1772 printf("TRACING: main: temp_upd_file=%s\n", temp_upd_file);
1773 }
1774 if(( upd_file = fopen(temp_upd_file, "a")) == NULL){
1775 ER_perror(FAC_UP, UP_CANTOPENW, "Can't open ack file, %s", temp_upd_file);
1776 }
1777
1778 while((c = getchar()) != EOF){
1779 fprintf(upd_file, "%c",c);
1780 }
1781 fclose(upd_file);
1782
1783 write_checkpoint(1);
1784 process_file(temp_upd_file, credentials,
1785 AUTO_NIC_hdl_hash, ack_file_name,
1786 ntfy_hash, forw_hash, cross_hash);
1787 unlink(temp_upd_file);
1788
1789 }
1790
1791 }
1792
1793
1794 /* post-process and send the ack */
1795 if(reading_from_mail && to_address != NULL){
1796 AK_send_ack(ack_file_name, to_address, mailcmd);
1797 }
1798
1799 /* if our update wasn't a mail update OR we have been asked explicitely
1800 to print out the ack to the stdout, print it */
1801 if(!reading_from_mail || print_out_ack){
1802 AK_print_ack(ack_file_name);
1803 }
1804
1805 AK_log_ack(ack_file_name, acklog);
1806 AK_delete_ack(ack_file_name);
1807
1808 NT_send_ntfy_list(ntfy_hash, mailcmd);
1809 NT_log_ntfy_list(ntfy_hash, notiflog);
1810 NT_delete_ntfy_list(ntfy_hash);
1811
1812 NT_send_ntfy_list(forw_hash, mailcmd);
1813 NT_log_ntfy_list(forw_hash, forwlog);
1814 NT_delete_ntfy_list(forw_hash);
1815
1816
1817 NT_send_ntfy_list(cross_hash, mailcmd);
1818 NT_log_ntfy_list(cross_hash, crosslog);
1819 NT_delete_ntfy_list(cross_hash);
1820
1821 /* remove the lock file */
1822 //remove_lock_file(lockfile);
1823
1824
1825 /* remove checkpoint file */
1826 remove_checkpoint();
1827
1828
1829
1830 if(tracing) {
1831 printf("TRACING: END\n");
1832 }
1833
1834
1835 }