OSDN Git Service

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