OSDN Git Service

cleanup
[openpts/openpts.git] / src / ptsc.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) 2011 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/ptsc.c
26  * \brief PTS collector command
27  * @author Seiji Munetoh <munetoh@users.sourceforge.jp>
28  * @author Olivier Valentin <olivier.valentin@us.ibm.com>
29  * @author Alexandre Ratchov <alexandre.ratchov@bull.net>
30  * @date 2010-04-04
31  * cleanup 2012-01-04 SM
32  *
33  */
34
35 #ifdef AIX
36 #include <sys/lockf.h>
37 #endif
38
39 #include <sys/types.h>
40 #include <sys/socket.h>
41 #include <sys/un.h>
42 #include <sys/socketvar.h>
43 #include <errno.h>
44 #include <fcntl.h>
45 #include <stdio.h>
46 #include <string.h>
47 #include <unistd.h>
48 #include <pwd.h>
49 #include <grp.h>
50 #include <sys/stat.h>  // chmod
51
52 #include <openpts.h>
53
54 int prop_num = 0;
55 OPENPTS_PROPERTY *start = NULL;
56 OPENPTS_PROPERTY *end = NULL;
57
58 /**
59  * collector
60  *
61  * TODO support single connection.
62  * TODO for multiple conenction, multiple ctxs are required. 
63  * TODO disable remote connection
64  */ 
65 int collector(OPENPTS_CONFIG *conf) {
66     int rc;
67     int terminate = 0;
68     OPENPTS_CONTEXT *ctx = NULL;
69     PTS_IF_M_Attribute *read_tlv = NULL;
70
71     /* Init RMs */
72     rc = getRmSetDir(conf);
73     if (rc != PTS_SUCCESS) {
74         LOG(LOG_ERR, "collector() - getRmSetDir() was failed\n");
75         return PTS_INTERNAL_ERROR;
76     }
77
78     rc = getNewRmSetDir(conf);
79     if (rc != PTS_SUCCESS) {
80         /* don't care */
81         DEBUG("collector() - getNewRmSetDir() was failed - never mind\n");
82     }
83
84     LOG(LOG_INFO, "start collector (System UUID=%s, RM UUID = %s)\n",
85         conf->uuid->str, conf->rm_uuid->str);
86
87     /* Collector <-> Verifier - handshake loop */
88     ctx = newPtsContext(conf);
89
90     addPropertiesFromConfig(conf, ctx);
91
92     /* protocol loop */
93     while (!terminate) {
94         /* V->C request */
95
96         /* read() will block forever unless STDIN was explicitly set to
97            be non-blocking or we receive an interrupt. even then wrapRead() will
98            ignore EAGAIN and EINTR and keep attempting to call read(). the only way
99            this could fail is if the other end of the connection closed, in which case
100            we should exit. if timeouts are required then poll() or select() can be
101            used on blocking file descriptors to listen for input. */
102         read_tlv = readPtsTlv(STDIN_FILENO);  // ifm.c, malloc tlv
103         if (read_tlv == NULL) {
104             DEBUG("close IF-M PTS connection\n");
105             break;
106         }
107
108         /* check bad TLV */
109         if (read_tlv->type == 0) {
110             LOG(LOG_ERR, "Bad TLV type received - quit");
111             break;
112         }
113
114         if (read_tlv->length > 0 && read_tlv->value == NULL) {
115             LOG(LOG_ERR, "Malformed TLV message (ghost body) - quit");
116             break;
117         }
118
119         DEBUG_IFM("IF-M read type = 0x%X, len %d\n",
120                 read_tlv->type,
121                 read_tlv->length);
122
123         /* C->V responces */
124         switch (read_tlv->type) {
125             case OPENPTS_CAPABILITIES:
126                 DEBUG("IF-M OPENPTS_CAPABILITIES\n");
127                 /* check the UUID */
128                 if (read_tlv->length != sizeof(OPENPTS_IF_M_Capability)) {  // TODO use defined name
129                     LOG(LOG_ERR, "Bad PTS_CAPABILITIES, len = %d != %d\n",
130                         read_tlv->length, sizeof(OPENPTS_IF_M_Capability));
131                     terminate = 1;
132                 } else {
133                     // TODO copy
134                     OPENPTS_IF_M_Capability *cap;
135                     cap = (OPENPTS_IF_M_Capability *) read_tlv->value;
136                     /* get version */
137                     // TODO
138                     /* get verifier's UUID */
139                     ctx->uuid = xmalloc_assert(sizeof(PTS_UUID));
140                     memcpy(ctx->uuid, &cap->platform_uuid, 16);
141                     ctx->str_uuid = getStringOfUuid(ctx->uuid);
142
143                     /* syslog */
144                     LOG(LOG_INFO, "verifier (UUID=%s)\n", ctx->str_uuid);
145
146                     /* send PTS_CAPABILITIES msg. to verifier (=UUID) */
147                     rc = writePtsTlv(ctx, STDOUT_FILENO, OPENPTS_CAPABILITIES);
148                     if (rc < 0) {
149                         LOG(LOG_ERR, "Send CAPABILITY answer failed - quit");
150                         terminate = 1;
151                     }
152                 }
153                 break;
154
155             case DH_NONCE_PARAMETERS_REQUEST:
156                 DEBUG("IF-M DH_NONCE_PARAMETERS_REQUEST\n");
157                 /* check */
158                 if (read_tlv->length != 4) {
159                     LOG(LOG_ERR, "Bad DH_NONCE_PARAMETERS_REQUEST, len = %d != 4\n", read_tlv->length);
160                     terminate = 1;
161                 } else {
162                     /* req -> res */
163                     ctx->nonce->req->reserved      = read_tlv->value[0];
164                     ctx->nonce->req->min_nonce_len = read_tlv->value[1];
165                     // NBO to Host
166                     ctx->nonce->req->dh_group_set  = (read_tlv->value[2]<<8) | read_tlv->value[3];
167
168                     rc = getDhResponce(ctx->nonce);
169
170                     /* send responce */
171                     rc = writePtsTlv(
172                             ctx, STDOUT_FILENO, DH_NONCE_PARAMETORS_RESPONSE);
173                     if (rc < 0) {
174                         LOG(LOG_ERR, "Send NONCE answer failed - quit");
175                         terminate = 1;
176                     }
177                 }
178                 break;
179             case DH_NONCE_FINISH:
180                 DEBUG("IF-M DH_NONCE_FINISH\n");
181                 /* check */
182                 if (read_tlv->length != 152) {  // TODO  how to calc this size?
183                     LOG(LOG_ERR, "Bad DH_NONCE_FINISH, len = %d != 152\n", read_tlv->length);
184                     terminate = 1;
185                 } else {
186                     /* finish  */
187                     ctx->nonce->fin->reserved            = read_tlv->value[0];
188                     ctx->nonce->fin->nonce_length        = read_tlv->value[1];
189                     // NBO to Host
190                     ctx->nonce->fin->selected_hash_alg   = (read_tlv->value[2]<<8) | read_tlv->value[3];
191
192                     /* public */
193                     ctx->nonce->fin->dh_initiator_public = xmalloc_assert(ctx->nonce->pubkey_length);
194                     memcpy(
195                         ctx->nonce->fin->dh_initiator_public,
196                         &read_tlv->value[4],
197                         ctx->nonce->pubkey_length);
198
199                     /* nonce */
200                     ctx->nonce->fin->dh_initiator_nonce = xmalloc_assert(ctx->nonce->fin->nonce_length);
201                     memcpy(
202                         ctx->nonce->fin->dh_initiator_nonce,
203                         &read_tlv->value[4 + ctx->nonce->pubkey_length],
204                         ctx->nonce->fin->nonce_length);
205
206                     rc = calcDhFin(ctx->nonce);
207
208                     /* no responce */
209                 }
210                 break;
211             case REQUEST_RIMM_SET:  // 5
212                 DEBUG("IF-M REQUEST_RIMM_SET\n");
213                 /* check */
214                 if (read_tlv->length != 0) {
215                     LOG(LOG_ERR, "Bad REQUEST__RIMM_SET, len = %d != 0\n", read_tlv->length);
216                     terminate = 1;
217                 } else {
218                     rc = writePtsTlv(
219                             ctx, STDOUT_FILENO, RIMM_SET);
220                     if (rc < 0) {
221                         LOG(LOG_ERR, "Send RIMM_SET answer failed - quit");
222                         terminate = 1;
223                     }
224                 }
225                 break;
226             case REQUEST_NEW_RIMM_SET:
227                 DEBUG("IF-M REQUEST_NEW_RIMM_SET\n");
228                 /* check */
229                 if (read_tlv->length != 0) {
230                     LOG(LOG_ERR, "Bad REQUEST_NEW_RIMM_SET, len = %d != 0\n", read_tlv->length);
231                     terminate = 1;
232                 } else {
233                     rc = writePtsTlv(
234                             ctx, STDOUT_FILENO, NEW_RIMM_SET);
235                     if (rc < 0) {
236                         /* this will fail if NEW RM is missing */
237                         DEBUG_IFM("Send NEW_RIMM_SET answer failed - quit");
238                         terminate = 1;
239                     }
240                 }
241                 break;
242             case REQUEST_INTEGRITY_REPORT:
243                 DEBUG("IF-M REQUEST_INTEGRITY_REPORT\n");
244                 /* check */
245                 if (read_tlv->length != 0) {
246                     LOG(LOG_ERR, "Bad REQUEST_INTEGRITY_REPORT, len = %d != 0\n", read_tlv->length);
247                     terminate = 1;
248                 } else {
249                     rc = writePtsTlv(ctx, STDOUT_FILENO, INTEGRITY_REPORT);
250                     if (rc < 0) {
251                         LOG(LOG_ERR, "Send INTEGRITY_REPORT answer failed - quit");
252                         terminate = 1;
253                     }
254                 }
255                 break;
256             case VERIFICATION_RESULT:
257                 /* no responce */
258                 DEBUG_IFM("IF-M VERIFICATION_RESULT => terminate\n");
259                 DEBUG_IFM("finish\n");
260                 terminate = 1;  // TODO add TERMINATE MSG
261                 break;
262 #ifdef CONFIG_AIDE
263             case REQUEST_AIDE_DATABASE:
264                 LOG(LOG_INFO, "IF-M REQUEST_AIDE_DATABASE\n");
265                 /* check */
266                 if (read_tlv->length != 0) {
267                     LOG(LOG_ERR, "Bad REQUEST_AIDE_DATABASE, len = %d != 0\n", read_tlv->length);
268                     terminate = 1;
269                 } else {
270                     rc = writePtsTlv(ctx, STDOUT_FILENO, AIDE_DATABASE);
271                     if (rc < 0) {
272                         LOG(LOG_ERR, "Send REQUEST_AIDE_DATABASE answer failed - quit");
273                         terminate = 1;
274                     }
275                 }
276                 break;
277 #endif
278             case REQUEST_TPM_PUBKEY:
279                 /* check */
280                 if (read_tlv->length != 0) {
281                     LOG(LOG_ERR, "Bad REQUEST_TPM_PUBKEY, len = %d != 0\n", read_tlv->length);
282                     terminate = 1;
283                 } else {
284                     rc = writePtsTlv(ctx, STDOUT_FILENO, TPM_PUBKEY);  // ifm.c
285                     if (rc < 0) {
286                         LOG(LOG_ERR, "Send TPM_PUBKEY answer failed - quit");
287                         terminate = 1;
288                     }
289                 }
290                 break;
291             case NONCE:
292                 /* check */
293                 if (read_tlv->length != 20) {
294                     LOG(LOG_ERR, "Bad NONCE, len = %d != 20\n", read_tlv->length);
295                     terminate = 1;
296                 } else {
297                     /* set nonce */
298                     ctx->nonce->nonce_length = 20;
299                     if (ctx->nonce->nonce != NULL) {
300                         xfree(ctx->nonce->nonce);
301                     }
302                     ctx->nonce->nonce = xmalloc_assert(20);
303                     memcpy(ctx->nonce->nonce, read_tlv->value, 20);
304                     DEBUG_IFM("nonce[%d] : \n", ctx->nonce->nonce_length);
305                 }
306                 break;
307             case OPENPTS_ERROR:
308                 LOG(LOG_ERR, "verifier returns error, termnate\n");
309                 terminate = 1;
310                 break;
311             default:
312                 LOG(LOG_ERR, "PTS IF-M type 0x%08x is not supported\n", read_tlv->type);
313                 LOG(LOG_INFO, "send OPENPTS_ERROR msg to verifier, then terminate the conenction");
314                 ctx->ifm_errno = PTS_UNRECOGNIZED_COMMAND;
315                 if (ctx->ifm_strerror != NULL) {
316                     xfree(ctx->ifm_strerror);
317                 }
318                 ctx->ifm_strerror = smalloc_assert("Unknown message type");
319                 rc = writePtsTlv(ctx, STDOUT_FILENO, OPENPTS_ERROR);  // ifm.c
320                 terminate = 1;
321                 break;
322         }  // switch case
323
324         /* free TLV */
325         if (read_tlv != NULL) {
326             freePtsTlv(read_tlv);
327         }
328     }
329
330     freePtsContext(ctx);
331
332     return 0;
333 }
334
335
336 /**
337  * Usage
338  */
339 void usage(void) {
340     OUTPUT(NLS(MS_OPENPTS,  OPENPTS_COLLECTOR_USAGE_1,
341         "OpenPTS Collector\n\n"
342         "Usage: ptsc [options] [command]\n\n"
343         "Commands: (foreground)\n"
344         "  -i                    Initialize PTS collector\n"
345         "  -t                    Self test (attestation)\n"
346         "  -s                    Startup (selftest + timestamp)\n"
347         "  -u                    Update the RM\n"
348         "  -e                    Clear PTS collector\n"));
349 #ifdef CONFIG_AUTO_RM_UPDATE
350     OUTPUT(NLS(MS_OPENPTS, OPENPTS_COLLECTOR_USAGE_2,
351         "  -U                    Update the RM (auto)\n"));
352 #endif
353     OUTPUT(NLS(MS_OPENPTS, OPENPTS_COLLECTOR_USAGE_3,
354         "  -D                    Display the configuration\n"
355         "  -m                    IF-M mode\n"
356         "\n"
357         "Miscellaneous:\n"
358         "  -h                    Show this help message\n"
359         "  -v                    Verbose mode. Multiple -v options increase the verbosity.\n"
360         "\n"
361         "Options:\n"
362         "  -c configfile         Set configuration file. defalt is %s\n"
363         "  -P name=value         Set properties.\n"
364         "  -R                    Remove RMs\n"
365         "  -z                    Set the SRK secret to all zeros (20 bytes of zeros)\n"), PTSC_CONFIG_FILE);
366 }
367
368 enum COMMAND {
369     COMMAND_IFM,
370     COMMAND_INIT,
371     COMMAND_STATUS,
372     COMMAND_SELFTEST,
373     COMMAND_UPDATE,
374     COMMAND_STARTUP,
375     COMMAND_CLEAR,
376 #ifdef CONFIG_AUTO_RM_UPDATE
377     COMMAND_AUTO_UPDATE,
378 #endif
379 };
380
381 /**
382  * name=value
383  */
384 OPENPTS_PROPERTY *getPropertyFromArg(char *arg) {
385     char *name;
386     char *value;
387     char * eq;
388     OPENPTS_PROPERTY *prop;
389
390     if ((eq = strstr(arg, "=")) != NULL) {
391         /* remove CR */
392         *eq = 0;
393         name = arg;
394         value = eq + 1;
395
396         prop = newProperty(name, value);
397         return prop;
398     } else {
399         LOG(LOG_ERR, "bad property %s\n", arg);
400         return NULL;
401     }
402 }
403
404 #ifdef AIX
405 #define LOCK_DIR    "/var/ptsc/"
406 #else  // LINUX
407 #define LOCK_DIR    "/var/lib/openpts/"
408 #endif
409 #define LOCK_FILE    LOCK_DIR "ptsc.lock"
410
411 /**
412  * lock ptsc
413  * 
414  * check the log msg
415  */
416 void ptsc_lock(void) {
417     int fd, oldmask, oldgrp = 0;
418     struct group *grpent = NULL;
419     struct group grp;
420     char *buf = NULL;
421     size_t buf_len;
422     int rc;
423
424     if (geteuid() == 0) {
425         // grpent = getgrnam(PTSC_GROUP_NAME);
426         // if (grpent) {
427         //     oldgrp = getegid();
428         //     setegid(grpent->gr_gid);
429         // }
430         buf_len = sysconf(_SC_GETGR_R_SIZE_MAX);
431         if (buf_len < 0) {
432             buf_len = 4096;
433         }
434         buf = xmalloc(buf_len);
435         if (buf == NULL) {
436             LOG(LOG_ERR, "no memory");
437             exit(1);
438         }
439
440         rc = getgrnam_r(PTSC_GROUP_NAME, &grp, buf, buf_len, &grpent);
441         if (rc != 0) {
442             LOG(LOG_ERR, "getgrnam_r() fail");
443             exit(1);
444         }
445         if (grpent == NULL) {
446             LOG(LOG_ERR, "grpent is null");
447             exit(1);
448         }
449         oldgrp = getegid();
450         setegid(grp.gr_gid);
451     }
452
453     oldmask = umask(0);
454     if (mkdir(LOCK_DIR, 0775) < 0 && errno != EEXIST) {
455         LOG(LOG_ERR, "mkdir(%s) fail", LOCK_DIR);
456         exit(1);
457     }
458     if (grpent) {
459         chmod(LOCK_DIR, 02775);
460         setegid(oldgrp);
461     }
462     fd = open(LOCK_FILE, O_RDWR | O_CREAT | O_TRUNC, 0660);
463     if (fd < 0) {
464         LOG(LOG_ERR, "open(%s) fail", LOCK_DIR);
465         exit(1);
466     }
467     umask(oldmask);
468     if (lockf(fd, F_LOCK, 0) < 0) {
469         LOG(LOG_ERR, "lockf(%s) fail", LOCK_DIR);
470         exit(1);
471     }
472
473     if (buf != NULL) xfree(buf);
474 }
475
476 /**
477  * Prepare privileges
478  */
479 static int preparePriv() {
480     int rc = PTS_SUCCESS;
481     struct group *ptsc_grp = NULL;
482     struct group grp;
483     char *buf = NULL;
484     size_t buf_len;
485
486 #if 0
487     /* check UID */
488     if ((ptscd_pwd = getpwnam_r(PTSCD_USER_NAME)) == NULL) {
489         LOG(LOG_ERR, "Looking up for user %s", PTSCD_USER_NAME);
490         return PTS_FATAL;
491     }
492 #endif
493
494     /* check GID */
495     buf_len = sysconf(_SC_GETGR_R_SIZE_MAX);
496     if (buf_len < 0) {
497         buf_len = 4096;
498     }
499     buf = xmalloc(buf_len);
500     if (buf == NULL) {
501         LOG(LOG_ERR, "no memory");
502         return PTS_FATAL;
503     }
504
505     rc = getgrnam_r(PTSC_GROUP_NAME, &grp, buf, buf_len, &ptsc_grp);
506     if (rc != 0) {
507         LOG(LOG_ERR, "getgrnam_r(%s) fail", PTSC_GROUP_NAME);
508         rc = PTS_FATAL;
509         goto free;
510     }
511     if (ptsc_grp == NULL) {
512         LOG(LOG_ERR, "ptsc_grp == NULL");
513         rc = PTS_FATAL;
514         goto free;
515     }
516
517     /* set GID */
518     rc = setgid(grp.gr_gid);
519     if (rc < 0) {
520         // TODO do not need for IF-M access (read only)
521         LOG(LOG_INFO, "Switching group (gid=%d) fail. %s\n", grp.gr_gid, strerror(errno));
522         rc = PTS_FATAL;
523         goto free;
524     }
525
526 #if 0
527     if (setuid(ptscd_pwd->pw_uid) == -1) {
528         LOG(LOG_ERR, "Switching to user %s", PTSCD_USER_NAME);
529         return PTS_FATAL;
530     }
531 #endif
532
533     /* free  */
534   free:
535     if (buf != NULL) xfree(buf);
536
537     return rc;
538 }
539
540 /**
541  * dir group => PTSC_GROUP_NAME
542  *
543  * flag 0:read, 1:read/write
544  */
545 static int chmodDir(char *dirpath, int flag) {
546     int rc = PTS_SUCCESS;
547     struct group *ptsc_grp;
548     struct group grp;
549     char *buf = NULL;
550     size_t buf_len;
551
552
553     /* check GID */
554     buf_len = sysconf(_SC_GETGR_R_SIZE_MAX);
555     if (buf_len < 0) {
556         buf_len = 4096;
557     }
558     buf = xmalloc(buf_len);
559     if (buf == NULL) {
560         LOG(LOG_ERR, "no memory");
561         return PTS_FATAL;
562     }
563
564     rc = getgrnam_r(PTSC_GROUP_NAME, &grp, buf, buf_len, &ptsc_grp);
565     if (rc != 0) {
566         LOG(LOG_ERR, "getgrnam_r");
567         rc = PTS_FATAL;
568         goto free;
569     }
570     if (ptsc_grp == NULL) {
571         LOG(LOG_ERR, "ptsc_grp == NULL");
572         rc = PTS_FATAL;
573         goto free;
574     }
575
576     /* chgep */
577     rc = chown(
578             dirpath,
579             -1,
580             ptsc_grp->gr_gid);
581     if (rc <0) {
582         rc = PTS_FATAL;
583         goto free;
584     }
585
586     if (flag == 0) {
587         rc = chmod(
588                 dirpath,
589                 S_IRUSR | S_IWUSR | S_IXUSR |
590                 S_IRGRP | S_IXGRP);
591         if (rc <0) {
592             rc = PTS_FATAL;
593             goto free;
594         }
595     } else {  // write
596         rc = chmod(
597                 dirpath,
598                 S_IRUSR | S_IWUSR | S_IXUSR |
599                 S_IRGRP | S_IWGRP | S_IXGRP);
600         if (rc <0) {
601             rc = PTS_FATAL;
602             goto free;
603         }
604     }
605
606   free:
607     if (buf != NULL) xfree(buf);
608     return rc;
609 }
610
611
612 /**
613  * Main
614  */
615 int main(int argc, char *argv[]) {
616     int rc;
617     OPENPTS_CONFIG *conf = NULL;
618     char *config_filename = NULL;
619     int command = COMMAND_STATUS;
620     int c;
621     int force = 0;
622 #ifdef CONFIG_AUTO_RM_UPDATE
623     int remove = 0;
624 #endif
625
626     /* properties by cmdline  */
627     OPENPTS_PROPERTY *prop;
628
629     /* Logging/NLS */
630     initCatalog();
631     setSyslogCommandName("ptsc");
632
633     /* command option */
634     while ((c = getopt(argc, argv, "ic:uUefDtsmvP:Rzh")) != EOF) {
635         switch (c) {
636         case 'i':
637             command = COMMAND_INIT;
638             break;
639         case 'u':
640             command = COMMAND_UPDATE;
641             break;
642         case 'U':
643 #ifdef CONFIG_AUTO_RM_UPDATE
644             command = COMMAND_AUTO_UPDATE;
645 #endif
646             break;
647         case 'D':
648             command = COMMAND_STATUS;
649             break;
650         case 't':
651             command = COMMAND_SELFTEST;
652             break;
653         case 's':
654             command = COMMAND_STARTUP;
655             break;
656         case 'e':
657             command = COMMAND_CLEAR;
658             break;
659         case 'f':
660             force = 1;
661             break;
662         case 'm':
663             command = COMMAND_IFM;
664             /* not everything should go to syslog - on some systems
665                this could go to a log file - let default behaviour
666                in log.c decide this */
667             break;
668         case 'c':
669             config_filename = optarg;
670             break;
671         case 'v':
672             incVerbosity();
673             break;
674         case 'R':
675 #ifdef CONFIG_AUTO_RM_UPDATE
676             remove = 1;
677 #endif
678             break;
679         case 'z':
680             conf->srk_password_mode = 1;
681             break;
682         case 'P':
683             prop = getPropertyFromArg(optarg);
684             if (prop != NULL) {
685                 if (start == NULL) {
686                     start = prop;
687                     end = prop;
688                     prop->next = NULL;
689                 } else {
690                     end->next = prop;
691                     end = prop;
692                     prop->next = NULL;
693                 }
694                 prop_num++;
695             } else {
696                 usage();
697                 return -1;
698             }
699             break;
700         case 'h':
701             /* help */
702         default:
703             usage();
704             return -1;
705             break;
706         }
707     }
708     argc -= optind;
709     argv += optind;
710
711     /* Verbose & Logging  */
712     if (command == COMMAND_IFM) {
713         /* Set IF-M log location, syslog or file(for DEBUG) */
714         setLogLocation(OPENPTS_LOG_SYSLOG, NULL);
715     } else {
716         /* Set logging (location,filename)  by ENV */
717         determineLogLocationByEnv();
718
719         // TODO chgrp
720         rc = preparePriv();
721         if (rc != PTS_SUCCESS) {
722             LOG(LOG_INFO, "preparePriv fail\n");
723         }
724     }
725
726     conf = newPtsConfig();
727     if (conf == NULL) {
728         LOG(LOG_ERR, "internal error\n");  // TODO(munetoh)
729         return -1;
730     }
731
732     /* set the DEBUG level, 1,2,3 */
733     if (getVerbosity() > 2) {
734         setDebugFlags(DEBUG_FLAG | DEBUG_IFM_FLAG | DEBUG_FSM_FLAG | DEBUG_CAL_FLAG);
735     } else if (getVerbosity() > 1) {
736         setDebugFlags(DEBUG_FLAG | DEBUG_IFM_FLAG);
737     } else if (getVerbosity() > 0) {
738         setDebugFlags(DEBUG_FLAG);
739     }
740
741     DEBUG("VERBOSITY (%d), DEBUG mode (0x%x)\n", getVerbosity(), getDebugFlags());
742
743     /* lock */
744     ptsc_lock();
745
746     /* load config, /etc/ptsc.conf */
747     if (config_filename == NULL) {
748         // this goto stdout and bad with "-m"
749         VERBOSE(2, NLS(MS_OPENPTS, OPENPTS_COLLECTOR_CONFIG_FILE,
750             "Config file: %s\n"), PTSC_CONFIG_FILE);
751         rc = readPtsConfig(conf, PTSC_CONFIG_FILE);
752         if (rc != PTS_SUCCESS) {
753             DEBUG("readPtsConfig() failed\n");
754             goto free;
755         }
756     } else {
757         VERBOSE(2, NLS(MS_OPENPTS, OPENPTS_COLLECTOR_CONFIG_FILE,
758             "Config file: %s\n"), config_filename);
759         rc = readPtsConfig(conf, config_filename);
760         if (rc != PTS_SUCCESS) {
761             DEBUG("readPtsConfig() failed\n");
762             goto free;
763         }
764     }
765
766     /* logging */
767
768     /* Check initialization */
769     if (command != COMMAND_INIT) {
770         /* initilized? */
771         if (checkFile(conf->uuid->filename) != OPENPTS_FILE_EXISTS) {
772             // missing
773             LOG(LOG_ERR, "ptsc is not initialized yet");
774             ERROR(NLS(MS_OPENPTS, OPENPTS_COLLECTOR_NOT_INITIALIZED,
775                 "ptsc is not initialized yet.\n\n"));
776             goto free;
777         }
778     }
779
780     /* only do this when needed */
781     if (command != COMMAND_STATUS) {
782         /* check IR dir */
783         if (checkDir(conf->ir_dir) != PTS_SUCCESS) {
784             rc = makeDir(conf->ir_dir);
785             if (rc != PTS_SUCCESS) {
786                 LOG(LOG_ERR, "Can not create the dir to store IR, %s\n", conf->ir_dir);
787                 goto free;
788             }
789             rc = chmodDir(conf->ir_dir, 1);
790             if (rc != PTS_SUCCESS) {
791                 LOG(LOG_ERR, "Can not create the dir to store IR, %s\n", conf->ir_dir);
792                 goto free;
793             }
794         }
795     }
796
797     /* initialize the PTS collector */
798     if (command == COMMAND_INIT) {
799         VERBOSE(1, NLS(MS_OPENPTS, OPENPTS_COLLECTOR_INIT_RM, "Initializing Reference Manifest\n"));
800         rc = init(conf, prop_num, start, end);
801         /* Exit */
802         goto free;
803     }
804
805     /* Clear the PTS collector */
806     if (command == COMMAND_CLEAR) {
807         rc = clear(conf, force);
808         /* Exit */
809         goto free;
810     }
811
812
813     /* RM UUID */
814     if (conf->rm_uuid == NULL) {
815         LOG(LOG_ERR, "rm_uuid is missing");
816         /* Exit */
817         goto free;
818     } else {
819         rc = readOpenptsUuidFile(conf->rm_uuid);
820         if (rc != PTS_SUCCESS) {
821             DEBUG("readOpenptsUuidFile(%s) failed\n", conf->rm_uuid->filename);
822             OUTPUT(NLS(MS_OPENPTS, OPENPTS_COLLECTOR_FAILED_READ_RM_UUID,
823                    "Failed to read the Reference Manifest UUID file '%s':\n"
824                    "Please ensure on the target that:\n"
825                    "  * ptsc has been initialized (ptsc -i)\n"
826                    "  * you (uid==%d) are allowed to attest (i.e. a member of group '%s')\n\n"),
827                    conf->rm_uuid->filename, getuid(), PTSC_GROUP_NAME);
828             goto free;
829         } else {
830             DEBUG("conf->str_rm_uuid         : %s\n", conf->rm_uuid->str);
831         }
832     }
833
834     /* NEWRM UUID */
835     if (conf->newrm_uuid == NULL) {
836         LOG(LOG_ERR, "newrm_uuid is missing.");
837         /* Exit */
838         goto free;
839     } else {
840         rc = readOpenptsUuidFile(conf->newrm_uuid);
841         if (rc != PTS_SUCCESS) {
842             DEBUG("conf->str_newrm_uuid      : missing (file:%s)\n", conf->newrm_uuid->filename);
843             // goto free;
844         } else {
845             DEBUG("conf->str_newrm_uuid      : %s (for next boot)\n", conf->newrm_uuid->str);
846         }
847     }
848
849     /* load RSA PUB key */
850     // TODO single key => multiple keys?
851 #ifdef CONFIG_NO_TSS
852     LOG(LOG_TODO, "CONFIG_NO_TSS, no TPM_PUBKEY\n");
853     conf->pubkey_length = 0;
854     conf->pubkey = NULL;
855 #else
856     /* only do this when needed */
857     if (command != COMMAND_STATUS) {
858         /* get PUBKEY */
859         rc = getTssPubKey(
860                 conf->uuid->uuid,
861                 conf->aik_storage_type,  // TSS_PS_TYPE_SYSTEM,
862                 conf->srk_password_mode,
863                 conf->tpm_resetdalock,
864                 conf->aik_storage_filename,  // NULL,
865                 conf->aik_auth_type,
866                 &conf->pubkey_length,
867                 &conf->pubkey);
868         if (rc != TSS_SUCCESS) {
869             LOG(LOG_ERR, "getTssPubKey() fail rc=0x%x srk password mode=%d, key =%s\n",
870                 rc, conf->srk_password_mode, conf->uuid->str);
871             OUTPUT(NLS(MS_OPENPTS, OPENPTS_TPM_TSS_COMMS_FAILURE,
872                 "TSS communications failure. Is tcsd running?\n"));
873             goto free;
874         }
875     }
876 #endif
877
878     /* run */
879     switch (command) {
880 #ifdef CONFIG_AUTO_RM_UPDATE
881         case COMMAND_AUTO_UPDATE:
882             /* update by command, but HUP is better */
883             VERBOSE(1, "Updating Reference Manifest\n");
884             /* update RMs */
885             rc = update(conf, prop_num, start, end, remove);
886             if (rc != PTS_SUCCESS) {
887                 LOG(LOG_ERR, "update was fail\n");
888             }
889             break;
890 #endif
891         case COMMAND_STATUS:
892             rc = printCollectorStatus(conf);
893             break;
894         case COMMAND_SELFTEST:
895             rc = selftest(conf, prop_num, start, end);
896             if (rc == OPENPTS_SELFTEST_SUCCESS) {
897                 OUTPUT(NLS(MS_OPENPTS, OPENPTS_COLLECTOR_SUCCESS, "selftest - OK\n"));
898                 LOG(LOG_INFO, "selftest - OK\n");
899             } else if (rc == OPENPTS_SELFTEST_RENEWED) {
900                 OUTPUT(NLS(MS_OPENPTS, OPENPTS_COLLECTOR_RENEWED, "selftest - Renewed\n"));
901                 LOG(LOG_INFO, "selftest - Renewed\n");
902             } else if (rc == OPENPTS_SELFTEST_FALLBACK) {
903                 OUTPUT(NLS(MS_OPENPTS, OPENPTS_COLLECTOR_FALLBACK, "selftest - fallback\n"));
904                 LOG(LOG_INFO, "selftest - fallback\n");
905             } else if (rc == OPENPTS_SELFTEST_FAILED) {
906                 OUTPUT(NLS(MS_OPENPTS, OPENPTS_COLLECTOR_FAIL, "selftest - fail\n"));
907                 LOG(LOG_INFO, "selftest - fail\n");
908             } else {
909                 LOG(LOG_ERR, "TBD\n");
910             }
911             break;
912         case COMMAND_STARTUP:
913             rc = selftest(conf, prop_num, start, end);
914             if (rc == OPENPTS_SELFTEST_SUCCESS) {
915                 OUTPUT(NLS(MS_OPENPTS, OPENPTS_COLLECTOR_SUCCESS, "selftest - OK\n"));
916                 LOG(LOG_INFO, "selftest - OK\n");
917                 /* timestamp */
918                 extendEvCollectorStart(conf);  // collector.c
919             } else if (rc == OPENPTS_SELFTEST_RENEWED) {
920                 OUTPUT(NLS(MS_OPENPTS, OPENPTS_COLLECTOR_RENEWED, "selftest - Renewed\n"));
921                 LOG(LOG_INFO, "selftest - Renewed\n");
922                 /* timestamp */
923                 extendEvCollectorStart(conf);
924             } else if (rc == OPENPTS_SELFTEST_FALLBACK) {
925                 OUTPUT(NLS(MS_OPENPTS, OPENPTS_COLLECTOR_FALLBACK, "selftest - fallback\n"));
926                 LOG(LOG_INFO, "selftest - fallback\n");
927                 /* timestamp */
928                 extendEvCollectorStart(conf);
929             } else if (rc == OPENPTS_SELFTEST_FAILED) {
930                 OUTPUT(NLS(MS_OPENPTS, OPENPTS_COLLECTOR_FAIL, "selftest - fail\n"));
931                 LOG(LOG_INFO, "selftest - fail\n");
932                 if (conf->autoupdate == 1) {
933                     LOG(LOG_ERR, "selftest failed, trying to generate a new manifest\n");
934                     /* del RM_UUID */
935                     conf->rm_uuid->status = OPENPTS_UUID_FILENAME_ONLY;
936                     if (conf->rm_uuid->uuid != NULL) freeUuid(conf->rm_uuid->uuid);
937                     if (conf->rm_uuid->str != NULL) xfree(conf->rm_uuid->str);
938                     if (conf->rm_uuid->time != NULL) xfree(conf->rm_uuid->time);
939                     conf->rm_uuid->uuid = NULL;
940                     conf->rm_uuid->str = NULL;
941                     conf->rm_uuid->time = NULL;
942
943                     /* gen new RM_UUID and RM */
944                     rc = newrm(conf, prop_num, start, end);
945                     if (rc != PTS_SUCCESS) {
946                         OUTPUT(NLS(MS_OPENPTS, OPENPTS_COLLECTOR_UPDATE_RM_FAIL,
947                             "Failed to generated a reference manifest\n"));
948                         LOG(LOG_INFO, "Failed to generated a reference manifest\n");
949                         goto free;
950                     }
951                     rc = selftest(conf, prop_num, start, end);
952                     if (rc == OPENPTS_SELFTEST_SUCCESS) {
953                         OUTPUT(NLS(MS_OPENPTS, OPENPTS_COLLECTOR_SUCCESS, "selftest - OK\n"));
954                         OUTPUT(NLS(MS_OPENPTS, OPENPTS_COLLECTOR_UPDATE_RM_SUCCESS,
955                             "Successfully generated the reference manifest\n"));
956                         LOG(LOG_INFO, "selftest - OK\n");
957                         LOG(LOG_INFO, "Successfully generated the reference manifest\n");
958                     } else if (rc == OPENPTS_SELFTEST_RENEWED) {
959                         OUTPUT(NLS(MS_OPENPTS, OPENPTS_COLLECTOR_RENEWED, "selftest - Renewed\n"));
960                         LOG(LOG_INFO, "selftest - Renewed\n");
961                     } else {
962                         LOG(LOG_ERR, "TBD\n");
963                     }
964                 } else {
965                     OUTPUT(NLS(MS_OPENPTS, OPENPTS_COLLECTOR_UPDATE_RM_WONT,
966                         "selftest failed, keeping existing manifests as requested by configuration\n"));
967                     LOG(LOG_INFO, "selftest failed, keeping existing manifests as requested by configuration\n");
968                 }
969             } else {
970                 LOG(LOG_ERR, "TBD\n");
971             }
972             break;
973         case COMMAND_UPDATE:
974             /* del RM_UUID */
975             conf->rm_uuid->status = OPENPTS_UUID_FILENAME_ONLY;
976             if (conf->rm_uuid->uuid != NULL) freeUuid(conf->rm_uuid->uuid);
977             if (conf->rm_uuid->str != NULL) xfree(conf->rm_uuid->str);
978             if (conf->rm_uuid->time != NULL) xfree(conf->rm_uuid->time);
979             conf->rm_uuid->uuid = NULL;
980             conf->rm_uuid->str = NULL;
981             conf->rm_uuid->time = NULL;
982
983             /* gen new RM_UUID and RM */
984             rc = newrm(conf, prop_num, start, end);
985             if (rc != PTS_SUCCESS) {
986                 LOG(LOG_ERR, "newrm() fail\n");
987                 goto free;
988             }
989
990             /* self test */
991             rc = selftest(conf, prop_num, start, end);
992             if (rc == OPENPTS_SELFTEST_SUCCESS) {
993                 VERBOSE(1, NLS(MS_OPENPTS, OPENPTS_COLLECTOR_UPDATE_RM_SUCCESS,
994                     "Successfully generated the reference manifest\n"));
995             } else if (rc == OPENPTS_SELFTEST_RENEWED) {
996                 LOG(LOG_TODO, "TBD\n");
997             } else {
998                 LOG(LOG_TODO, "TBD\n");
999             }
1000             break;
1001         case COMMAND_IFM:
1002             /* run colelctor IF-M */
1003             rc = collector(conf);
1004             break;
1005         default:
1006             LOG(LOG_ERR, "bad command\n");
1007             break;
1008     }
1009
1010  free:
1011     freePtsConfig(conf);
1012
1013     if (rc != PTS_SUCCESS) {
1014         LOG(LOG_ERR, "ptsc exit. rc = %d", rc);
1015     }
1016     return rc;
1017 }