1// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <cstdio>
6#include <iostream>
7
8#include "base/basictypes.h"
9#include "base/command_line.h"
10#include "base/files/file_path.h"
11#include "base/json/json_file_value_serializer.h"
12#include "base/logging.h"
13#include "base/values.h"
14#include "chromeos/network/onc/onc_signature.h"
15#include "chromeos/network/onc/onc_validator.h"
16
17// Command line switches.
18const char kSwitchErrorOnUnknownField[] = "error-on-unknown-field";
19const char kSwitchErrorOnWrongRecommended[] = "error-on-wrong-recommended";
20const char kSwitchErrorOnMissingField[] = "error-on-missing-field";
21const char kSwitchManagedOnc[] = "managed-onc";
22const char kSwitchUserPolicy[] = "user-policy";
23const char kSwitchDevicePolicy[] = "device-policy";
24const char kSwitchUserImport[] = "user-import";
25
26const char* kSwitches[] = {
27  kSwitchErrorOnUnknownField,
28  kSwitchErrorOnWrongRecommended,
29  kSwitchErrorOnMissingField,
30  kSwitchManagedOnc,
31  kSwitchUserPolicy,
32  kSwitchDevicePolicy,
33  kSwitchUserImport
34};
35
36// Return codes.
37enum ReturnCode {
38  kStatusValid = 0,
39  kStatusWarnings = 1,
40  kStatusInvalid = 2,
41  kStatusJsonError = 3,
42  kStatusArgumentError = 4,
43};
44
45const char kToplevelConfiguration[] = "ToplevelConfiguration";
46const char kNetworkConfiguration[] = "NetworkConfiguration";
47const char kCertificate[] = "Certificate";
48const char* kTypes[] = {
49  kToplevelConfiguration,
50  kNetworkConfiguration,
51  kCertificate
52};
53
54void PrintHelp() {
55  fprintf(stderr,
56          "Usage:\n"
57          "  onc_validator [OPTION]... [TYPE] onc_file\n"
58          "\n"
59          "Valid TYPEs are:\n");
60  for (size_t i = 0; i < arraysize(kTypes); ++i)
61    fprintf(stderr, "  %s\n", kTypes[i]);
62
63  fprintf(stderr,
64          "\n"
65          "Valid OPTIONs are:\n");
66  for (size_t i = 0; i < arraysize(kSwitches); ++i)
67    fprintf(stderr, "  --%s\n", kSwitches[i]);
68
69  fprintf(stderr,
70          "\n"
71          "Exit status is one of:\n"
72          "  %i  File is valid without warnings.\n"
73          "  %i  File is valid with warnings,\n"
74          "       i.e. there were errors which were degraded to warnings.\n"
75          "  %i  File is invalid.\n"
76          "  %i  File couldn't be read or is not a valid JSON dictionary.\n"
77          "  %i  Some command line arguments are wrong.\n",
78          kStatusValid,
79          kStatusWarnings,
80          kStatusInvalid,
81          kStatusJsonError,
82          kStatusArgumentError);
83}
84
85scoped_ptr<base::DictionaryValue> ReadDictionary(std::string filename) {
86  base::FilePath path(filename);
87  JSONFileValueSerializer serializer(path);
88  serializer.set_allow_trailing_comma(true);
89
90  base::DictionaryValue* dict = NULL;
91
92  std::string json_error;
93  base::Value* value = serializer.Deserialize(NULL, &json_error);
94  if (!value) {
95    LOG(ERROR) << "Couldn't json-deserialize file '" << filename
96               << "': " << json_error;
97    return make_scoped_ptr(dict);
98  }
99
100  if (!value->GetAsDictionary(&dict)) {
101    LOG(ERROR) << "File '" << filename
102               << "' does not contain a dictionary as expected, but type "
103               << value->GetType();
104  }
105
106  return make_scoped_ptr(dict);
107}
108
109int main(int argc, const char* argv[]) {
110  CommandLine::Init(argc, argv);
111
112  const CommandLine& command_line = *CommandLine::ForCurrentProcess();
113  CommandLine::StringVector args = command_line.GetArgs();
114  if (args.size() != 2) {
115    PrintHelp();
116    return kStatusArgumentError;
117  }
118
119  scoped_ptr<base::DictionaryValue> onc_object = ReadDictionary(args[1]);
120
121  if (!onc_object)
122    return kStatusJsonError;
123
124  chromeos::onc::Validator validator(
125      command_line.HasSwitch(kSwitchErrorOnUnknownField),
126      command_line.HasSwitch(kSwitchErrorOnWrongRecommended),
127      command_line.HasSwitch(kSwitchErrorOnMissingField),
128      command_line.HasSwitch(kSwitchManagedOnc));
129
130  if (command_line.HasSwitch(kSwitchUserPolicy))
131    validator.SetOncSource(::onc::ONC_SOURCE_USER_POLICY);
132  else if (command_line.HasSwitch(kSwitchDevicePolicy))
133    validator.SetOncSource(::onc::ONC_SOURCE_DEVICE_POLICY);
134  else if (command_line.HasSwitch(kSwitchUserImport))
135    validator.SetOncSource(::onc::ONC_SOURCE_USER_IMPORT);
136
137  std::string type_arg(args[0]);
138  const chromeos::onc::OncValueSignature* signature = NULL;
139  if (type_arg == kToplevelConfiguration) {
140    signature = &chromeos::onc::kToplevelConfigurationSignature;
141  } else if (type_arg == kNetworkConfiguration) {
142    signature = &chromeos::onc::kNetworkConfigurationSignature;
143  } else if (type_arg == kCertificate) {
144    signature = &chromeos::onc::kCertificateSignature;
145  } else {
146    LOG(ERROR) << "Unknown ONC type '" << type_arg << "'";
147    return kStatusArgumentError;
148  }
149
150  chromeos::onc::Validator::Result result;
151  validator.ValidateAndRepairObject(signature, *onc_object, &result);
152
153  switch(result) {
154    case chromeos::onc::Validator::VALID:
155      return kStatusValid;
156    case chromeos::onc::Validator::VALID_WITH_WARNINGS:
157      return kStatusWarnings;
158    case chromeos::onc::Validator::INVALID:
159      return kStatusInvalid;
160    default:
161      CHECK(false);
162  }
163}
164