xref: /unit/src/nxt_conf_validation.c (revision 804:fe8d2dea28dd)
1 
2 /*
3  * Copyright (C) Valentin V. Bartenev
4  * Copyright (C) NGINX, Inc.
5  */
6 
7 #include <nxt_main.h>
8 #include <nxt_conf.h>
9 #include <nxt_cert.h>
10 #include <nxt_router.h>
11 
12 
13 typedef enum {
14     NXT_CONF_VLDT_NULL    = 1 << NXT_CONF_NULL,
15     NXT_CONF_VLDT_BOOLEAN = 1 << NXT_CONF_BOOLEAN,
16     NXT_CONF_VLDT_INTEGER = 1 << NXT_CONF_INTEGER,
17     NXT_CONF_VLDT_NUMBER  = 1 << NXT_CONF_NUMBER,
18     NXT_CONF_VLDT_STRING  = 1 << NXT_CONF_STRING,
19     NXT_CONF_VLDT_ARRAY   = 1 << NXT_CONF_ARRAY,
20     NXT_CONF_VLDT_OBJECT  = 1 << NXT_CONF_OBJECT,
21 } nxt_conf_vldt_type_t;
22 
23 
24 typedef struct {
25     nxt_str_t             name;
26     nxt_conf_vldt_type_t  type;
27     nxt_int_t             (*validator)(nxt_conf_validation_t *vldt,
28                                        nxt_conf_value_t *value, void *data);
29     void                  *data;
30 } nxt_conf_vldt_object_t;
31 
32 
33 #define NXT_CONF_VLDT_NEXT(f)  { nxt_null_string, 0, NULL, (f) }
34 #define NXT_CONF_VLDT_END      { nxt_null_string, 0, NULL, NULL }
35 
36 
37 typedef nxt_int_t (*nxt_conf_vldt_member_t)(nxt_conf_validation_t *vldt,
38                                             nxt_str_t *name,
39                                             nxt_conf_value_t *value);
40 typedef nxt_int_t (*nxt_conf_vldt_element_t)(nxt_conf_validation_t *vldt,
41                                              nxt_conf_value_t *value);
42 typedef nxt_int_t (*nxt_conf_vldt_system_t)(nxt_conf_validation_t *vldt,
43                                             char *name);
44 
45 
46 static nxt_int_t nxt_conf_vldt_type(nxt_conf_validation_t *vldt,
47     nxt_str_t *name, nxt_conf_value_t *value, nxt_conf_vldt_type_t type);
48 static nxt_int_t nxt_conf_vldt_error(nxt_conf_validation_t *vldt,
49     const char *fmt, ...);
50 
51 static nxt_int_t nxt_conf_vldt_listener(nxt_conf_validation_t *vldt,
52     nxt_str_t *name, nxt_conf_value_t *value);
53 #if (NXT_TLS)
54 static nxt_int_t nxt_conf_vldt_certificate(nxt_conf_validation_t *vldt,
55     nxt_conf_value_t *value, void *data);
56 #endif
57 static nxt_int_t nxt_conf_vldt_app_name(nxt_conf_validation_t *vldt,
58     nxt_conf_value_t *value, void *data);
59 static nxt_int_t nxt_conf_vldt_app(nxt_conf_validation_t *vldt,
60     nxt_str_t *name, nxt_conf_value_t *value);
61 static nxt_int_t nxt_conf_vldt_object(nxt_conf_validation_t *vldt,
62     nxt_conf_value_t *value, void *data);
63 static nxt_int_t nxt_conf_vldt_processes(nxt_conf_validation_t *vldt,
64     nxt_conf_value_t *value, void *data);
65 static nxt_int_t nxt_conf_vldt_object_iterator(nxt_conf_validation_t *vldt,
66     nxt_conf_value_t *value, void *data);
67 static nxt_int_t nxt_conf_vldt_array_iterator(nxt_conf_validation_t *vldt,
68     nxt_conf_value_t *value, void *data);
69 static nxt_int_t nxt_conf_vldt_system(nxt_conf_validation_t *vldt,
70     nxt_conf_value_t *value, void *data);
71 static nxt_int_t nxt_conf_vldt_user(nxt_conf_validation_t *vldt, char *name);
72 static nxt_int_t nxt_conf_vldt_group(nxt_conf_validation_t *vldt, char *name);
73 static nxt_int_t nxt_conf_vldt_environment(nxt_conf_validation_t *vldt,
74     nxt_str_t *name, nxt_conf_value_t *value);
75 static nxt_int_t nxt_conf_vldt_argument(nxt_conf_validation_t *vldt,
76     nxt_conf_value_t *value);
77 static nxt_int_t nxt_conf_vldt_php_option(nxt_conf_validation_t *vldt,
78     nxt_str_t *name, nxt_conf_value_t *value);
79 
80 
81 static nxt_conf_vldt_object_t  nxt_conf_vldt_http_members[] = {
82     { nxt_string("header_read_timeout"),
83       NXT_CONF_VLDT_INTEGER,
84       NULL,
85       NULL },
86 
87     { nxt_string("body_read_timeout"),
88       NXT_CONF_VLDT_INTEGER,
89       NULL,
90       NULL },
91 
92     { nxt_string("send_timeout"),
93       NXT_CONF_VLDT_INTEGER,
94       NULL,
95       NULL },
96 
97     { nxt_string("idle_timeout"),
98       NXT_CONF_VLDT_INTEGER,
99       NULL,
100       NULL },
101 
102     { nxt_string("max_body_size"),
103       NXT_CONF_VLDT_INTEGER,
104       NULL,
105       NULL },
106 
107     NXT_CONF_VLDT_END
108 };
109 
110 
111 static nxt_conf_vldt_object_t  nxt_conf_vldt_setting_members[] = {
112     { nxt_string("http"),
113       NXT_CONF_VLDT_OBJECT,
114       &nxt_conf_vldt_object,
115       (void *) &nxt_conf_vldt_http_members },
116 
117     NXT_CONF_VLDT_END
118 };
119 
120 
121 static nxt_conf_vldt_object_t  nxt_conf_vldt_root_members[] = {
122     { nxt_string("settings"),
123       NXT_CONF_VLDT_OBJECT,
124       &nxt_conf_vldt_object,
125       (void *) &nxt_conf_vldt_setting_members },
126 
127     { nxt_string("listeners"),
128       NXT_CONF_VLDT_OBJECT,
129       &nxt_conf_vldt_object_iterator,
130       (void *) &nxt_conf_vldt_listener },
131 
132     { nxt_string("applications"),
133       NXT_CONF_VLDT_OBJECT,
134       &nxt_conf_vldt_object_iterator,
135       (void *) &nxt_conf_vldt_app },
136 
137     { nxt_string("access_log"),
138       NXT_CONF_VLDT_STRING,
139       NULL,
140       NULL },
141 
142     NXT_CONF_VLDT_END
143 };
144 
145 
146 #if (NXT_TLS)
147 
148 static nxt_conf_vldt_object_t  nxt_conf_vldt_tls_members[] = {
149     { nxt_string("certificate"),
150       NXT_CONF_VLDT_STRING,
151       &nxt_conf_vldt_certificate,
152       NULL },
153 
154     NXT_CONF_VLDT_END
155 };
156 
157 #endif
158 
159 
160 static nxt_conf_vldt_object_t  nxt_conf_vldt_listener_members[] = {
161     { nxt_string("application"),
162       NXT_CONF_VLDT_STRING,
163       &nxt_conf_vldt_app_name,
164       NULL },
165 
166 #if (NXT_TLS)
167 
168     { nxt_string("tls"),
169       NXT_CONF_VLDT_OBJECT,
170       &nxt_conf_vldt_object,
171       (void *) &nxt_conf_vldt_tls_members },
172 
173 #endif
174 
175     NXT_CONF_VLDT_END
176 };
177 
178 
179 static nxt_conf_vldt_object_t  nxt_conf_vldt_app_limits_members[] = {
180     { nxt_string("timeout"),
181       NXT_CONF_VLDT_INTEGER,
182       NULL,
183       NULL },
184 
185     { nxt_string("reschedule_timeout"),
186       NXT_CONF_VLDT_INTEGER,
187       NULL,
188       NULL },
189 
190     { nxt_string("requests"),
191       NXT_CONF_VLDT_INTEGER,
192       NULL,
193       NULL },
194 
195     NXT_CONF_VLDT_END
196 };
197 
198 
199 static nxt_conf_vldt_object_t  nxt_conf_vldt_app_processes_members[] = {
200     { nxt_string("spare"),
201       NXT_CONF_VLDT_INTEGER,
202       NULL,
203       NULL },
204 
205     { nxt_string("max"),
206       NXT_CONF_VLDT_INTEGER,
207       NULL,
208       NULL },
209 
210     { nxt_string("idle_timeout"),
211       NXT_CONF_VLDT_INTEGER,
212       NULL,
213       NULL },
214 
215     NXT_CONF_VLDT_END
216 };
217 
218 
219 static nxt_conf_vldt_object_t  nxt_conf_vldt_common_members[] = {
220     { nxt_string("type"),
221       NXT_CONF_VLDT_STRING,
222       NULL,
223       NULL },
224 
225     { nxt_string("limits"),
226       NXT_CONF_VLDT_OBJECT,
227       &nxt_conf_vldt_object,
228       (void *) &nxt_conf_vldt_app_limits_members },
229 
230     { nxt_string("processes"),
231       NXT_CONF_VLDT_INTEGER | NXT_CONF_VLDT_OBJECT,
232       &nxt_conf_vldt_processes,
233       (void *) &nxt_conf_vldt_app_processes_members },
234 
235     { nxt_string("user"),
236       NXT_CONF_VLDT_STRING,
237       nxt_conf_vldt_system,
238       (void *) &nxt_conf_vldt_user },
239 
240     { nxt_string("group"),
241       NXT_CONF_VLDT_STRING,
242       nxt_conf_vldt_system,
243       (void *) &nxt_conf_vldt_group },
244 
245     { nxt_string("working_directory"),
246       NXT_CONF_VLDT_STRING,
247       NULL,
248       NULL },
249 
250     { nxt_string("environment"),
251       NXT_CONF_VLDT_OBJECT,
252       &nxt_conf_vldt_object_iterator,
253       (void *) &nxt_conf_vldt_environment },
254 
255     NXT_CONF_VLDT_END
256 };
257 
258 
259 static nxt_conf_vldt_object_t  nxt_conf_vldt_external_members[] = {
260     { nxt_string("executable"),
261       NXT_CONF_VLDT_STRING,
262       NULL,
263       NULL },
264 
265     { nxt_string("arguments"),
266       NXT_CONF_VLDT_ARRAY,
267       &nxt_conf_vldt_array_iterator,
268       (void *) &nxt_conf_vldt_argument },
269 
270     NXT_CONF_VLDT_NEXT(&nxt_conf_vldt_common_members)
271 };
272 
273 
274 static nxt_conf_vldt_object_t  nxt_conf_vldt_python_members[] = {
275     { nxt_string("home"),
276       NXT_CONF_VLDT_STRING,
277       NULL,
278       NULL },
279 
280     { nxt_string("path"),
281       NXT_CONF_VLDT_STRING,
282       NULL,
283       NULL },
284 
285     { nxt_string("module"),
286       NXT_CONF_VLDT_STRING,
287       NULL,
288       NULL },
289 
290     NXT_CONF_VLDT_NEXT(&nxt_conf_vldt_common_members)
291 };
292 
293 
294 static nxt_conf_vldt_object_t  nxt_conf_vldt_php_options_members[] = {
295     { nxt_string("file"),
296       NXT_CONF_VLDT_STRING,
297       NULL,
298       NULL },
299 
300     { nxt_string("admin"),
301       NXT_CONF_VLDT_OBJECT,
302       &nxt_conf_vldt_object_iterator,
303       (void *) &nxt_conf_vldt_php_option },
304 
305     { nxt_string("user"),
306       NXT_CONF_VLDT_OBJECT,
307       &nxt_conf_vldt_object_iterator,
308       (void *) &nxt_conf_vldt_php_option },
309 
310     NXT_CONF_VLDT_END
311 };
312 
313 
314 static nxt_conf_vldt_object_t  nxt_conf_vldt_php_members[] = {
315     { nxt_string("root"),
316       NXT_CONF_VLDT_STRING,
317       NULL,
318       NULL },
319 
320     { nxt_string("script"),
321       NXT_CONF_VLDT_STRING,
322       NULL,
323       NULL },
324 
325     { nxt_string("index"),
326       NXT_CONF_VLDT_STRING,
327       NULL,
328       NULL },
329 
330     { nxt_string("options"),
331       NXT_CONF_VLDT_OBJECT,
332       &nxt_conf_vldt_object,
333       (void *) &nxt_conf_vldt_php_options_members },
334 
335     NXT_CONF_VLDT_NEXT(&nxt_conf_vldt_common_members)
336 };
337 
338 
339 static nxt_conf_vldt_object_t  nxt_conf_vldt_perl_members[] = {
340     { nxt_string("script"),
341       NXT_CONF_VLDT_STRING,
342       NULL,
343       NULL },
344 
345     NXT_CONF_VLDT_NEXT(&nxt_conf_vldt_common_members)
346 };
347 
348 
349 static nxt_conf_vldt_object_t  nxt_conf_vldt_ruby_members[] = {
350     { nxt_string("script"),
351       NXT_CONF_VLDT_STRING,
352       NULL,
353       NULL },
354 
355     NXT_CONF_VLDT_NEXT(&nxt_conf_vldt_common_members)
356 };
357 
358 
359 nxt_int_t
360 nxt_conf_validate(nxt_conf_validation_t *vldt)
361 {
362     nxt_int_t  ret;
363 
364     ret = nxt_conf_vldt_type(vldt, NULL, vldt->conf, NXT_CONF_VLDT_OBJECT);
365 
366     if (ret != NXT_OK) {
367         return ret;
368     }
369 
370     return nxt_conf_vldt_object(vldt, vldt->conf, nxt_conf_vldt_root_members);
371 }
372 
373 
374 #define NXT_CONF_VLDT_ANY_TYPE                                                \
375     "either a null, a boolean, an integer, "                                  \
376     "a number, a string, an array, or an object"
377 
378 
379 static nxt_int_t
380 nxt_conf_vldt_type(nxt_conf_validation_t *vldt, nxt_str_t *name,
381     nxt_conf_value_t *value, nxt_conf_vldt_type_t type)
382 {
383     u_char      *p;
384     nxt_str_t   expected;
385     nxt_bool_t  serial;
386     nxt_uint_t  value_type, n, t;
387     u_char      buf[nxt_length(NXT_CONF_VLDT_ANY_TYPE)];
388 
389     static nxt_str_t  type_name[] = {
390         nxt_string("a null"),
391         nxt_string("a boolean"),
392         nxt_string("an integer"),
393         nxt_string("a number"),
394         nxt_string("a string"),
395         nxt_string("an array"),
396         nxt_string("an object"),
397     };
398 
399     value_type = nxt_conf_type(value);
400 
401     if ((1 << value_type) & type) {
402         return NXT_OK;
403     }
404 
405     p = buf;
406 
407     n = nxt_popcount(type);
408 
409     if (n > 1) {
410         p = nxt_cpymem(p, "either ", 7);
411     }
412 
413     serial = (n > 2);
414 
415     for ( ;; ) {
416         t = __builtin_ffs(type) - 1;
417 
418         p = nxt_cpymem(p, type_name[t].start, type_name[t].length);
419 
420         n--;
421 
422         if (n == 0) {
423             break;
424         }
425 
426         if (n > 1 || serial) {
427             *p++ = ',';
428         }
429 
430         if (n == 1) {
431             p = nxt_cpymem(p, " or", 3);
432         }
433 
434         *p++ = ' ';
435 
436         type = type & ~(1 << t);
437     }
438 
439     expected.length = p - buf;
440     expected.start = buf;
441 
442     if (name == NULL) {
443         return nxt_conf_vldt_error(vldt,
444                                    "The configuration must be %V, but not %V.",
445                                    &expected, &type_name[value_type]);
446     }
447 
448     return nxt_conf_vldt_error(vldt,
449                                "The \"%V\" value must be %V, but not %V.",
450                                name, &expected, &type_name[value_type]);
451 }
452 
453 
454 static nxt_int_t
455 nxt_conf_vldt_error(nxt_conf_validation_t *vldt, const char *fmt, ...)
456 {
457     u_char   *p, *end;
458     size_t   size;
459     va_list  args;
460     u_char   error[NXT_MAX_ERROR_STR];
461 
462     va_start(args, fmt);
463     end = nxt_vsprintf(error, error + NXT_MAX_ERROR_STR, fmt, args);
464     va_end(args);
465 
466     size = end - error;
467 
468     p = nxt_mp_nget(vldt->pool, size);
469     if (p == NULL) {
470         return NXT_ERROR;
471     }
472 
473     nxt_memcpy(p, error, size);
474 
475     vldt->error.length = size;
476     vldt->error.start = p;
477 
478     return NXT_DECLINED;
479 }
480 
481 
482 static nxt_int_t
483 nxt_conf_vldt_listener(nxt_conf_validation_t *vldt, nxt_str_t *name,
484     nxt_conf_value_t *value)
485 {
486     nxt_int_t  ret;
487 
488     ret = nxt_conf_vldt_type(vldt, name, value, NXT_CONF_VLDT_OBJECT);
489 
490     if (ret != NXT_OK) {
491         return ret;
492     }
493 
494     return nxt_conf_vldt_object(vldt, value, nxt_conf_vldt_listener_members);
495 }
496 
497 
498 #if (NXT_TLS)
499 
500 static nxt_int_t
501 nxt_conf_vldt_certificate(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
502     void *data)
503 {
504     nxt_str_t         name;
505     nxt_conf_value_t  *cert;
506 
507     nxt_conf_get_string(value, &name);
508 
509     cert = nxt_cert_info_get(&name);
510 
511     if (cert == NULL) {
512         return nxt_conf_vldt_error(vldt, "Certificate \"%V\" is not found.",
513                                    &name);
514     }
515 
516     return NXT_OK;
517 }
518 
519 #endif
520 
521 
522 static nxt_int_t
523 nxt_conf_vldt_app_name(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
524     void *data)
525 {
526     nxt_str_t         name;
527     nxt_conf_value_t  *apps, *app;
528 
529     static nxt_str_t  apps_str = nxt_string("applications");
530 
531     nxt_conf_get_string(value, &name);
532 
533     apps = nxt_conf_get_object_member(vldt->conf, &apps_str, NULL);
534 
535     if (nxt_slow_path(apps == NULL)) {
536         goto error;
537     }
538 
539     app = nxt_conf_get_object_member(apps, &name, NULL);
540 
541     if (nxt_slow_path(app == NULL)) {
542         goto error;
543     }
544 
545     return NXT_OK;
546 
547 error:
548 
549     return nxt_conf_vldt_error(vldt, "Listening socket is assigned for "
550                                      "a non existing application \"%V\".",
551                                      &name);
552 }
553 
554 
555 static nxt_int_t
556 nxt_conf_vldt_app(nxt_conf_validation_t *vldt, nxt_str_t *name,
557     nxt_conf_value_t *value)
558 {
559     nxt_int_t              ret;
560     nxt_str_t              type;
561     nxt_thread_t           *thread;
562     nxt_conf_value_t       *type_value;
563     nxt_app_lang_module_t  *lang;
564 
565     static nxt_str_t  type_str = nxt_string("type");
566 
567     static void  *members[] = {
568         nxt_conf_vldt_external_members,
569         nxt_conf_vldt_python_members,
570         nxt_conf_vldt_php_members,
571         nxt_conf_vldt_perl_members,
572         nxt_conf_vldt_ruby_members,
573     };
574 
575     ret = nxt_conf_vldt_type(vldt, name, value, NXT_CONF_VLDT_OBJECT);
576 
577     if (ret != NXT_OK) {
578         return ret;
579     }
580 
581     type_value = nxt_conf_get_object_member(value, &type_str, NULL);
582 
583     if (type_value == NULL) {
584         return nxt_conf_vldt_error(vldt,
585                            "Application must have the \"type\" property set.");
586     }
587 
588     ret = nxt_conf_vldt_type(vldt, &type_str, type_value, NXT_CONF_VLDT_STRING);
589 
590     if (ret != NXT_OK) {
591         return ret;
592     }
593 
594     nxt_conf_get_string(type_value, &type);
595 
596     thread = nxt_thread();
597 
598     lang = nxt_app_lang_module(thread->runtime, &type);
599     if (lang == NULL) {
600         return nxt_conf_vldt_error(vldt,
601                                    "The module to run \"%V\" is not found "
602                                    "among the available application modules.",
603                                    &type);
604     }
605 
606     return nxt_conf_vldt_object(vldt, value, members[lang->type]);
607 }
608 
609 
610 static nxt_int_t
611 nxt_conf_vldt_object(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
612     void *data)
613 {
614     uint32_t                index;
615     nxt_int_t               ret;
616     nxt_str_t               name;
617     nxt_conf_value_t        *member;
618     nxt_conf_vldt_object_t  *vals;
619 
620     index = 0;
621 
622     for ( ;; ) {
623         member = nxt_conf_next_object_member(value, &name, &index);
624 
625         if (member == NULL) {
626             return NXT_OK;
627         }
628 
629         vals = data;
630 
631         for ( ;; ) {
632             if (vals->name.length == 0) {
633 
634                 if (vals->data != NULL) {
635                     vals = vals->data;
636                     continue;
637                 }
638 
639                 return nxt_conf_vldt_error(vldt, "Unknown parameter \"%V\".",
640                                            &name);
641             }
642 
643             if (!nxt_strstr_eq(&vals->name, &name)) {
644                 vals++;
645                 continue;
646             }
647 
648             ret = nxt_conf_vldt_type(vldt, &name, member, vals->type);
649 
650             if (ret != NXT_OK) {
651                 return ret;
652             }
653 
654             if (vals->validator != NULL) {
655                 ret = vals->validator(vldt, member, vals->data);
656 
657                 if (ret != NXT_OK) {
658                     return ret;
659                 }
660             }
661 
662             break;
663         }
664     }
665 }
666 
667 
668 typedef struct {
669     int64_t  spare;
670     int64_t  max;
671     int64_t  idle_timeout;
672 } nxt_conf_vldt_processes_conf_t;
673 
674 
675 static nxt_conf_map_t  nxt_conf_vldt_processes_conf_map[] = {
676     {
677         nxt_string("spare"),
678         NXT_CONF_MAP_INT64,
679         offsetof(nxt_conf_vldt_processes_conf_t, spare),
680     },
681 
682     {
683         nxt_string("max"),
684         NXT_CONF_MAP_INT64,
685         offsetof(nxt_conf_vldt_processes_conf_t, max),
686     },
687 
688     {
689         nxt_string("idle_timeout"),
690         NXT_CONF_MAP_INT64,
691         offsetof(nxt_conf_vldt_processes_conf_t, idle_timeout),
692     },
693 };
694 
695 
696 static nxt_int_t
697 nxt_conf_vldt_processes(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
698     void *data)
699 {
700     int64_t                         int_value;
701     nxt_int_t                       ret;
702     nxt_conf_vldt_processes_conf_t  proc;
703 
704     if (nxt_conf_type(value) == NXT_CONF_INTEGER) {
705         int_value = nxt_conf_get_integer(value);
706 
707         if (int_value < 1) {
708             return nxt_conf_vldt_error(vldt, "The \"processes\" number must be "
709                                        "equal to or greater than 1.");
710         }
711 
712         if (int_value > NXT_INT32_T_MAX) {
713             return nxt_conf_vldt_error(vldt, "The \"processes\" number must "
714                                        "not exceed %d.", NXT_INT32_T_MAX);
715         }
716 
717         return NXT_OK;
718     }
719 
720     ret = nxt_conf_vldt_object(vldt, value, data);
721     if (ret != NXT_OK) {
722         return ret;
723     }
724 
725     proc.spare = 0;
726     proc.max = 1;
727     proc.idle_timeout = 15;
728 
729     ret = nxt_conf_map_object(vldt->pool, value,
730                               nxt_conf_vldt_processes_conf_map,
731                               nxt_nitems(nxt_conf_vldt_processes_conf_map),
732                               &proc);
733     if (ret != NXT_OK) {
734         return ret;
735     }
736 
737     if (proc.spare < 0) {
738         return nxt_conf_vldt_error(vldt, "The \"spare\" number must not be "
739                                    "negative.");
740     }
741 
742     if (proc.spare > NXT_INT32_T_MAX) {
743         return nxt_conf_vldt_error(vldt, "The \"spare\" number must not "
744                                    "exceed %d.", NXT_INT32_T_MAX);
745     }
746 
747     if (proc.max < 1) {
748         return nxt_conf_vldt_error(vldt, "The \"max\" number must be equal "
749                                    "to or greater than 1.");
750     }
751 
752     if (proc.max > NXT_INT32_T_MAX) {
753         return nxt_conf_vldt_error(vldt, "The \"max\" number must not "
754                                    "exceed %d.", NXT_INT32_T_MAX);
755     }
756 
757     if (proc.max < proc.spare) {
758         return nxt_conf_vldt_error(vldt, "The \"spare\" number must be "
759                                    "less than or equal to \"max\".");
760     }
761 
762     if (proc.idle_timeout < 0) {
763         return nxt_conf_vldt_error(vldt, "The \"idle_timeout\" number must not "
764                                    "be negative.");
765     }
766 
767     if (proc.idle_timeout > NXT_INT32_T_MAX / 1000) {
768         return nxt_conf_vldt_error(vldt, "The \"idle_timeout\" number must not "
769                                    "exceed %d.", NXT_INT32_T_MAX / 1000);
770     }
771 
772     return NXT_OK;
773 }
774 
775 
776 static nxt_int_t
777 nxt_conf_vldt_object_iterator(nxt_conf_validation_t *vldt,
778     nxt_conf_value_t *value, void *data)
779 {
780     uint32_t                index;
781     nxt_int_t               ret;
782     nxt_str_t               name;
783     nxt_conf_value_t        *member;
784     nxt_conf_vldt_member_t  validator;
785 
786     validator = (nxt_conf_vldt_member_t) data;
787     index = 0;
788 
789     for ( ;; ) {
790         member = nxt_conf_next_object_member(value, &name, &index);
791 
792         if (member == NULL) {
793             return NXT_OK;
794         }
795 
796         ret = validator(vldt, &name, member);
797 
798         if (ret != NXT_OK) {
799             return ret;
800         }
801     }
802 }
803 
804 
805 static nxt_int_t
806 nxt_conf_vldt_array_iterator(nxt_conf_validation_t *vldt,
807     nxt_conf_value_t *value, void *data)
808 {
809     uint32_t                 index;
810     nxt_int_t                ret;
811     nxt_conf_value_t         *element;
812     nxt_conf_vldt_element_t  validator;
813 
814     validator = (nxt_conf_vldt_element_t) data;
815 
816     for (index = 0; /* void */ ; index++) {
817         element = nxt_conf_get_array_element(value, index);
818 
819         if (element == NULL) {
820             return NXT_OK;
821         }
822 
823         ret = validator(vldt, element);
824 
825         if (ret != NXT_OK) {
826             return ret;
827         }
828     }
829 }
830 
831 
832 static nxt_int_t
833 nxt_conf_vldt_system(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
834     void *data)
835 {
836     size_t                  length;
837     nxt_str_t               name;
838     nxt_conf_vldt_system_t  validator;
839     char                    string[32];
840 
841     /* The cast is required by Sun C. */
842     validator = (nxt_conf_vldt_system_t) data;
843 
844     nxt_conf_get_string(value, &name);
845 
846     length = name.length + 1;
847     length = nxt_min(length, sizeof(string));
848 
849     nxt_cpystrn((u_char *) string, name.start, length);
850 
851     return validator(vldt, string);
852 }
853 
854 
855 static nxt_int_t
856 nxt_conf_vldt_user(nxt_conf_validation_t *vldt, char *user)
857 {
858     struct passwd  *pwd;
859 
860     nxt_errno = 0;
861 
862     pwd = getpwnam(user);
863 
864     if (pwd != NULL) {
865         return NXT_OK;
866     }
867 
868     if (nxt_errno == 0) {
869         return nxt_conf_vldt_error(vldt, "User \"%s\" is not found.", user);
870     }
871 
872     return NXT_ERROR;
873 }
874 
875 
876 static nxt_int_t
877 nxt_conf_vldt_group(nxt_conf_validation_t *vldt, char *group)
878 {
879     struct group  *grp;
880 
881     nxt_errno = 0;
882 
883     grp = getgrnam(group);
884 
885     if (grp != NULL) {
886         return NXT_OK;
887     }
888 
889     if (nxt_errno == 0) {
890         return nxt_conf_vldt_error(vldt, "Group \"%s\" is not found.", group);
891     }
892 
893     return NXT_ERROR;
894 }
895 
896 
897 static nxt_int_t
898 nxt_conf_vldt_environment(nxt_conf_validation_t *vldt, nxt_str_t *name,
899     nxt_conf_value_t *value)
900 {
901     nxt_str_t  str;
902 
903     if (name->length == 0) {
904         return nxt_conf_vldt_error(vldt,
905                                    "The environment name must not be empty.");
906     }
907 
908     if (nxt_memchr(name->start, '\0', name->length) != NULL) {
909         return nxt_conf_vldt_error(vldt, "The environment name must not "
910                                    "contain null character.");
911     }
912 
913     if (nxt_memchr(name->start, '=', name->length) != NULL) {
914         return nxt_conf_vldt_error(vldt, "The environment name must not "
915                                    "contain '=' character.");
916     }
917 
918     if (nxt_conf_type(value) != NXT_CONF_STRING) {
919         return nxt_conf_vldt_error(vldt, "The \"%V\" environment value must be "
920                                    "a string.", name);
921     }
922 
923     nxt_conf_get_string(value, &str);
924 
925     if (nxt_memchr(str.start, '\0', str.length) != NULL) {
926         return nxt_conf_vldt_error(vldt, "The \"%V\" environment value must "
927                                    "not contain null character.", name);
928     }
929 
930     return NXT_OK;
931 }
932 
933 
934 static nxt_int_t
935 nxt_conf_vldt_argument(nxt_conf_validation_t *vldt, nxt_conf_value_t *value)
936 {
937     nxt_str_t  str;
938 
939     if (nxt_conf_type(value) != NXT_CONF_STRING) {
940         return nxt_conf_vldt_error(vldt, "The \"arguments\" array "
941                                    "must contain only string values.");
942     }
943 
944     nxt_conf_get_string(value, &str);
945 
946     if (nxt_memchr(str.start, '\0', str.length) != NULL) {
947         return nxt_conf_vldt_error(vldt, "The \"arguments\" array must not "
948                                    "contain strings with null character.");
949     }
950 
951     return NXT_OK;
952 }
953 
954 
955 static nxt_int_t
956 nxt_conf_vldt_php_option(nxt_conf_validation_t *vldt, nxt_str_t *name,
957     nxt_conf_value_t *value)
958 {
959     if (name->length == 0) {
960         return nxt_conf_vldt_error(vldt,
961                                    "The PHP option name must not be empty.");
962     }
963 
964     if (nxt_conf_type(value) != NXT_CONF_STRING) {
965         return nxt_conf_vldt_error(vldt, "The \"%V\" PHP option must be "
966                                    "a string.", name);
967     }
968 
969     return NXT_OK;
970 }
971