OSDN Git Service

accept [enter] as the default option [Y]
[openpts/openpts.git] / src / openpts.c
1 /*
2  * This file is part of the OpenPTS project.
3  *
4  * The Initial Developer of the Original Code is International
5  * Business Machines Corporation. Portions created by IBM
6  * Corporation are Copyright (C) 2010 International Business
7  * Machines Corporation. All Rights Reserved.
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the Common Public License as published by
11  * IBM Corporation; either version 1 of the License, or (at your option)
12  * any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * Common Public License for more details.
18  *
19  * You should have received a copy of the Common Public License
20  * along with this program; if not, a copy can be viewed at
21  * http://www.opensource.org/licenses/cpl1.0.php.
22  */
23
24 /**
25  * \file src/openpts.c
26  * \brief main of openpts command
27  * @author Seiji Munetoh <munetoh@users.sourceforge.jp>
28  * @date 2010-07-25
29  * cleanup 2011-07-20 SM
30  *
31  * This is verifier and utility to maintain the collector/verifier
32  *
33  *
34  *
35  */
36
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <netdb.h>
41 #include <errno.h>
42
43 #include <sys/types.h>
44 #include <sys/socket.h>
45 #include <sys/stat.h>
46 #include <netinet/in.h>
47 #include <fcntl.h>
48
49 #include <unistd.h>
50 #include <sys/wait.h>
51 #include <dirent.h>
52 #include <limits.h>
53
54 // #define USE_SCANDIR
55
56 #include <openpts.h>
57
58 int verbose = 0; /**< DEBUG */
59
60 // DEBUG
61 // /usr/sbin/ptsc -m
62 // /PATH/ptsc -m -c XXX
63 // openpts -P PATH -C CONF
64 extern char *ptsc_command;
65
66 #define LINE "--------------------------------------------------------------------"
67
68 /**
69  * Usage
70  */
71 void usage(void) {
72     fprintf(stderr, "OpenPTS command\n\n");
73     fprintf(stderr, "Usage: openpts [options] {-i [-f]|[-v]|-D} <target>\n");
74     fprintf(stderr, "       openpts -D\n\n");
75     fprintf(stderr, "Commands:\n");
76     fprintf(stderr, "  -i [-f]               Initialize [forcibly] the PTS verifier with the target(collector).\n");
77     fprintf(stderr, "  [-v]                  Verify target(collector) integrity against know measure.\n");
78     fprintf(stderr, "  -D                    Display the configuration (target/ALL)\n");
79     fprintf(stderr, "\n");
80     fprintf(stderr, "Miscellaneous:\n");
81     fprintf(stderr, "  -h                    Show this help message\n");
82     fprintf(stderr, "  -V                    Verbose mode. Multiple -V options increase the verbosity.\n");
83     fprintf(stderr, "\n");
84     fprintf(stderr, "Options:\n");
85 #ifdef CONFIG_AUTO_RM_UPDATE
86     fprintf(stderr, "  -u                    "
87                     "Selects 'yes' as the the default answer when an update is available [no]\n");
88 #endif
89     fprintf(stderr, "  -l username           ssh username [ssh default]\n");
90     fprintf(stderr, "  -p port               ssh port number [ssh default]\n");
91     fprintf(stderr, "  -c configfile         Set configuration file [~/.openpts/openpts.conf]\n");
92     fprintf(stderr, "\n");
93 }
94
95 #define INIT    0
96 #define VERIFY  1
97 #define UPDATE  2
98 #define DISPLAY 3
99 #define NONE    4
100
101 /**
102  * get Default Config File
103  */
104 int getDefaultConfigfile(OPENPTS_CONFIG *conf) {
105     int rc;
106     /* use system default config file */
107     char dirbuf[BUF_SIZE];
108     char confbuf[BUF_SIZE];
109     char uuidbuf[BUF_SIZE];
110
111     snprintf(dirbuf, BUF_SIZE, "%s/.openpts", getenv("HOME"));
112     snprintf(confbuf, BUF_SIZE, "%s/.openpts/openpts.conf", getenv("HOME"));
113     snprintf(uuidbuf, BUF_SIZE, "%s/.openpts/uuid", getenv("HOME"));
114
115     /* check dir */
116     if (checkDir(dirbuf) != PTS_SUCCESS) {
117         char ans;
118         if (isatty(STDIN_FILENO)) {
119             // Console
120             char buf[256];
121             char *s;
122             printf("%s is missing. create [Y/n]:", dirbuf);
123             s = fgets(buf, sizeof(buf), stdin);
124             if (s !=NULL) {
125                 ans = buf[0];
126             } else {
127                 printf("bad input?");
128                 goto error;
129             }
130         } else {
131             ans = 'Y';
132         }
133
134         /* new UUID */
135         conf->uuid = newOpenptsUuid();
136         conf->uuid->filename = smalloc(uuidbuf);
137         conf->uuid->status = OPENPTS_UUID_FILENAME_ONLY;
138         genOpenptsUuid(conf->uuid);
139
140         /* Y,y and just enter => create ~/.openpts */
141         if ((ans == 'Y') || (ans == 'y') || (ans == 0x0a)) {
142             rc = mkdir(dirbuf, S_IRUSR | S_IWUSR | S_IXUSR);
143             rc = writeOpenptsUuidFile(conf->uuid, 1);
144             if (rc != PTS_SUCCESS) {
145                 ERROR("writeOpenptsUuidFile fail\n");
146             }
147             rc = writeOpenptsConf(conf, confbuf);
148
149         } else {
150             printf("Bad answer %c, exit\n", ans);
151             rc = -1;
152             goto error;
153         }
154     }
155
156     /* check conf  */
157
158     DEBUG("read conf file          : %s\n", confbuf);
159     rc = readOpenptsConf(conf, confbuf);
160     if (rc != 0) {
161         ERROR("readOpenptsConf() failed\n");
162         goto error;
163     }
164     return PTS_SUCCESS;
165
166   error:
167     return PTS_FATAL;
168 }
169
170
171 /**
172  * main of "openpts" command 
173  *
174  *
175  * IntegrationTest: check_ifm
176  *
177  */
178 int main(int argc, char *argv[]) {
179     int command = NONE;
180     int rc = 0;
181     int opt;
182
183     OPENPTS_CONFIG *conf = NULL;  // conf for openpts
184     OPENPTS_CONTEXT *ctx = NULL;
185     char * config_filename = NULL;
186     char * target_hostname = NULL;
187     int initialized = 0;  // 0 -> 1 -> 2
188     char * target_conf_dir = NULL;
189     char * target_conf_filename = NULL;
190     int force = 0;
191     char *ssh_port = NULL;
192     char *ssh_username = NULL;
193 #ifdef CONFIG_AUTO_RM_UPDATE
194     int update_by_default = 0;
195 #endif
196     int i;
197     OPENPTS_TARGET *target_collector = NULL;
198     OPENPTS_CONFIG *target_conf = NULL;    // conf for target
199     int new_target = 0;  // indicate new target
200     int debug = 0;
201     // DEBUG
202     char *ptsc_path = NULL;
203     char *ptsc_conf = NULL;
204
205     verbose = 0;
206
207     /* args */
208     while ((opt = getopt(argc, argv, "ivuDVc:dfuyl:p:P:C:h")) != -1) {
209         switch (opt) {
210         case 'i':
211             if (command == NONE) {
212                 command = INIT;
213                 break;
214             }
215             ERROR("Only one command may be given at a time.");
216             usage();
217             return -1;
218         case 'v':
219             if (command == NONE) {
220                 command = VERIFY;
221                 break;
222             }
223             ERROR("Only one command may be given at a time.");
224             usage();
225             return -1;
226         case 'D':
227             if (command == NONE) {
228                 command = DISPLAY;
229                 break;
230             }
231             ERROR("Only one command may be given at a time.");
232             usage();
233             return -1;
234         case 'V':
235             debug++;
236             break;
237         case 'c':
238             config_filename = optarg;
239             break;
240         case 'd':
241             verbose = DEBUG_FLAG | DEBUG_FSM_FLAG;
242             break;
243         case 'f':
244             force = 1;
245             break;
246 #ifdef CONFIG_AUTO_RM_UPDATE
247         case 'u':
248             update_by_default = 1;
249             break;
250 #endif
251         case 'l':
252             ssh_username = optarg;
253             break;
254         case 'p':
255             ssh_port = optarg;
256             break;
257         case 'P':
258             ptsc_path = optarg;
259             break;
260         case 'C':
261             ptsc_conf = optarg;
262             break;
263         case 'h':
264             /* fall through */
265         default:
266             usage();
267             return -1;
268             break;
269         }
270     }
271     argc -= optind;
272     argv += optind;
273
274     target_hostname = argv[0];
275
276     /* check */
277     if ((ptsc_path != NULL) && (ptsc_conf != NULL)) {
278         int len;
279         INFO("ptsc debug mode\n");
280         len =  strlen(ptsc_path) + strlen(ptsc_conf) + 13;
281         ptsc_command = malloc(len);
282         snprintf(ptsc_command, len, "%s -m -v -c %s", ptsc_path, ptsc_conf);
283         INFO("command: %s\n", ptsc_command);
284     }
285
286     /* default command is to verify */
287     if (command == NONE) command = VERIFY;
288
289     /* set the DEBUG level, 1,2,3 */
290     if (debug > 2) {
291         verbose = DEBUG_FLAG | DEBUG_FSM_FLAG | DEBUG_IFM_FLAG;
292     } else if (debug > 1) {
293         verbose = DEBUG_FLAG | DEBUG_IFM_FLAG;
294     } else if (debug > 0) {
295         verbose = DEBUG_FLAG;
296     }
297
298     DEBUG("DEBUG mode (%d)\n", debug);
299
300     /* new config */
301     conf = newPtsConfig();
302     if (conf == NULL) {
303         printf("ERROR\n");  // TODO(munetoh)
304         return -1;
305     }
306
307     /* check/create config file */
308     if (config_filename == NULL) {
309         /* use default config file, HOME./openpts/openpts.conf  */
310         rc = getDefaultConfigfile(conf);
311         if (rc != PTS_SUCCESS) {
312             ERROR("getDefaultConfigfile() failed\n");
313             rc = -1;
314             goto error;
315         } else {
316             initialized++;  // 0->1
317         }
318     } else {
319         /* use given config file */
320         DEBUG("read conf file       : %s\n", config_filename);
321         rc = readOpenptsConf(conf, config_filename);
322         if (rc != 0) {
323             ERROR("config file [%s] - missing\n", config_filename);
324             rc = -1;
325             goto error;
326         } else {
327             initialized++;  // 0->1
328         }
329     }
330
331     /* Display (no remote access) */
332     if (command == DISPLAY) {
333         /* target List */
334         rc = getTargetList(conf, conf->config_dir);
335         if (rc != PTS_SUCCESS) {
336             TODO("main() - getTargetList rc =%d\n", rc);
337         }
338
339         if (target_hostname != NULL) {
340             /* given target (by hostname) */
341             /* look up */
342             conf->hostname = smalloc(target_hostname);
343             target_collector =  getTargetCollector(conf);
344             if (target_collector != NULL) {
345                 target_conf = (OPENPTS_CONFIG*)target_collector->target_conf;
346
347                 printf("hostname  : %s\n", target_hostname);
348                 printf("UUID      : %s\n", target_collector->str_uuid);
349                 printf("State     : %d\n", target_collector->state);
350                 printf("Dir       : %s\n", target_collector->dir);
351                 printf("Manifests :\n");
352
353                 getRmList(target_conf, target_conf->config_dir);
354                 printRmList(target_conf, "");
355             } else {
356                 printf("hostname  : %s --- unknown host, check the list\n", target_hostname);
357             }
358             goto free;  // exit
359         } else {
360             /* all target (simple) */
361             printTargetList(conf, "");  // target.c
362             goto free;  // exit anyway
363         }
364     }
365
366
367     /* Other commands use Remote Access (SSH) */
368
369     if (target_hostname == NULL) {
370         printf("set the target.\n");
371         usage();
372         goto free;
373     }
374
375     /* check/create target conf dir */
376     /* look up the conf of target(hostname) */
377     rc = getTargetList(conf, conf->config_dir);
378     if (rc != PTS_SUCCESS) {
379         TODO("main() - getTargetList rc =%d\n", rc);
380     }
381     if (verbose & DEBUG_FLAG) {
382         DEBUG("target list\n");
383         printTargetList(conf, "");  // uuid.c
384     }
385
386     /* set the target hostname:port and search */
387     if (conf->hostname != NULL) {
388         TODO("realloc conf->hostname\n");
389         free(conf->hostname);
390     }
391     conf->hostname = smalloc(target_hostname);
392     target_collector =  getTargetCollector(conf);
393     if (target_collector == NULL) {
394         /* missing, new target => malloc temp target */
395         new_target = 1;
396         target_conf = newPtsConfig();
397     } else {
398         /* HIT exist */
399         target_conf_dir  = getTargetConfDir(conf);  // HOME/.openpts/UUID
400         target_conf_filename = smalloc(target_collector->target_conf_filename);
401         target_conf = (OPENPTS_CONFIG*)target_collector->target_conf;
402     }
403
404     /* verify -> read target conf */
405     if (command == VERIFY) {
406         /* check the target dir  */
407         if (checkDir(target_conf_dir) == PTS_SUCCESS) {
408             initialized++;  // 1->2
409         } else {
410             ERROR("target_conf_dir, %s is missing", target_conf_dir);
411         }
412     }
413
414     /* check for an overriding ssh username */
415     if (ssh_username != NULL) {
416         target_conf->ssh_username = strdup(ssh_username);
417         if (target_conf->ssh_username == NULL) {
418             ERROR("No memory");
419             goto free;
420         }
421     } else {
422         ssh_username = target_conf->ssh_username;
423     }
424
425     /* check for an overriding ssh port # */
426     if (ssh_port != NULL) {
427         target_conf->ssh_port = smalloc(ssh_port);
428         if (target_conf->ssh_port == NULL) {
429             ERROR("No memory");
430             goto free;
431         }
432     } else {
433         ssh_port = target_conf->ssh_port;
434     }
435
436     // TODO Wrong?
437     if (command == INIT) {
438         if (target_conf->hostname != NULL) {
439             // DEBUG("realloc target_conf->hostname\n"); TODO realloc happen
440             free(target_conf->hostname);
441         }
442         target_conf->hostname = smalloc(target_hostname);
443         target_conf->ssh_port = smalloc(ssh_port);
444     }
445
446     /* new context */
447     ctx = newPtsContext(conf);
448     if (ctx == NULL) {
449         printf("ERROR\n");  // TODO(munetoh)
450         rc = -1;
451         goto error;
452     }
453     ctx->target_conf = target_conf;
454
455     /* command */
456     switch (command) {
457     case INIT:
458         /* */
459         ctx->target_conf = NULL;
460
461
462         /* get UUID, RMs, AIDE DB */
463         DEBUG("enroll with %s  (SSH uses localost)\n", target_hostname);
464         DEBUG("conf->config_dir %s\n", conf->config_dir);
465         rc =  enroll(ctx, target_hostname, ssh_username, ssh_port, conf->config_dir, force);  // verifier.c
466         if (rc != 0) {
467             fprintf(stderr, "enroll was failed, rc = %d\n", rc);
468             printReason(ctx);
469             goto error;
470         }
471
472         DEBUG("conf->config_dir %s\n", conf->config_dir);
473         rc =  verifier(ctx, target_hostname, ssh_username, ssh_port, conf->config_dir, 1);  // init
474         if (rc != OPENPTS_RESULT_VALID) {
475             fprintf(stderr, "initial verification was failed, rc = %d\n", rc);
476             printReason(ctx);
477             goto error;
478         }
479
480         /* message */
481         printf("Target            : %s\n", target_hostname);
482
483         if (ctx->target_conf != NULL) {
484             if (ctx->target_conf->rm_uuid != NULL) {
485                 printf("Manifest UUID     : %s\n", ctx->target_conf->rm_uuid->str);
486                 for (i = 0; i< ctx->conf->rm_num; i ++) {
487                     printf("manifest[%d]       : %s\n", i, ctx->target_conf->rm_filename[i]);
488                 }
489             }
490             printf("Collector UUID    : %s\n", ctx->target_conf->uuid->str);
491             printf("configuration     : %s\n", ctx->target_conf->config_file);
492             printf("validation policy : %s\n", ctx->target_conf->policy_filename);
493         } else {
494             // TODO never happen?
495             printf("configuration     : new target\n");
496         }
497         break;
498     case VERIFY:
499         /* verify */
500         if (initialized < 2) {
501             fprintf(stderr, "ERROR: target %s is not initialized yet. please enroll with %s first\n\n",
502                 target_hostname, target_hostname);
503             usage();
504             rc = -1;
505             goto error;
506         }
507
508         // TODO(munetoh) control by policy? or conf?
509         ctx->conf->ima_validation_unknown = 1;
510
511         /* vefify*/
512         rc =  verifier(ctx, target_hostname, ssh_username, ssh_port, conf->config_dir, 0);  // normal
513
514         /* messages */
515         // printf("target        : %s\n", argv[0]);
516         printf("Target            : %s\n", argv[0]);
517         if (target_conf != NULL) {
518             printf("Collector UUID    : %s ", target_conf->uuid->str);
519             // TODO set this when load the uuid
520             if (target_conf->uuid->time == NULL) {
521                 target_conf->uuid->time = getDateTimeOfUuid(target_conf->uuid->uuid);
522             }
523             printf("(date: %04d-%02d-%02d-%02d:%02d:%02d)\n",
524                 target_conf->uuid->time->year + 1900,
525                 target_conf->uuid->time->mon + 1,
526                 target_conf->uuid->time->mday,
527                 target_conf->uuid->time->hour,
528                 target_conf->uuid->time->min,
529                 target_conf->uuid->time->sec);
530             printf("Manifest UUID     : %s ", target_conf->rm_uuid->str);
531             printf("(date: %04d-%02d-%02d-%02d:%02d:%02d)\n",
532                 target_conf->rm_uuid->time->year + 1900,
533                 target_conf->rm_uuid->time->mon + 1,
534                 target_conf->rm_uuid->time->mday,
535                 target_conf->rm_uuid->time->hour,
536                 target_conf->rm_uuid->time->min,
537                 target_conf->rm_uuid->time->sec);
538
539             printf("username(ssh)     : %s\n",
540                 conf->ssh_username ? conf->ssh_username : "default");
541             printf("port(ssh)         : %s\n",
542                 conf->ssh_port ? conf->ssh_port : "default");
543             printf("policy file       : %s\n", target_conf->policy_filename);
544             printf("property file     : %s\n", target_conf->prop_filename);  // TODO ptoperty or prop
545         } else {
546             // ERROR("\n");
547         }
548
549         if (rc == OPENPTS_RESULT_VALID) {
550             printf("integrity         : valid\n");
551         } else if (rc == OPENPTS_RESULT_INVALID) {
552             printf("integrity         : invalid\n");
553             printReason(ctx);
554         } else if (rc == OPENPTS_RESULT_UNKNOWN) {
555             printf("integrity         : unknown\n");
556             printReason(ctx);
557         } else if (rc == PTS_VERIFY_FAILED) {
558             printf("integrity         : invalid ()\n");
559             printReason(ctx);
560         } else {
561             printf("integrity         : unknown (INTERNAL ERROR) rc=%d\n", rc);
562             printReason(ctx);
563         }
564
565 #ifdef CONFIG_AUTO_RM_UPDATE
566         // Verify() check the ARU
567         // remote : conf->aru_newrm_uuid
568         // local  : target_conf->newrm_uuid
569         if ((target_conf != NULL) && (conf->newrm_exist > 0)) {
570             char *uuid_str;
571             PTS_DateTime *uuid_time;
572             char ans;
573             int same = 0;
574
575             if (verbose & DEBUG_FLAG) {
576                 DEBUG("NEWRM_UUID\n");
577                 printHex("NEWRM UUID (remote)  : ", (BYTE*)conf->aru_newrm_uuid, 16, "\n");
578                 if (target_conf->newrm_uuid != NULL) {
579                     printHex("NEWRM UUID (local)   : ", (BYTE*)target_conf->newrm_uuid->uuid, 16, "\n");
580                 } else {
581                     printf("NEWRM UUID (local)   : missing\n");
582                 }
583             }
584
585             /* Check local newrm vs remote newrm */
586             if ((target_conf->newrm_uuid != NULL) && (target_conf->newrm_uuid->uuid != NULL)) {
587                 if (memcmp(
588                         (BYTE*)conf->aru_newrm_uuid,
589                         (BYTE*)target_conf->newrm_uuid->uuid, 16) == 0) {
590                     /* HIT */
591                     printf("---------------------------------------------------------\n");
592                     printf("New Manifest UUID : %s ", target_conf->newrm_uuid->str);
593                     printf("(date: %04d-%02d-%02d-%02d:%02d:%02d) - local\n",
594                         target_conf->newrm_uuid->time->year + 1900,
595                         target_conf->newrm_uuid->time->mon + 1,
596                         target_conf->newrm_uuid->time->mday,
597                         target_conf->newrm_uuid->time->hour,
598                         target_conf->newrm_uuid->time->min,
599                         target_conf->newrm_uuid->time->sec);
600                     goto free;
601                 } else {
602                     /* local is old? */
603                     same = 1;
604                 }
605             }
606
607             /* msg */
608             printf("---------------------------------------------------------\n");
609             uuid_time = getDateTimeOfUuid(conf->aru_newrm_uuid);
610             uuid_str = getStringOfUuid(conf->aru_newrm_uuid);
611             printf("New Manifest UUID : %s ", uuid_str);
612             printf("(date: %04d-%02d-%02d-%02d:%02d:%02d)\n",
613                 uuid_time->year + 1900,
614                 uuid_time->mon + 1,
615                 uuid_time->mday,
616                 uuid_time->hour,
617                 uuid_time->min,
618                 uuid_time->sec);
619             free(uuid_str);
620
621             if (same == 0) {
622                 if (isatty(STDIN_FILENO)) {
623                     printf("New reference manifest exist. update? [Y/n]\n");
624                     rc = scanf("%[YyNn]", &ans);
625                 } else {
626                     rc = 1;
627                     ans = update_by_default ? 'Y' : 'N';
628                 }
629
630                 DEBUG("conf->config_dir %s\n", conf->config_dir);
631
632                 if ((ans == 'Y') || (ans == 'y')) {
633                     rc = updateNewRm(ctx, target_hostname, ssh_username, ssh_port, conf->config_dir);  // aru.c
634                     if (rc == PTS_SUCCESS) {
635                         printf("Save new reference manifest\n");
636                         // TODO UUID
637                     } else {
638                     }
639                 } else if ((ans == 'N') || (ans == 'n')) {
640                     printf("keep current manifest\n");
641                 } else {
642                     printf("Bad answer %c, exit\n", ans);
643                     rc = -1;
644                     goto error;
645                 }
646             }
647
648             // TODO validate new RM
649             // TODO e.g. gen new RM by verifier and compare both
650         } else if (rc == PTS_RULE_NOT_FOUND) {
651             // char ans;
652             printf("New reference manifest exist. if this is expected change, update the manifest by openpts -i -f \n");
653         } else {
654             DEBUG("no newrm\n");
655         }
656 #else
657         if (rc == PTS_RULE_NOT_FOUND) {
658             // char ans;
659             printf("New reference manifest exist. if this is expected change, update the manifest by openpts -i -f \n");
660         }
661 #endif
662         break;
663     case UPDATE:
664         TODO("TBD\n");
665         break;
666     default:
667         ERROR("Bad command?");
668         usage();
669         break;
670     }
671     rc = 0;
672
673  error:
674  free:
675     if (target_conf_dir != NULL) free(target_conf_dir);
676     if (target_conf_filename != NULL) free(target_conf_filename);
677     if ((new_target == 1) && (target_conf != NULL)) {
678         /* free new target conf */
679         freePtsConfig(target_conf);
680     }
681     if (ctx != NULL) {
682         ctx->target_conf = NULL;
683         freePtsContext(ctx);
684     }
685
686     freePtsConfig(conf);
687
688     return rc;
689 }