lib/param: Put common FN_ macros into param_functions.c
[kai/samba.git] / lib / param / loadparm.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Parameter loading functions
4    Copyright (C) Karl Auer 1993-1998
5
6    Largely re-written by Andrew Tridgell, September 1994
7
8    Copyright (C) Simo Sorce 2001
9    Copyright (C) Alexander Bokovoy 2002
10    Copyright (C) Stefan (metze) Metzmacher 2002
11    Copyright (C) Jim McDonough (jmcd@us.ibm.com)  2003.
12    Copyright (C) James Myers 2003 <myersjj@samba.org>
13    Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007
14
15    This program is free software; you can redistribute it and/or modify
16    it under the terms of the GNU General Public License as published by
17    the Free Software Foundation; either version 3 of the License, or
18    (at your option) any later version.
19
20    This program is distributed in the hope that it will be useful,
21    but WITHOUT ANY WARRANTY; without even the implied warranty of
22    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23    GNU General Public License for more details.
24
25    You should have received a copy of the GNU General Public License
26    along with this program.  If not, see <http://www.gnu.org/licenses/>.
27 */
28
29 /*
30  *  Load parameters.
31  *
32  *  This module provides suitable callback functions for the params
33  *  module. It builds the internal table of service details which is
34  *  then used by the rest of the server.
35  *
36  * To add a parameter:
37  *
38  * 1) add it to the global or service structure definition
39  * 2) add it to the parm_table
40  * 3) add it to the list of available functions (eg: using FN_GLOBAL_STRING())
41  * 4) If it's a global then initialise it in init_globals. If a local
42  *    (ie. service) parameter then initialise it in the sDefault structure
43  *
44  *
45  * Notes:
46  *   The configuration file is processed sequentially for speed. It is NOT
47  *   accessed randomly as happens in 'real' Windows. For this reason, there
48  *   is a fair bit of sequence-dependent code here - ie., code which assumes
49  *   that certain things happen before others. In particular, the code which
50  *   happens at the boundary between sections is delicately poised, so be
51  *   careful!
52  *
53  */
54
55 #include "includes.h"
56 #include "version.h"
57 #include "dynconfig/dynconfig.h"
58 #include "system/time.h"
59 #include "system/locale.h"
60 #include "system/network.h" /* needed for TCP_NODELAY */
61 #include "../lib/util/dlinklist.h"
62 #include "lib/param/param.h"
63 #include "lib/param/loadparm.h"
64 #include "auth/gensec/gensec.h"
65 #include "s3_param.h"
66 #include "lib/util/bitmap.h"
67 #include "libcli/smb/smb_constants.h"
68 #include "source4/dns_server/dns_update.h"
69
70 #define standard_sub_basic talloc_strdup
71
72 static bool do_parameter(const char *, const char *, void *);
73 static bool defaults_saved = false;
74
75 #define LOADPARM_EXTRA_GLOBALS \
76         struct parmlist_entry *param_opt;                               \
77         char *szRealm;                                                  \
78         char *tls_keyfile;                                              \
79         char *tls_certfile;                                             \
80         char *tls_cafile;                                               \
81         char *tls_crlfile;                                              \
82         char *tls_dhpfile;                                              \
83         char *loglevel;                                                 \
84         char *panic_action;                                             \
85         int server_role;                                                \
86         int security;                                                   \
87         int domain_master;                                              \
88         int domain_logons;                                              \
89         int bPreferredMaster;
90
91 #include "param_global.h"
92
93 #define NUMPARAMETERS (sizeof(parm_table) / sizeof(struct parm_struct))
94
95
96 /* prototypes for the special type handlers */
97 static bool handle_include(struct loadparm_context *lp_ctx, int unused,
98                            const char *pszParmValue, char **ptr);
99 static bool handle_realm(struct loadparm_context *lp_ctx, int unused,
100                          const char *pszParmValue, char **ptr);
101 static bool handle_copy(struct loadparm_context *lp_ctx, int unused,
102                         const char *pszParmValue, char **ptr);
103 static bool handle_debuglevel(struct loadparm_context *lp_ctx, int unused,
104                               const char *pszParmValue, char **ptr);
105 static bool handle_logfile(struct loadparm_context *lp_ctx, int unused,
106                            const char *pszParmValue, char **ptr);
107
108 #include "param_enums.c"
109
110 #define GLOBAL_VAR(name) offsetof(struct loadparm_global, name)
111 #define LOCAL_VAR(name) offsetof(struct loadparm_service, name)
112
113 static struct parm_struct parm_table[] = {
114         {
115                 .label          = "server role",
116                 .type           = P_ENUM,
117                 .p_class        = P_GLOBAL,
118                 .offset         = GLOBAL_VAR(server_role),
119                 .special        = NULL,
120                 .enum_list      = enum_server_role
121         },
122         {
123                 .label          = "domain logons",
124                 .type           = P_ENUM,
125                 .p_class        = P_GLOBAL,
126                 .offset         = GLOBAL_VAR(domain_logons),
127                 .special        = NULL,
128                 .enum_list      = enum_bool_auto
129         },
130         {
131                 .label          = "domain master",
132                 .type           = P_ENUM,
133                 .p_class        = P_GLOBAL,
134                 .offset         = GLOBAL_VAR(domain_master),
135                 .special        = NULL,
136                 .enum_list      = enum_bool_auto
137         },
138         {
139                 .label          = "dos charset",
140                 .type           = P_STRING,
141                 .p_class        = P_GLOBAL,
142                 .offset         = GLOBAL_VAR(dos_charset),
143                 .special        = NULL,
144                 .enum_list      = NULL
145         },
146         {
147                 .label          = "unix charset",
148                 .type           = P_STRING,
149                 .p_class        = P_GLOBAL,
150                 .offset         = GLOBAL_VAR(unix_charset),
151                 .special        = NULL,
152                 .enum_list      = NULL
153         },
154         {
155                 .label          = "ncalrpc dir",
156                 .type           = P_STRING,
157                 .p_class        = P_GLOBAL,
158                 .offset         = GLOBAL_VAR(ncalrpc_dir),
159                 .special        = NULL,
160                 .enum_list      = NULL
161         },
162         {
163                 .label          = "comment",
164                 .type           = P_STRING,
165                 .p_class        = P_LOCAL,
166                 .offset         = LOCAL_VAR(comment),
167                 .special        = NULL,
168                 .enum_list      = NULL,
169                 .flags          = FLAG_BASIC | FLAG_ADVANCED | FLAG_SHARE | FLAG_PRINT
170         },
171         {
172                 .label          = "path",
173                 .type           = P_STRING,
174                 .p_class        = P_LOCAL,
175                 .offset         = LOCAL_VAR(szPath),
176                 .special        = NULL,
177                 .enum_list      = NULL,
178                 .flags          = FLAG_BASIC | FLAG_ADVANCED | FLAG_SHARE | FLAG_PRINT,
179         },
180         {
181                 .label          = "directory",
182                 .type           = P_STRING,
183                 .p_class        = P_LOCAL,
184                 .offset         = LOCAL_VAR(szPath),
185                 .special        = NULL,
186                 .enum_list      = NULL,
187                 .flags          = FLAG_HIDE,
188         },
189         {
190                 .label          = "workgroup",
191                 .type           = P_USTRING,
192                 .p_class        = P_GLOBAL,
193                 .offset         = GLOBAL_VAR(szWorkgroup),
194                 .special        = NULL,
195                 .enum_list      = NULL,
196                 .flags          = FLAG_BASIC | FLAG_ADVANCED | FLAG_WIZARD,
197         },
198         {
199                 .label          = "realm",
200                 .type           = P_STRING,
201                 .p_class        = P_GLOBAL,
202                 .offset         = GLOBAL_VAR(szRealm),
203                 .special        = handle_realm,
204                 .enum_list      = NULL,
205                 .flags          = FLAG_BASIC | FLAG_ADVANCED | FLAG_WIZARD,
206         },
207         {
208                 .label          = "netbios name",
209                 .type           = P_USTRING,
210                 .p_class        = P_GLOBAL,
211                 .offset         = GLOBAL_VAR(szNetbiosName),
212                 .special        = NULL,
213                 .enum_list      = NULL,
214                 .flags          = FLAG_BASIC | FLAG_ADVANCED | FLAG_WIZARD,
215         },
216         {
217                 .label          = "netbios aliases",
218                 .type           = P_LIST,
219                 .p_class        = P_GLOBAL,
220                 .offset         = GLOBAL_VAR(szNetbiosAliases),
221                 .special        = NULL,
222                 .enum_list      = NULL
223         },
224         {
225                 .label          = "netbios scope",
226                 .type           = P_USTRING,
227                 .p_class        = P_GLOBAL,
228                 .offset         = GLOBAL_VAR(szNetbiosScope),
229                 .special        = NULL,
230                 .enum_list      = NULL,
231                 .flags          = FLAG_ADVANCED,
232         },
233         {
234                 .label          = "server string",
235                 .type           = P_STRING,
236                 .p_class        = P_GLOBAL,
237                 .offset         = GLOBAL_VAR(szServerString),
238                 .special        = NULL,
239                 .enum_list      = NULL,
240                 .flags          = FLAG_BASIC | FLAG_ADVANCED,
241         },
242         {
243                 .label          = "interfaces",
244                 .type           = P_LIST,
245                 .p_class        = P_GLOBAL,
246                 .offset         = GLOBAL_VAR(szInterfaces),
247                 .special        = NULL,
248                 .enum_list      = NULL,
249                 .flags          = FLAG_BASIC | FLAG_ADVANCED | FLAG_WIZARD,
250         },
251         {
252                 .label          = "bind interfaces only",
253                 .type           = P_BOOL,
254                 .p_class        = P_GLOBAL,
255                 .offset         = GLOBAL_VAR(bBindInterfacesOnly),
256                 .special        = NULL,
257                 .enum_list      = NULL,
258                 .flags          = FLAG_ADVANCED | FLAG_WIZARD,
259         },
260         {
261                 .label          = "ntvfs handler",
262                 .type           = P_LIST,
263                 .p_class        = P_LOCAL,
264                 .offset         = LOCAL_VAR(ntvfs_handler),
265                 .special        = NULL,
266                 .enum_list      = NULL
267         },
268         {
269                 .label          = "ntptr providor",
270                 .type           = P_STRING,
271                 .p_class        = P_GLOBAL,
272                 .offset         = GLOBAL_VAR(ntptr_providor),
273                 .special        = NULL,
274                 .enum_list      = NULL
275         },
276         {
277                 .label          = "passdb backend",
278                 .type           = P_STRING,
279                 .p_class        = P_GLOBAL,
280                 .offset         = GLOBAL_VAR(passdb_backend),
281                 .special        = NULL,
282                 .enum_list      = NULL
283         },
284         {
285                 .label          = "dcerpc endpoint servers",
286                 .type           = P_LIST,
287                 .p_class        = P_GLOBAL,
288                 .offset         = GLOBAL_VAR(dcerpc_ep_servers),
289                 .special        = NULL,
290                 .enum_list      = NULL
291         },
292         {
293                 .label          = "server services",
294                 .type           = P_LIST,
295                 .p_class        = P_GLOBAL,
296                 .offset         = GLOBAL_VAR(server_services),
297                 .special        = NULL,
298                 .enum_list      = NULL
299         },
300
301         {
302                 .label          = "security",
303                 .type           = P_ENUM,
304                 .p_class        = P_GLOBAL,
305                 .offset         = GLOBAL_VAR(security),
306                 .special        = NULL,
307                 .enum_list      = enum_security
308         },
309         {
310                 .label          = "encrypt passwords",
311                 .type           = P_BOOL,
312                 .p_class        = P_GLOBAL,
313                 .offset         = GLOBAL_VAR(bEncryptPasswords),
314                 .special        = NULL,
315                 .enum_list      = NULL
316         },
317         {
318                 .label          = "null passwords",
319                 .type           = P_BOOL,
320                 .p_class        = P_GLOBAL,
321                 .offset         = GLOBAL_VAR(bNullPasswords),
322                 .special        = NULL,
323                 .enum_list      = NULL,
324                 .flags          = FLAG_ADVANCED | FLAG_DEPRECATED,
325         },
326         {
327                 .label          = "obey pam restrictions",
328                 .type           = P_BOOL,
329                 .p_class        = P_GLOBAL,
330                 .offset         = GLOBAL_VAR(bObeyPamRestrictions),
331                 .special        = NULL,
332                 .enum_list      = NULL,
333                 .flags          = FLAG_ADVANCED,
334         },
335         {
336                 .label          = "password server",
337                 .type           = P_STRING,
338                 .p_class        = P_GLOBAL,
339                 .offset         = GLOBAL_VAR(szPasswordServer),
340                 .special        = NULL,
341                 .enum_list      = NULL
342         },
343         {
344                 .label          = "private dir",
345                 .type           = P_STRING,
346                 .p_class        = P_GLOBAL,
347                 .offset         = GLOBAL_VAR(szPrivateDir),
348                 .special        = NULL,
349                 .enum_list      = NULL
350         },
351         {
352                 .label          = "passwd chat",
353                 .type           = P_STRING,
354                 .p_class        = P_GLOBAL,
355                 .offset         = GLOBAL_VAR(szPasswdChat),
356                 .special        = NULL,
357                 .enum_list      = NULL
358         },
359         {
360                 .label          = "password level",
361                 .type           = P_INTEGER,
362                 .p_class        = P_GLOBAL,
363                 .offset         = GLOBAL_VAR(pwordlevel),
364                 .special        = NULL,
365                 .enum_list      = NULL
366         },
367         {
368                 .label          = "lanman auth",
369                 .type           = P_BOOL,
370                 .p_class        = P_GLOBAL,
371                 .offset         = GLOBAL_VAR(bLanmanAuth),
372                 .special        = NULL,
373                 .enum_list      = NULL,
374                 .flags          = FLAG_ADVANCED,
375         },
376         {
377                 .label          = "ntlm auth",
378                 .type           = P_BOOL,
379                 .p_class        = P_GLOBAL,
380                 .offset         = GLOBAL_VAR(bNTLMAuth),
381                 .special        = NULL,
382                 .enum_list      = NULL,
383                 .flags          = FLAG_ADVANCED,
384         },
385         {
386                 .label          = "client NTLMv2 auth",
387                 .type           = P_BOOL,
388                 .p_class        = P_GLOBAL,
389                 .offset         = GLOBAL_VAR(bClientNTLMv2Auth),
390                 .special        = NULL,
391                 .enum_list      = NULL,
392                 .flags          = FLAG_ADVANCED,
393         },
394         {
395                 .label          = "client lanman auth",
396                 .type           = P_BOOL,
397                 .p_class        = P_GLOBAL,
398                 .offset         = GLOBAL_VAR(bClientLanManAuth),
399                 .special        = NULL,
400                 .enum_list      = NULL,
401                 .flags          = FLAG_ADVANCED,
402         },
403         {
404                 .label          = "client plaintext auth",
405                 .type           = P_BOOL,
406                 .p_class        = P_GLOBAL,
407                 .offset         = GLOBAL_VAR(bClientPlaintextAuth),
408                 .special        = NULL,
409                 .enum_list      = NULL,
410                 .flags          = FLAG_ADVANCED,
411         },
412         {
413                 .label          = "client use spnego principal",
414                 .type           = P_BOOL,
415                 .p_class        = P_GLOBAL,
416                 .offset         = GLOBAL_VAR(client_use_spnego_principal),
417                 .special        = NULL,
418                 .enum_list      = NULL
419         },
420
421         {
422                 .label          = "read only",
423                 .type           = P_BOOL,
424                 .p_class        = P_LOCAL,
425                 .offset         = LOCAL_VAR(bRead_only),
426                 .special        = NULL,
427                 .enum_list      = NULL
428         },
429
430         {
431                 .label          = "create mask",
432                 .type           = P_OCTAL,
433                 .p_class        = P_LOCAL,
434                 .offset         = LOCAL_VAR(iCreate_mask),
435                 .special        = NULL,
436                 .enum_list      = NULL
437         },
438         {
439                 .label          = "force create mode",
440                 .type           = P_OCTAL,
441                 .p_class        = P_LOCAL,
442                 .offset         = LOCAL_VAR(iCreate_force_mode),
443                 .special        = NULL,
444                 .enum_list      = NULL
445         },
446         {
447                 .label          = "directory mask",
448                 .type           = P_OCTAL,
449                 .p_class        = P_LOCAL,
450                 .offset         = LOCAL_VAR(iDir_mask),
451                 .special        = NULL,
452                 .enum_list      = NULL
453         },
454         {
455                 .label          = "force directory mode",
456                 .type           = P_OCTAL,
457                 .p_class        = P_LOCAL,
458                 .offset         = LOCAL_VAR(iDir_force_mode),
459                 .special        = NULL,
460                 .enum_list      = NULL
461         },
462
463         {
464                 .label          = "hosts allow",
465                 .type           = P_LIST,
466                 .p_class        = P_LOCAL,
467                 .offset         = LOCAL_VAR(szHostsallow),
468                 .special        = NULL,
469                 .enum_list      = NULL
470         },
471         {
472                 .label          = "hosts deny",
473                 .type           = P_LIST,
474                 .p_class        = P_LOCAL,
475                 .offset         = LOCAL_VAR(szHostsdeny),
476                 .special        = NULL,
477                 .enum_list      = NULL
478         },
479
480         {
481                 .label          = "log level",
482                 .type           = P_STRING,
483                 .p_class        = P_GLOBAL,
484                 .offset         = GLOBAL_VAR(loglevel),
485                 .special        = handle_debuglevel,
486                 .enum_list      = NULL
487         },
488         {
489                 .label          = "debuglevel",
490                 .type           = P_STRING,
491                 .p_class        = P_GLOBAL,
492                 .offset         = GLOBAL_VAR(loglevel),
493                 .special        = handle_debuglevel,
494                 .enum_list      = NULL
495         },
496         {
497                 .label          = "log file",
498                 .type           = P_STRING,
499                 .p_class        = P_GLOBAL,
500                 .offset         = GLOBAL_VAR(logfile),
501                 .special        = handle_logfile,
502                 .enum_list      = NULL,
503                 .flags          = FLAG_ADVANCED,
504         },
505
506         {
507                 .label          = "smb ports",
508                 .type           = P_LIST,
509                 .p_class        = P_GLOBAL,
510                 .offset         = GLOBAL_VAR(smb_ports),
511                 .special        = NULL,
512                 .enum_list      = NULL
513         },
514         {
515                 .label          = "nbt port",
516                 .type           = P_INTEGER,
517                 .p_class        = P_GLOBAL,
518                 .offset         = GLOBAL_VAR(nbt_port),
519                 .special        = NULL,
520                 .enum_list      = NULL
521         },
522         {
523                 .label          = "dgram port",
524                 .type           = P_INTEGER,
525                 .p_class        = P_GLOBAL,
526                 .offset         = GLOBAL_VAR(dgram_port),
527                 .special        = NULL,
528                 .enum_list      = NULL
529         },
530         {
531                 .label          = "cldap port",
532                 .type           = P_INTEGER,
533                 .p_class        = P_GLOBAL,
534                 .offset         = GLOBAL_VAR(cldap_port),
535                 .special        = NULL,
536                 .enum_list      = NULL
537         },
538         {
539                 .label          = "krb5 port",
540                 .type           = P_INTEGER,
541                 .p_class        = P_GLOBAL,
542                 .offset         = GLOBAL_VAR(krb5_port),
543                 .special        = NULL,
544                 .enum_list      = NULL
545         },
546         {
547                 .label          = "kpasswd port",
548                 .type           = P_INTEGER,
549                 .p_class        = P_GLOBAL,
550                 .offset         = GLOBAL_VAR(kpasswd_port),
551                 .special        = NULL,
552                 .enum_list      = NULL
553         },
554         {
555                 .label          = "web port",
556                 .type           = P_INTEGER,
557                 .p_class        = P_GLOBAL,
558                 .offset         = GLOBAL_VAR(web_port),
559                 .special        = NULL,
560                 .enum_list      = NULL
561         },
562         {
563                 .label          = "tls enabled",
564                 .type           = P_BOOL,
565                 .p_class        = P_GLOBAL,
566                 .offset         = GLOBAL_VAR(tls_enabled),
567                 .special        = NULL,
568                 .enum_list      = NULL
569         },
570         {
571                 .label          = "tls keyfile",
572                 .type           = P_STRING,
573                 .p_class        = P_GLOBAL,
574                 .offset         = GLOBAL_VAR(tls_keyfile),
575                 .special        = NULL,
576                 .enum_list      = NULL
577         },
578         {
579                 .label          = "tls certfile",
580                 .type           = P_STRING,
581                 .p_class        = P_GLOBAL,
582                 .offset         = GLOBAL_VAR(tls_certfile),
583                 .special        = NULL,
584                 .enum_list      = NULL
585         },
586         {
587                 .label          = "tls cafile",
588                 .type           = P_STRING,
589                 .p_class        = P_GLOBAL,
590                 .offset         = GLOBAL_VAR(tls_cafile),
591                 .special        = NULL,
592                 .enum_list      = NULL
593         },
594         {
595                 .label          = "tls crlfile",
596                 .type           = P_STRING,
597                 .p_class        = P_GLOBAL,
598                 .offset         = GLOBAL_VAR(tls_crlfile),
599                 .special        = NULL,
600                 .enum_list      = NULL
601         },
602         {
603                 .label          = "tls dh params file",
604                 .type           = P_STRING,
605                 .p_class        = P_GLOBAL,
606                 .offset         = GLOBAL_VAR(tls_dhpfile),
607                 .special        = NULL,
608                 .enum_list      = NULL
609         },
610         {
611                 .label          = "large readwrite",
612                 .type           = P_BOOL,
613                 .p_class        = P_GLOBAL,
614                 .offset         = GLOBAL_VAR(bLargeReadwrite),
615                 .special        = NULL,
616                 .enum_list      = NULL,
617                 .flags          = FLAG_ADVANCED,
618         },
619         {
620                 .label          = "server max protocol",
621                 .type           = P_ENUM,
622                 .p_class        = P_GLOBAL,
623                 .offset         = GLOBAL_VAR(srv_maxprotocol),
624                 .special        = NULL,
625                 .enum_list      = enum_protocol,
626                 .flags          = FLAG_ADVANCED,
627         },
628         {
629                 .label          = "max protocol",
630                 .type           = P_ENUM,
631                 .p_class        = P_GLOBAL,
632                 .offset         = GLOBAL_VAR(srv_maxprotocol),
633                 .special        = NULL,
634                 .enum_list      = enum_protocol,
635                 .flags          = FLAG_ADVANCED,
636         },
637         {
638                 .label          = "protocol",
639                 .type           = P_ENUM,
640                 .p_class        = P_GLOBAL,
641                 .offset         = GLOBAL_VAR(srv_maxprotocol),
642                 .special        = NULL,
643                 .enum_list      = enum_protocol,
644                 .flags          = FLAG_ADVANCED,
645         },
646         {
647                 .label          = "server min protocol",
648                 .type           = P_ENUM,
649                 .p_class        = P_GLOBAL,
650                 .offset         = GLOBAL_VAR(srv_minprotocol),
651                 .special        = NULL,
652                 .enum_list      = enum_protocol,
653                 .flags          = FLAG_ADVANCED,
654         },
655         {
656                 .label          = "min protocol",
657                 .type           = P_ENUM,
658                 .p_class        = P_GLOBAL,
659                 .offset         = GLOBAL_VAR(srv_minprotocol),
660                 .special        = NULL,
661                 .enum_list      = enum_protocol,
662                 .flags          = FLAG_ADVANCED,
663         },
664         {
665                 .label          = "client max protocol",
666                 .type           = P_ENUM,
667                 .p_class        = P_GLOBAL,
668                 .offset         = GLOBAL_VAR(cli_maxprotocol),
669                 .special        = NULL,
670                 .enum_list      = enum_protocol
671         },
672         {
673                 .label          = "client min protocol",
674                 .type           = P_ENUM,
675                 .p_class        = P_GLOBAL,
676                 .offset         = GLOBAL_VAR(cli_minprotocol),
677                 .special        = NULL,
678                 .enum_list      = enum_protocol
679         },
680         {
681                 .label          = "unicode",
682                 .type           = P_BOOL,
683                 .p_class        = P_GLOBAL,
684                 .offset         = GLOBAL_VAR(bUnicode),
685                 .special        = NULL,
686                 .enum_list      = NULL
687         },
688         {
689                 .label          = "read raw",
690                 .type           = P_BOOL,
691                 .p_class        = P_GLOBAL,
692                 .offset         = GLOBAL_VAR(bReadRaw),
693                 .special        = NULL,
694                 .enum_list      = NULL
695         },
696         {
697                 .label          = "write raw",
698                 .type           = P_BOOL,
699                 .p_class        = P_GLOBAL,
700                 .offset         = GLOBAL_VAR(bWriteRaw),
701                 .special        = NULL,
702                 .enum_list      = NULL
703         },
704         {
705                 .label          = "disable netbios",
706                 .type           = P_BOOL,
707                 .p_class        = P_GLOBAL,
708                 .offset         = GLOBAL_VAR(bDisableNetbios),
709                 .special        = NULL,
710                 .enum_list      = NULL
711         },
712
713         {
714                 .label          = "nt status support",
715                 .type           = P_BOOL,
716                 .p_class        = P_GLOBAL,
717                 .offset         = GLOBAL_VAR(bNTStatusSupport),
718                 .special        = NULL,
719                 .enum_list      = NULL
720         },
721
722         {
723                 .label          = "max mux",
724                 .type           = P_INTEGER,
725                 .p_class        = P_GLOBAL,
726                 .offset         = GLOBAL_VAR(max_mux),
727                 .special        = NULL,
728                 .enum_list      = NULL,
729                 .flags          = FLAG_ADVANCED,
730         },
731         {
732                 .label          = "max xmit",
733                 .type           = P_BYTES,
734                 .p_class        = P_GLOBAL,
735                 .offset         = GLOBAL_VAR(max_xmit),
736                 .special        = NULL,
737                 .enum_list      = NULL,
738                 .flags          = FLAG_ADVANCED,
739         },
740
741         {
742                 .label          = "name resolve order",
743                 .type           = P_LIST,
744                 .p_class        = P_GLOBAL,
745                 .offset         = GLOBAL_VAR(szNameResolveOrder),
746                 .special        = NULL,
747                 .enum_list      = NULL
748         },
749         {
750                 .label          = "max wins ttl",
751                 .type           = P_INTEGER,
752                 .p_class        = P_GLOBAL,
753                 .offset         = GLOBAL_VAR(max_wins_ttl),
754                 .special        = NULL,
755                 .enum_list      = NULL,
756                 .flags          = FLAG_ADVANCED,
757         },
758         {
759                 .label          = "min wins ttl",
760                 .type           = P_INTEGER,
761                 .p_class        = P_GLOBAL,
762                 .offset         = GLOBAL_VAR(min_wins_ttl),
763                 .special        = NULL,
764                 .enum_list      = NULL,
765                 .flags          = FLAG_ADVANCED,
766         },
767         {
768                 .label          = "time server",
769                 .type           = P_BOOL,
770                 .p_class        = P_GLOBAL,
771                 .offset         = GLOBAL_VAR(bTimeServer),
772                 .special        = NULL,
773                 .enum_list      = NULL,
774                 .flags          = FLAG_ADVANCED,
775         },
776         {
777                 .label          = "unix extensions",
778                 .type           = P_BOOL,
779                 .p_class        = P_GLOBAL,
780                 .offset         = GLOBAL_VAR(bUnixExtensions),
781                 .special        = NULL,
782                 .enum_list      = NULL,
783                 .flags          = FLAG_ADVANCED,
784         },
785         {
786                 .label          = "use spnego",
787                 .type           = P_BOOL,
788                 .p_class        = P_GLOBAL,
789                 .offset         = GLOBAL_VAR(bUseSpnego),
790                 .special        = NULL,
791                 .enum_list      = NULL
792         },
793         {
794                 .label          = "server signing",
795                 .type           = P_ENUM,
796                 .p_class        = P_GLOBAL,
797                 .offset         = GLOBAL_VAR(server_signing),
798                 .special        = NULL,
799                 .enum_list      = enum_smb_signing_vals,
800                 .flags          = FLAG_ADVANCED,
801         },
802         {
803                 .label          = "client signing",
804                 .type           = P_ENUM,
805                 .p_class        = P_GLOBAL,
806                 .offset         = GLOBAL_VAR(client_signing),
807                 .special        = NULL,
808                 .enum_list      = enum_smb_signing_vals
809         },
810         {
811                 .label          = "rpc big endian",
812                 .type           = P_BOOL,
813                 .p_class        = P_GLOBAL,
814                 .offset         = GLOBAL_VAR(bRpcBigEndian),
815                 .special        = NULL,
816                 .enum_list      = NULL
817         },
818
819         {
820                 .label          = "max connections",
821                 .type           = P_INTEGER,
822                 .p_class        = P_LOCAL,
823                 .offset         = LOCAL_VAR(iMaxConnections),
824                 .special        = NULL,
825                 .enum_list      = NULL,
826                 .flags          = FLAG_ADVANCED | FLAG_SHARE,
827         },
828         {
829                 .label          = "paranoid server security",
830                 .type           = P_BOOL,
831                 .p_class        = P_GLOBAL,
832                 .offset         = GLOBAL_VAR(paranoid_server_security),
833                 .special        = NULL,
834                 .enum_list      = NULL
835         },
836         {
837                 .label          = "socket options",
838                 .type           = P_STRING,
839                 .p_class        = P_GLOBAL,
840                 .offset         = GLOBAL_VAR(socket_options),
841                 .special        = NULL,
842                 .enum_list      = NULL
843         },
844
845         {
846                 .label          = "strict sync",
847                 .type           = P_BOOL,
848                 .p_class        = P_LOCAL,
849                 .offset         = LOCAL_VAR(bStrictSync),
850                 .special        = NULL,
851                 .enum_list      = NULL
852         },
853         {
854                 .label          = "use mmap",
855                 .type           = P_BOOL,
856                 .p_class        = P_GLOBAL,
857                 .offset         = GLOBAL_VAR(bUseMmap),
858                 .special        = NULL,
859                 .enum_list      = NULL,
860                 .flags          = FLAG_ADVANCED,
861         },
862         {
863                 .label          = "case insensitive filesystem",
864                 .type           = P_BOOL,
865                 .p_class        = P_LOCAL,
866                 .offset         = LOCAL_VAR(bCIFileSystem),
867                 .special        = NULL,
868                 .enum_list      = NULL
869         },
870
871         {
872                 .label          = "max print jobs",
873                 .type           = P_INTEGER,
874                 .p_class        = P_LOCAL,
875                 .offset         = LOCAL_VAR(iMaxPrintJobs),
876                 .special        = NULL,
877                 .enum_list      = NULL
878         },
879         {
880                 .label          = "printable",
881                 .type           = P_BOOL,
882                 .p_class        = P_LOCAL,
883                 .offset         = LOCAL_VAR(bPrint_ok),
884                 .special        = NULL,
885                 .enum_list      = NULL
886         },
887         {
888                 .label          = "print ok",
889                 .type           = P_BOOL,
890                 .p_class        = P_LOCAL,
891                 .offset         = LOCAL_VAR(bPrint_ok),
892                 .special        = NULL,
893                 .enum_list      = NULL
894         },
895
896         {
897                 .label          = "printer name",
898                 .type           = P_STRING,
899                 .p_class        = P_LOCAL,
900                 .offset         = LOCAL_VAR(szPrintername),
901                 .special        = NULL,
902                 .enum_list      = NULL,
903                 .flags          = FLAG_ADVANCED | FLAG_PRINT,
904         },
905         {
906                 .label          = "printer",
907                 .type           = P_STRING,
908                 .p_class        = P_LOCAL,
909                 .offset         = LOCAL_VAR(szPrintername),
910                 .special        = NULL,
911                 .enum_list      = NULL,
912                 .flags          = FLAG_HIDE,
913         },
914
915         {
916                 .label          = "map system",
917                 .type           = P_BOOL,
918                 .p_class        = P_LOCAL,
919                 .offset         = LOCAL_VAR(bMap_system),
920                 .special        = NULL,
921                 .enum_list      = NULL
922         },
923         {
924                 .label          = "map hidden",
925                 .type           = P_BOOL,
926                 .p_class        = P_LOCAL,
927                 .offset         = LOCAL_VAR(bMap_hidden),
928                 .special        = NULL,
929                 .enum_list      = NULL
930         },
931         {
932                 .label          = "map archive",
933                 .type           = P_BOOL,
934                 .p_class        = P_LOCAL,
935                 .offset         = LOCAL_VAR(bMap_archive),
936                 .special        = NULL,
937                 .enum_list      = NULL
938         },
939
940         {
941                 .label          = "preferred master",
942                 .type           = P_ENUM,
943                 .p_class        = P_GLOBAL,
944                 .offset         = GLOBAL_VAR(bPreferredMaster),
945                 .special        = NULL,
946                 .enum_list      = enum_bool_auto,
947                 .flags          = FLAG_BASIC | FLAG_ADVANCED,
948         },
949         {
950                 .label          = "prefered master",
951                 .type           = P_ENUM,
952                 .p_class        = P_GLOBAL,
953                 .offset         = GLOBAL_VAR(bPreferredMaster),
954                 .special        = NULL,
955                 .enum_list      = enum_bool_auto,
956                 .flags          = FLAG_HIDE,
957         },
958         {
959                 .label          = "local master",
960                 .type           = P_BOOL,
961                 .p_class        = P_GLOBAL,
962                 .offset         = GLOBAL_VAR(bLocalMaster),
963                 .special        = NULL,
964                 .enum_list      = NULL
965         },
966         {
967                 .label          = "browseable",
968                 .type           = P_BOOL,
969                 .p_class        = P_LOCAL,
970                 .offset         = LOCAL_VAR(bBrowseable),
971                 .special        = NULL,
972                 .enum_list      = NULL,
973                 .flags          = FLAG_BASIC | FLAG_ADVANCED | FLAG_SHARE | FLAG_PRINT,
974         },
975         {
976                 .label          = "browsable",
977                 .type           = P_BOOL,
978                 .p_class        = P_LOCAL,
979                 .offset         = LOCAL_VAR(bBrowseable),
980                 .special        = NULL,
981                 .enum_list      = NULL
982         },
983
984         {
985                 .label          = "dns proxy",
986                 .type           = P_BOOL,
987                 .p_class        = P_GLOBAL,
988                 .offset         = GLOBAL_VAR(bWINSdnsProxy),
989                 .special        = NULL,
990                 .enum_list      = NULL
991         },
992         {
993                 .label          = "wins server",
994                 .type           = P_LIST,
995                 .p_class        = P_GLOBAL,
996                 .offset         = GLOBAL_VAR(szWINSservers),
997                 .special        = NULL,
998                 .enum_list      = NULL,
999                 .flags          = FLAG_BASIC | FLAG_ADVANCED | FLAG_WIZARD,
1000         },
1001         {
1002                 .label          = "wins support",
1003                 .type           = P_BOOL,
1004                 .p_class        = P_GLOBAL,
1005                 .offset         = GLOBAL_VAR(bWINSsupport),
1006                 .special        = NULL,
1007                 .enum_list      = NULL,
1008                 .flags          = FLAG_BASIC | FLAG_ADVANCED | FLAG_WIZARD,
1009         },
1010         {
1011                 .label          = "wins hook",
1012                 .type           = P_STRING,
1013                 .p_class        = P_GLOBAL,
1014                 .offset         = GLOBAL_VAR(szWINSHook),
1015                 .special        = NULL,
1016                 .enum_list      = NULL,
1017                 .flags          = FLAG_ADVANCED,
1018         },
1019
1020         {
1021                 .label          = "csc policy",
1022                 .type           = P_ENUM,
1023                 .p_class        = P_LOCAL,
1024                 .offset         = LOCAL_VAR(iCSCPolicy),
1025                 .special        = NULL,
1026                 .enum_list      = enum_csc_policy,
1027                 .flags          = FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL,
1028         },
1029
1030         {
1031                 .label          = "strict locking",
1032                 .type           = P_BOOL,
1033                 .p_class        = P_LOCAL,
1034                 .offset         = LOCAL_VAR(iStrictLocking),
1035                 .special        = NULL,
1036                 .enum_list      = NULL
1037         },
1038         {
1039                 .label          = "oplocks",
1040                 .type           = P_BOOL,
1041                 .p_class        = P_LOCAL,
1042                 .offset         = LOCAL_VAR(bOpLocks),
1043                 .special        = NULL,
1044                 .enum_list      = NULL
1045         },
1046
1047         {
1048                 .label          = "share backend",
1049                 .type           = P_STRING,
1050                 .p_class        = P_GLOBAL,
1051                 .offset         = GLOBAL_VAR(szShareBackend),
1052                 .special        = NULL,
1053                 .enum_list      = NULL
1054         },
1055         {
1056                 .label          = "preload",
1057                 .type           = P_STRING,
1058                 .p_class        = P_GLOBAL,
1059                 .offset         = GLOBAL_VAR(szAutoServices),
1060                 .special        = NULL,
1061                 .enum_list      = NULL,
1062                 .flags          = FLAG_ADVANCED,
1063         },
1064         {
1065                 .label          = "auto services",
1066                 .type           = P_STRING,
1067                 .p_class        = P_GLOBAL,
1068                 .offset         = GLOBAL_VAR(szAutoServices),
1069                 .special        = NULL,
1070                 .enum_list      = NULL,
1071                 .flags          = FLAG_ADVANCED,
1072         },
1073         {
1074                 .label          = "lock directory",
1075                 .type           = P_STRING,
1076                 .p_class        = P_GLOBAL,
1077                 .offset         = GLOBAL_VAR(szLockDir),
1078                 .special        = NULL,
1079                 .enum_list      = NULL,
1080                 .flags          = FLAG_ADVANCED,
1081         },
1082         {
1083                 .label          = "lock dir",
1084                 .type           = P_STRING,
1085                 .p_class        = P_GLOBAL,
1086                 .offset         = GLOBAL_VAR(szLockDir),
1087                 .special        = NULL,
1088                 .enum_list      = NULL,
1089                 .flags          = FLAG_HIDE,
1090         },
1091         {
1092                 .label          = "state directory",
1093                 .type           = P_STRING,
1094                 .p_class        = P_GLOBAL,
1095                 .offset         = GLOBAL_VAR(szStateDir),
1096                 .special        = NULL,
1097                 .enum_list      = NULL,
1098                 .flags          = FLAG_ADVANCED,
1099         },
1100         {
1101                 .label          = "cache directory",
1102                 .type           = P_STRING,
1103                 .p_class        = P_GLOBAL,
1104                 .offset         = GLOBAL_VAR(szCacheDir),
1105                 .special        = NULL,
1106                 .enum_list      = NULL,
1107                 .flags          = FLAG_ADVANCED,
1108         },
1109         {
1110                 .label          = "pid directory",
1111                 .type           = P_STRING,
1112                 .p_class        = P_GLOBAL,
1113                 .offset         = GLOBAL_VAR(szPidDir),
1114                 .special        = NULL,
1115                 .enum_list      = NULL
1116         },
1117
1118         {
1119                 .label          = "socket address",
1120                 .type           = P_STRING,
1121                 .p_class        = P_GLOBAL,
1122                 .offset         = GLOBAL_VAR(szSocketAddress),
1123                 .special        = NULL,
1124                 .enum_list      = NULL
1125         },
1126         {
1127                 .label          = "copy",
1128                 .type           = P_STRING,
1129                 .p_class        = P_LOCAL,
1130                 .offset         = LOCAL_VAR(szCopy),
1131                 .special        = handle_copy,
1132                 .enum_list      = NULL,
1133                 .flags          = FLAG_HIDE,
1134         },
1135         {
1136                 .label          = "include",
1137                 .type           = P_STRING,
1138                 .p_class        = P_LOCAL,
1139                 .offset         = LOCAL_VAR(szInclude),
1140                 .special        = handle_include,
1141                 .enum_list      = NULL
1142         },
1143
1144         {
1145                 .label          = "available",
1146                 .type           = P_BOOL,
1147                 .p_class        = P_LOCAL,
1148                 .offset         = LOCAL_VAR(bAvailable),
1149                 .special        = NULL,
1150                 .enum_list      = NULL
1151         },
1152         {
1153                 .label          = "volume",
1154                 .type           = P_STRING,
1155                 .p_class        = P_LOCAL,
1156                 .offset         = LOCAL_VAR(volume),
1157                 .special        = NULL,
1158                 .enum_list      = NULL,
1159                 .flags          = FLAG_ADVANCED | FLAG_SHARE,
1160         },
1161         {
1162                 .label          = "fstype",
1163                 .type           = P_STRING,
1164                 .p_class        = P_LOCAL,
1165                 .offset         = LOCAL_VAR(fstype),
1166                 .special        = NULL,
1167                 .enum_list      = NULL
1168         },
1169
1170         {
1171                 .label          = "panic action",
1172                 .type           = P_STRING,
1173                 .p_class        = P_GLOBAL,
1174                 .offset         = GLOBAL_VAR(panic_action),
1175                 .special        = NULL,
1176                 .enum_list      = NULL
1177         },
1178
1179         {
1180                 .label          = "msdfs root",
1181                 .type           = P_BOOL,
1182                 .p_class        = P_LOCAL,
1183                 .offset         = LOCAL_VAR(bMSDfsRoot),
1184                 .special        = NULL,
1185                 .enum_list      = NULL
1186         },
1187         {
1188                 .label          = "host msdfs",
1189                 .type           = P_BOOL,
1190                 .p_class        = P_GLOBAL,
1191                 .offset         = GLOBAL_VAR(bHostMSDfs),
1192                 .special        = NULL,
1193                 .enum_list      = NULL,
1194                 .flags          = FLAG_ADVANCED,
1195         },
1196         {
1197                 .label          = "winbind separator",
1198                 .type           = P_STRING,
1199                 .p_class        = P_GLOBAL,
1200                 .offset         = GLOBAL_VAR(szWinbindSeparator),
1201                 .special        = NULL,
1202                 .enum_list      = NULL
1203         },
1204         {
1205                 .label          = "winbindd socket directory",
1206                 .type           = P_STRING,
1207                 .p_class        = P_GLOBAL,
1208                 .offset         = GLOBAL_VAR(szWinbinddSocketDirectory),
1209                 .special        = NULL,
1210                 .enum_list      = NULL,
1211                 .flags          = FLAG_ADVANCED,
1212         },
1213         {
1214                 .label          = "winbindd privileged socket directory",
1215                 .type           = P_STRING,
1216                 .p_class        = P_GLOBAL,
1217                 .offset         = GLOBAL_VAR(szWinbinddPrivilegedSocketDirectory),
1218                 .special        = NULL,
1219                 .enum_list      = NULL,
1220                 .flags          = FLAG_ADVANCED,
1221         },
1222         {
1223                 .label          = "winbind sealed pipes",
1224                 .type           = P_BOOL,
1225                 .p_class        = P_GLOBAL,
1226                 .offset         = GLOBAL_VAR(bWinbindSealedPipes),
1227                 .special        = NULL,
1228                 .enum_list      = NULL,
1229                 .flags          = FLAG_ADVANCED,
1230         },
1231         {
1232                 .label          = "template shell",
1233                 .type           = P_STRING,
1234                 .p_class        = P_GLOBAL,
1235                 .offset         = GLOBAL_VAR(szTemplateShell),
1236                 .special        = NULL,
1237                 .enum_list      = NULL,
1238                 .flags          = FLAG_ADVANCED,
1239         },
1240         {
1241                 .label          = "template homedir",
1242                 .type           = P_STRING,
1243                 .p_class        = P_GLOBAL,
1244                 .offset         = GLOBAL_VAR(szTemplateHomedir),
1245                 .special        = NULL,
1246                 .enum_list      = NULL,
1247                 .flags          = FLAG_ADVANCED,
1248         },
1249         {
1250                 .label          = "idmap trusted only",
1251                 .type           = P_BOOL,
1252                 .p_class        = P_GLOBAL,
1253                 .offset         = GLOBAL_VAR(bIdmapTrustedOnly),
1254                 .special        = NULL,
1255                 .enum_list      = NULL,
1256                 .flags          = FLAG_ADVANCED,
1257         },
1258
1259         {
1260                 .label          = "ntp signd socket directory",
1261                 .type           = P_STRING,
1262                 .p_class        = P_GLOBAL,
1263                 .offset         = GLOBAL_VAR(szNTPSignDSocketDirectory),
1264                 .special        = NULL,
1265                 .enum_list      = NULL,
1266                 .flags          = FLAG_ADVANCED,
1267         },
1268         {
1269                 .label          = "rndc command",
1270                 .type           = P_CMDLIST,
1271                 .p_class        = P_GLOBAL,
1272                 .offset         = GLOBAL_VAR(szRNDCCommand),
1273                 .special        = NULL,
1274                 .enum_list      = NULL,
1275                 .flags          = FLAG_ADVANCED,
1276         },
1277         {
1278                 .label          = "dns update command",
1279                 .type           = P_CMDLIST,
1280                 .p_class        = P_GLOBAL,
1281                 .offset         = GLOBAL_VAR(szDNSUpdateCommand),
1282                 .special        = NULL,
1283                 .enum_list      = NULL,
1284                 .flags          = FLAG_ADVANCED,
1285         },
1286         {
1287                 .label          = "spn update command",
1288                 .type           = P_CMDLIST,
1289                 .p_class        = P_GLOBAL,
1290                 .offset         = GLOBAL_VAR(szSPNUpdateCommand),
1291                 .special        = NULL,
1292                 .enum_list      = NULL,
1293                 .flags          = FLAG_ADVANCED,
1294         },
1295         {
1296                 .label          = "samba kcc command",
1297                 .type           = P_CMDLIST,
1298                 .p_class        = P_GLOBAL,
1299                 .offset         = GLOBAL_VAR(szSambaKCCCommand),
1300                 .special        = NULL,
1301                 .enum_list      = NULL,
1302                 .flags          = FLAG_ADVANCED,
1303         },
1304         {
1305                 .label          = "nsupdate command",
1306                 .type           = P_CMDLIST,
1307                 .p_class        = P_GLOBAL,
1308                 .offset         = GLOBAL_VAR(szNSUpdateCommand),
1309                 .special        = NULL,
1310                 .enum_list      = NULL,
1311                 .flags          = FLAG_ADVANCED,
1312         },
1313         {
1314                 .label          = "allow dns updates",
1315                 .type           = P_ENUM,
1316                 .p_class        = P_GLOBAL,
1317                 .offset         = GLOBAL_VAR(allow_dns_updates),
1318                 .special        = NULL,
1319                 .enum_list      = enum_dns_update_settings,
1320                 .flags          = FLAG_ADVANCED,
1321         },
1322         {
1323                 .label          = "dns forwarder",
1324                 .type           = P_STRING,
1325                 .p_class        = P_GLOBAL,
1326                 .offset         = GLOBAL_VAR(dns_forwarder),
1327                 .special        = NULL,
1328                 .enum_list      = NULL,
1329                 .flags          = FLAG_ADVANCED,
1330         },
1331         {
1332                 .label          = "dns recursive queries",
1333                 .type           = P_BOOL,
1334                 .p_class        = P_GLOBAL,
1335                 .offset         = GLOBAL_VAR(dns_recursive_queries),
1336                 .special        = NULL,
1337                 .enum_list      = NULL
1338         },
1339
1340         {NULL,  P_BOOL,  P_NONE,  0,  NULL,  NULL,  0}
1341 };
1342
1343
1344 /* local variables */
1345 struct loadparm_context {
1346         const char *szConfigFile;
1347         struct loadparm_global *globals;
1348         struct loadparm_service **services;
1349         struct loadparm_service *sDefault;
1350         struct smb_iconv_handle *iconv_handle;
1351         int iNumServices;
1352         struct loadparm_service *currentService;
1353         bool bInGlobalSection;
1354         struct file_lists {
1355                 struct file_lists *next;
1356                 char *name;
1357                 char *subfname;
1358                 time_t modtime;
1359         } *file_lists;
1360         unsigned int flags[NUMPARAMETERS];
1361         bool loaded;
1362         bool refuse_free;
1363         bool global; /* Is this the global context, which may set
1364                       * global variables such as debug level etc? */
1365         const struct loadparm_s3_context *s3_fns;
1366 };
1367
1368
1369 struct loadparm_service *lpcfg_default_service(struct loadparm_context *lp_ctx)
1370 {
1371         if (lp_ctx->s3_fns) {
1372                 return lp_ctx->s3_fns->get_default_loadparm_service();
1373         }
1374         return lp_ctx->sDefault;
1375 }
1376
1377 /**
1378  * Convenience routine to grab string parameters into temporary memory
1379  * and run standard_sub_basic on them.
1380  *
1381  * The buffers can be written to by
1382  * callers without affecting the source string.
1383  */
1384
1385 static const char *lp_string(const char *s)
1386 {
1387 #if 0  /* until REWRITE done to make thread-safe */
1388         size_t len = s ? strlen(s) : 0;
1389         char *ret;
1390 #endif
1391
1392         /* The follow debug is useful for tracking down memory problems
1393            especially if you have an inner loop that is calling a lp_*()
1394            function that returns a string.  Perhaps this debug should be
1395            present all the time? */
1396
1397 #if 0
1398         DEBUG(10, ("lp_string(%s)\n", s));
1399 #endif
1400
1401 #if 0  /* until REWRITE done to make thread-safe */
1402         if (!lp_talloc)
1403                 lp_talloc = talloc_init("lp_talloc");
1404
1405         ret = talloc_array(lp_talloc, char, len + 100); /* leave room for substitution */
1406
1407         if (!ret)
1408                 return NULL;
1409
1410         if (!s)
1411                 *ret = 0;
1412         else
1413                 strlcpy(ret, s, len);
1414
1415         if (trim_string(ret, "\"", "\"")) {
1416                 if (strchr(ret,'"') != NULL)
1417                         strlcpy(ret, s, len);
1418         }
1419
1420         standard_sub_basic(ret,len+100);
1421         return (ret);
1422 #endif
1423         return s;
1424 }
1425
1426 /*
1427    In this section all the functions that are used to access the
1428    parameters from the rest of the program are defined
1429 */
1430
1431 /*
1432  * the creation of separate lpcfg_*() and lp_*() functions is to allow
1433  * for code compatibility between existing Samba4 and Samba3 code.
1434  */
1435
1436 /* this global context supports the lp_*() function varients */
1437 static struct loadparm_context *global_loadparm_context;
1438
1439 #define lpcfg_default_service global_loadparm_context->sDefault
1440 #define lpcfg_global_service(i) global_loadparm_context->services[i]
1441
1442 #define FN_GLOBAL_STRING(fn_name,var_name)                              \
1443  _PUBLIC_ const char *lpcfg_ ## fn_name(struct loadparm_context *lp_ctx) { \
1444         if (lp_ctx == NULL) return NULL;                                \
1445         if (lp_ctx->s3_fns) {                                           \
1446                 SMB_ASSERT(lp_ctx->s3_fns->fn_name);                    \
1447                 return lp_ctx->s3_fns->fn_name();                       \
1448         }                                                               \
1449         return lp_ctx->globals->var_name ? lp_string(lp_ctx->globals->var_name) : ""; \
1450 }
1451
1452 #define FN_GLOBAL_CONST_STRING(fn_name,var_name) \
1453  _PUBLIC_ const char *lpcfg_ ## fn_name(struct loadparm_context *lp_ctx) {\
1454          if (lp_ctx == NULL) return NULL;                               \
1455          if (lp_ctx->s3_fns) {                                          \
1456                  SMB_ASSERT(lp_ctx->s3_fns->fn_name);                   \
1457                  return lp_ctx->s3_fns->fn_name();                      \
1458          }                                                              \
1459          return lp_ctx->globals->var_name ? lp_string(lp_ctx->globals->var_name) : ""; \
1460  }
1461
1462 #define FN_GLOBAL_LIST(fn_name,var_name)                                \
1463  _PUBLIC_ const char **lpcfg_ ## fn_name(struct loadparm_context *lp_ctx) { \
1464          if (lp_ctx == NULL) return NULL;                               \
1465          if (lp_ctx->s3_fns) {                                          \
1466                  SMB_ASSERT(lp_ctx->s3_fns->fn_name);                   \
1467                  return lp_ctx->s3_fns->fn_name();                      \
1468          }                                                              \
1469          return lp_ctx->globals->var_name;                              \
1470  }
1471
1472 #define FN_GLOBAL_BOOL(fn_name,var_name) \
1473  _PUBLIC_ bool lpcfg_ ## fn_name(struct loadparm_context *lp_ctx) {\
1474          if (lp_ctx == NULL) return false;                              \
1475          if (lp_ctx->s3_fns) {                                          \
1476                  SMB_ASSERT(lp_ctx->s3_fns->fn_name);                   \
1477                  return lp_ctx->s3_fns->fn_name();                      \
1478          }                                                              \
1479          return lp_ctx->globals->var_name;                              \
1480 }
1481
1482 #define FN_GLOBAL_INTEGER(fn_name,var_name) \
1483  _PUBLIC_ int lpcfg_ ## fn_name(struct loadparm_context *lp_ctx) { \
1484          if (lp_ctx->s3_fns) {                                          \
1485                  SMB_ASSERT(lp_ctx->s3_fns->fn_name);                   \
1486                  return lp_ctx->s3_fns->fn_name();                      \
1487          }                                                              \
1488          return lp_ctx->globals->var_name;                              \
1489  }
1490
1491 /* Local parameters don't need the ->s3_fns because the struct
1492  * loadparm_service is shared and lpcfg_service() checks the ->s3_fns
1493  * hook */
1494 #define FN_LOCAL_STRING(fn_name,val) \
1495  _PUBLIC_ const char *lpcfg_ ## fn_name(struct loadparm_service *service, \
1496                                         struct loadparm_service *sDefault) { \
1497          return(lp_string((const char *)((service != NULL && service->val != NULL) ? service->val : sDefault->val))); \
1498  }
1499
1500 #define FN_LOCAL_CONST_STRING(fn_name,val) FN_LOCAL_STRING(fn_name, val)
1501
1502 #define FN_LOCAL_LIST(fn_name,val) \
1503  _PUBLIC_ const char **lpcfg_ ## fn_name(struct loadparm_service *service, \
1504                                          struct loadparm_service *sDefault) {\
1505          return(const char **)(service != NULL && service->val != NULL? service->val : sDefault->val); \
1506  }
1507
1508 #define FN_LOCAL_PARM_BOOL(fn_name, val) FN_LOCAL_BOOL(fn_name, val)
1509
1510 #define FN_LOCAL_BOOL(fn_name,val) \
1511  _PUBLIC_ bool lpcfg_ ## fn_name(struct loadparm_service *service, \
1512                                  struct loadparm_service *sDefault) {   \
1513          return((service != NULL)? service->val : sDefault->val); \
1514  }
1515
1516 #define FN_LOCAL_INTEGER(fn_name,val) \
1517  _PUBLIC_ int lpcfg_ ## fn_name(struct loadparm_service *service, \
1518                                 struct loadparm_service *sDefault) {    \
1519          return((service != NULL)? service->val : sDefault->val); \
1520  }
1521
1522 #define FN_LOCAL_PARM_INTEGER(fn_name, val) FN_LOCAL_INTEGER(fn_name, val)
1523
1524 #define FN_LOCAL_PARM_CHAR(fn_name, val) FN_LOCAL_CHAR(fn_name, val)
1525
1526 #define FN_LOCAL_CHAR(fn_name,val) \
1527  _PUBLIC_ char lpcfg_ ## fn_name(struct loadparm_service *service, \
1528                                 struct loadparm_service *sDefault) {    \
1529          return((service != NULL)? service->val : sDefault->val); \
1530  }
1531
1532 #include "lib/param/param_functions.c"
1533
1534 /* These functions remain only in lib/param for now */
1535 FN_GLOBAL_BOOL(idmap_trusted_only, bIdmapTrustedOnly)
1536 FN_GLOBAL_BOOL(readraw, bReadRaw)
1537 FN_GLOBAL_BOOL(time_server, bTimeServer)
1538 FN_GLOBAL_BOOL(unicode, bUnicode)
1539 FN_GLOBAL_BOOL(writeraw, bWriteRaw)
1540 FN_GLOBAL_LIST(name_resolve_order, szNameResolveOrder)
1541 FN_GLOBAL_LIST(smb_ports, smb_ports)
1542 FN_GLOBAL_STRING(cachedir, szCacheDir)
1543 FN_GLOBAL_STRING(socket_address, szSocketAddress)
1544 FN_GLOBAL_STRING(statedir, szStateDir)
1545
1546 /* local prototypes */
1547 static int map_parameter(const char *pszParmName);
1548 static struct loadparm_service *getservicebyname(struct loadparm_context *lp_ctx,
1549                                         const char *pszServiceName);
1550 static void copy_service(struct loadparm_service *pserviceDest,
1551                          struct loadparm_service *pserviceSource,
1552                          struct bitmap *pcopymapDest);
1553 static bool lpcfg_service_ok(struct loadparm_service *service);
1554 static bool do_section(const char *pszSectionName, void *);
1555 static void init_copymap(struct loadparm_service *pservice);
1556
1557 /* This is a helper function for parametrical options support. */
1558 /* It returns a pointer to parametrical option value if it exists or NULL otherwise */
1559 /* Actual parametrical functions are quite simple */
1560 const char *lpcfg_get_parametric(struct loadparm_context *lp_ctx,
1561                               struct loadparm_service *service,
1562                               const char *type, const char *option)
1563 {
1564         char *vfskey_tmp = NULL;
1565         char *vfskey = NULL;
1566         struct parmlist_entry *data;
1567
1568         if (lp_ctx == NULL)
1569                 return NULL;
1570
1571         if (lp_ctx->s3_fns) {
1572                 return lp_ctx->s3_fns->get_parametric(service, type, option);
1573         }
1574
1575         data = (service == NULL ? lp_ctx->globals->param_opt : service->param_opt);
1576
1577         vfskey_tmp = talloc_asprintf(NULL, "%s:%s", type, option);
1578         if (vfskey_tmp == NULL) return NULL;
1579         vfskey = strlower_talloc(NULL, vfskey_tmp);
1580         talloc_free(vfskey_tmp);
1581
1582         while (data) {
1583                 if (strcmp(data->key, vfskey) == 0) {
1584                         talloc_free(vfskey);
1585                         return data->value;
1586                 }
1587                 data = data->next;
1588         }
1589
1590         if (service != NULL) {
1591                 /* Try to fetch the same option but from globals */
1592                 /* but only if we are not already working with globals */
1593                 for (data = lp_ctx->globals->param_opt; data;
1594                      data = data->next) {
1595                         if (strcmp(data->key, vfskey) == 0) {
1596                                 talloc_free(vfskey);
1597                                 return data->value;
1598                         }
1599                 }
1600         }
1601
1602         talloc_free(vfskey);
1603
1604         return NULL;
1605 }
1606
1607
1608 /**
1609  * convenience routine to return int parameters.
1610  */
1611 static int lp_int(const char *s)
1612 {
1613
1614         if (!s) {
1615                 DEBUG(0,("lp_int(%s): is called with NULL!\n",s));
1616                 return -1;
1617         }
1618
1619         return strtol(s, NULL, 0);
1620 }
1621
1622 /**
1623  * convenience routine to return unsigned long parameters.
1624  */
1625 static unsigned long lp_ulong(const char *s)
1626 {
1627
1628         if (!s) {
1629                 DEBUG(0,("lp_ulong(%s): is called with NULL!\n",s));
1630                 return -1;
1631         }
1632
1633         return strtoul(s, NULL, 0);
1634 }
1635
1636 /**
1637  * convenience routine to return unsigned long parameters.
1638  */
1639 static long lp_long(const char *s)
1640 {
1641
1642         if (!s) {
1643                 DEBUG(0,("lp_long(%s): is called with NULL!\n",s));
1644                 return -1;
1645         }
1646
1647         return strtol(s, NULL, 0);
1648 }
1649
1650 /**
1651  * convenience routine to return unsigned long parameters.
1652  */
1653 static double lp_double(const char *s)
1654 {
1655
1656         if (!s) {
1657                 DEBUG(0,("lp_double(%s): is called with NULL!\n",s));
1658                 return -1;
1659         }
1660
1661         return strtod(s, NULL);
1662 }
1663
1664 /**
1665  * convenience routine to return boolean parameters.
1666  */
1667 static bool lp_bool(const char *s)
1668 {
1669         bool ret = false;
1670
1671         if (!s) {
1672                 DEBUG(0,("lp_bool(%s): is called with NULL!\n",s));
1673                 return false;
1674         }
1675
1676         if (!set_boolean(s, &ret)) {
1677                 DEBUG(0,("lp_bool(%s): value is not boolean!\n",s));
1678                 return false;
1679         }
1680
1681         return ret;
1682 }
1683
1684
1685 /**
1686  * Return parametric option from a given service. Type is a part of option before ':'
1687  * Parametric option has following syntax: 'Type: option = value'
1688  * Returned value is allocated in 'lp_talloc' context
1689  */
1690
1691 const char *lpcfg_parm_string(struct loadparm_context *lp_ctx,
1692                               struct loadparm_service *service, const char *type,
1693                               const char *option)
1694 {
1695         const char *value = lpcfg_get_parametric(lp_ctx, service, type, option);
1696
1697         if (value)
1698                 return lp_string(value);
1699
1700         return NULL;
1701 }
1702
1703 /**
1704  * Return parametric option from a given service. Type is a part of option before ':'
1705  * Parametric option has following syntax: 'Type: option = value'
1706  * Returned value is allocated in 'lp_talloc' context
1707  */
1708
1709 const char **lpcfg_parm_string_list(TALLOC_CTX *mem_ctx,
1710                                     struct loadparm_context *lp_ctx,
1711                                     struct loadparm_service *service,
1712                                     const char *type,
1713                                     const char *option, const char *separator)
1714 {
1715         const char *value = lpcfg_get_parametric(lp_ctx, service, type, option);
1716
1717         if (value != NULL)
1718                 return (const char **)str_list_make(mem_ctx, value, separator);
1719
1720         return NULL;
1721 }
1722
1723 /**
1724  * Return parametric option from a given service. Type is a part of option before ':'
1725  * Parametric option has following syntax: 'Type: option = value'
1726  */
1727
1728 int lpcfg_parm_int(struct loadparm_context *lp_ctx,
1729                    struct loadparm_service *service, const char *type,
1730                    const char *option, int default_v)
1731 {
1732         const char *value = lpcfg_get_parametric(lp_ctx, service, type, option);
1733
1734         if (value)
1735                 return lp_int(value);
1736
1737         return default_v;
1738 }
1739
1740 /**
1741  * Return parametric option from a given service. Type is a part of
1742  * option before ':'.
1743  * Parametric option has following syntax: 'Type: option = value'.
1744  */
1745
1746 int lpcfg_parm_bytes(struct loadparm_context *lp_ctx,
1747                   struct loadparm_service *service, const char *type,
1748                   const char *option, int default_v)
1749 {
1750         uint64_t bval;
1751
1752         const char *value = lpcfg_get_parametric(lp_ctx, service, type, option);
1753
1754         if (value && conv_str_size_error(value, &bval)) {
1755                 if (bval <= INT_MAX) {
1756                         return (int)bval;
1757                 }
1758         }
1759
1760         return default_v;
1761 }
1762
1763 /**
1764  * Return parametric option from a given service.
1765  * Type is a part of option before ':'
1766  * Parametric option has following syntax: 'Type: option = value'
1767  */
1768 unsigned long lpcfg_parm_ulong(struct loadparm_context *lp_ctx,
1769                             struct loadparm_service *service, const char *type,
1770                             const char *option, unsigned long default_v)
1771 {
1772         const char *value = lpcfg_get_parametric(lp_ctx, service, type, option);
1773
1774         if (value)
1775                 return lp_ulong(value);
1776
1777         return default_v;
1778 }
1779
1780 long lpcfg_parm_long(struct loadparm_context *lp_ctx,
1781                      struct loadparm_service *service, const char *type,
1782                      const char *option, long default_v)
1783 {
1784         const char *value = lpcfg_get_parametric(lp_ctx, service, type, option);
1785
1786         if (value)
1787                 return lp_long(value);
1788
1789         return default_v;
1790 }
1791
1792 double lpcfg_parm_double(struct loadparm_context *lp_ctx,
1793                       struct loadparm_service *service, const char *type,
1794                       const char *option, double default_v)
1795 {
1796         const char *value = lpcfg_get_parametric(lp_ctx, service, type, option);
1797
1798         if (value != NULL)
1799                 return lp_double(value);
1800
1801         return default_v;
1802 }
1803
1804 /**
1805  * Return parametric option from a given service. Type is a part of option before ':'
1806  * Parametric option has following syntax: 'Type: option = value'
1807  */
1808
1809 bool lpcfg_parm_bool(struct loadparm_context *lp_ctx,
1810                      struct loadparm_service *service, const char *type,
1811                      const char *option, bool default_v)
1812 {
1813         const char *value = lpcfg_get_parametric(lp_ctx, service, type, option);
1814
1815         if (value != NULL)
1816                 return lp_bool(value);
1817
1818         return default_v;
1819 }
1820
1821
1822 /**
1823  * Initialise a service to the defaults.
1824  */
1825
1826 static struct loadparm_service *init_service(TALLOC_CTX *mem_ctx, struct loadparm_service *sDefault)
1827 {
1828         struct loadparm_service *pservice =
1829                 talloc_zero(mem_ctx, struct loadparm_service);
1830         copy_service(pservice, sDefault, NULL);
1831         return pservice;
1832 }
1833
1834 /**
1835  * Set a string value, deallocating any existing space, and allocing the space
1836  * for the string
1837  */
1838 static bool lpcfg_string_set(TALLOC_CTX *mem_ctx, char **dest, const char *src)
1839 {
1840         talloc_free(*dest);
1841
1842         if (src == NULL)
1843                 src = "";
1844
1845         *dest = talloc_strdup(mem_ctx, src);
1846         if ((*dest) == NULL) {
1847                 DEBUG(0,("Out of memory in string_set\n"));
1848                 return false;
1849         }
1850
1851         return true;
1852 }
1853
1854 /**
1855  * Set a string value, deallocating any existing space, and allocing the space
1856  * for the string
1857  */
1858 static bool lpcfg_string_set_upper(TALLOC_CTX *mem_ctx, char **dest, const char *src)
1859 {
1860         talloc_free(*dest);
1861
1862         if (src == NULL)
1863                 src = "";
1864
1865         *dest = strupper_talloc(mem_ctx, src);
1866         if ((*dest) == NULL) {
1867                 DEBUG(0,("Out of memory in string_set_upper\n"));
1868                 return false;
1869         }
1870
1871         return true;
1872 }
1873
1874
1875
1876 /**
1877  * Add a new service to the services array initialising it with the given
1878  * service.
1879  */
1880
1881 struct loadparm_service *lpcfg_add_service(struct loadparm_context *lp_ctx,
1882                                            const struct loadparm_service *pservice,
1883                                            const char *name)
1884 {
1885         int i;
1886         struct loadparm_service tservice;
1887         int num_to_alloc = lp_ctx->iNumServices + 1;
1888         struct parmlist_entry *data, *pdata;
1889
1890         if (pservice == NULL) {
1891                 pservice = lp_ctx->sDefault;
1892         }
1893
1894         tservice = *pservice;
1895
1896         /* it might already exist */
1897         if (name) {
1898                 struct loadparm_service *service = getservicebyname(lp_ctx,
1899                                                                     name);
1900                 if (service != NULL) {
1901                         /* Clean all parametric options for service */
1902                         /* They will be added during parsing again */
1903                         data = service->param_opt;
1904                         while (data) {
1905                                 pdata = data->next;
1906                                 talloc_free(data);
1907                                 data = pdata;
1908                         }
1909                         service->param_opt = NULL;
1910                         return service;
1911                 }
1912         }
1913
1914         /* find an invalid one */
1915         for (i = 0; i < lp_ctx->iNumServices; i++)
1916                 if (lp_ctx->services[i] == NULL)
1917                         break;
1918
1919         /* if not, then create one */
1920         if (i == lp_ctx->iNumServices) {
1921                 struct loadparm_service **tsp;
1922
1923                 tsp = talloc_realloc(lp_ctx, lp_ctx->services, struct loadparm_service *, num_to_alloc);
1924
1925                 if (!tsp) {
1926                         DEBUG(0,("lpcfg_add_service: failed to enlarge services!\n"));
1927                         return NULL;
1928                 } else {
1929                         lp_ctx->services = tsp;
1930                         lp_ctx->services[lp_ctx->iNumServices] = NULL;
1931                 }
1932
1933                 lp_ctx->iNumServices++;
1934         }
1935
1936         lp_ctx->services[i] = init_service(lp_ctx->services, lp_ctx->sDefault);
1937         if (lp_ctx->services[i] == NULL) {
1938                 DEBUG(0,("lpcfg_add_service: out of memory!\n"));
1939                 return NULL;
1940         }
1941         copy_service(lp_ctx->services[i], &tservice, NULL);
1942         if (name != NULL)
1943                 lpcfg_string_set(lp_ctx->services[i], &lp_ctx->services[i]->szService, name);
1944         return lp_ctx->services[i];
1945 }
1946
1947 /**
1948  * Add a new home service, with the specified home directory, defaults coming
1949  * from service ifrom.
1950  */
1951
1952 bool lpcfg_add_home(struct loadparm_context *lp_ctx,
1953                  const char *pszHomename,
1954                  struct loadparm_service *default_service,
1955                  const char *user, const char *pszHomedir)
1956 {
1957         struct loadparm_service *service;
1958
1959         service = lpcfg_add_service(lp_ctx, default_service, pszHomename);
1960
1961         if (service == NULL)
1962                 return false;
1963
1964         if (!(*(default_service->szPath))
1965             || strequal(default_service->szPath, lp_ctx->sDefault->szPath)) {
1966                 service->szPath = talloc_strdup(service, pszHomedir);
1967         } else {
1968                 service->szPath = string_sub_talloc(service, lpcfg_pathname(default_service, lp_ctx->sDefault), "%H", pszHomedir);
1969         }
1970
1971         if (!(*(service->comment))) {
1972                 service->comment = talloc_asprintf(service, "Home directory of %s", user);
1973         }
1974         service->bAvailable = default_service->bAvailable;
1975         service->bBrowseable = default_service->bBrowseable;
1976
1977         DEBUG(3, ("adding home's share [%s] for user '%s' at '%s'\n",
1978                   pszHomename, user, service->szPath));
1979
1980         return true;
1981 }
1982
1983 /**
1984  * Add a new printer service, with defaults coming from service iFrom.
1985  */
1986
1987 bool lpcfg_add_printer(struct loadparm_context *lp_ctx,
1988                        const char *pszPrintername,
1989                        struct loadparm_service *default_service)
1990 {
1991         const char *comment = "From Printcap";
1992         struct loadparm_service *service;
1993         service = lpcfg_add_service(lp_ctx, default_service, pszPrintername);
1994
1995         if (service == NULL)
1996                 return false;
1997
1998         /* note that we do NOT default the availability flag to True - */
1999         /* we take it from the default service passed. This allows all */
2000         /* dynamic printers to be disabled by disabling the [printers] */
2001         /* entry (if/when the 'available' keyword is implemented!).    */
2002
2003         /* the printer name is set to the service name. */
2004         lpcfg_string_set(service, &service->szPrintername, pszPrintername);
2005         lpcfg_string_set(service, &service->comment, comment);
2006         service->bBrowseable = default_service->bBrowseable;
2007         /* Printers cannot be read_only. */
2008         service->bRead_only = false;
2009         /* Printer services must be printable. */
2010         service->bPrint_ok = true;
2011
2012         DEBUG(3, ("adding printer service %s\n", pszPrintername));
2013
2014         return true;
2015 }
2016
2017 /**
2018  * Map a parameter's string representation to something we can use.
2019  * Returns False if the parameter string is not recognised, else TRUE.
2020  */
2021
2022 static int map_parameter(const char *pszParmName)
2023 {
2024         int iIndex;
2025
2026         if (*pszParmName == '-')
2027                 return -1;
2028
2029         for (iIndex = 0; parm_table[iIndex].label; iIndex++)
2030                 if (strwicmp(parm_table[iIndex].label, pszParmName) == 0)
2031                         return iIndex;
2032
2033         /* Warn only if it isn't parametric option */
2034         if (strchr(pszParmName, ':') == NULL)
2035                 DEBUG(0, ("Unknown parameter encountered: \"%s\"\n", pszParmName));
2036         /* We do return 'fail' for parametric options as well because they are
2037            stored in different storage
2038          */
2039         return -1;
2040 }
2041
2042
2043 /**
2044   return the parameter structure for a parameter
2045 */
2046 struct parm_struct *lpcfg_parm_struct(struct loadparm_context *lp_ctx, const char *name)
2047 {
2048         int parmnum;
2049
2050         if (lp_ctx->s3_fns) {
2051                 return lp_ctx->s3_fns->get_parm_struct(name);
2052         }
2053
2054         parmnum = map_parameter(name);
2055         if (parmnum == -1) return NULL;
2056         return &parm_table[parmnum];
2057 }
2058
2059 /**
2060   return the parameter pointer for a parameter
2061 */
2062 void *lpcfg_parm_ptr(struct loadparm_context *lp_ctx,
2063                   struct loadparm_service *service, struct parm_struct *parm)
2064 {
2065         if (lp_ctx->s3_fns) {
2066                 return lp_ctx->s3_fns->get_parm_ptr(service, parm);
2067         }
2068
2069         if (service == NULL) {
2070                 if (parm->p_class == P_LOCAL)
2071                         return ((char *)lp_ctx->sDefault)+parm->offset;
2072                 else if (parm->p_class == P_GLOBAL)
2073                         return ((char *)lp_ctx->globals)+parm->offset;
2074                 else return NULL;
2075         } else {
2076                 return ((char *)service) + parm->offset;
2077         }
2078 }
2079
2080 /**
2081   return the parameter pointer for a parameter
2082 */
2083 bool lpcfg_parm_is_cmdline(struct loadparm_context *lp_ctx, const char *name)
2084 {
2085         int parmnum;
2086
2087         if (lp_ctx->s3_fns) {
2088                 struct parm_struct *parm = lp_ctx->s3_fns->get_parm_struct(name);
2089                 if (parm) {
2090                         return parm->flags & FLAG_CMDLINE;
2091                 }
2092                 return false;
2093         }
2094
2095         parmnum = map_parameter(name);
2096         if (parmnum == -1) return false;
2097
2098         return lp_ctx->flags[parmnum] & FLAG_CMDLINE;
2099 }
2100
2101 /**
2102  * Find a service by name. Otherwise works like get_service.
2103  */
2104
2105 static struct loadparm_service *getservicebyname(struct loadparm_context *lp_ctx,
2106                                         const char *pszServiceName)
2107 {
2108         int iService;
2109
2110         if (lp_ctx->s3_fns) {
2111                 return lp_ctx->s3_fns->get_service(pszServiceName);
2112         }
2113
2114         for (iService = lp_ctx->iNumServices - 1; iService >= 0; iService--)
2115                 if (lp_ctx->services[iService] != NULL &&
2116                     strwicmp(lp_ctx->services[iService]->szService, pszServiceName) == 0) {
2117                         return lp_ctx->services[iService];
2118                 }
2119
2120         return NULL;
2121 }
2122
2123 /**
2124  * Copy a service structure to another.
2125  * If pcopymapDest is NULL then copy all fields
2126  */
2127
2128 static void copy_service(struct loadparm_service *pserviceDest,
2129                          struct loadparm_service *pserviceSource,
2130                          struct bitmap *pcopymapDest)
2131 {
2132         int i;
2133         bool bcopyall = (pcopymapDest == NULL);
2134         struct parmlist_entry *data, *pdata, *paramo;
2135         bool not_added;
2136
2137         for (i = 0; parm_table[i].label; i++)
2138                 if (parm_table[i].p_class == P_LOCAL &&
2139                     (bcopyall || bitmap_query(pcopymapDest, i))) {
2140                         void *src_ptr =
2141                                 ((char *)pserviceSource) + parm_table[i].offset;
2142                         void *dest_ptr =
2143                                 ((char *)pserviceDest) + parm_table[i].offset;
2144
2145                         switch (parm_table[i].type) {
2146                                 case P_BOOL:
2147                                         *(bool *)dest_ptr = *(bool *)src_ptr;
2148                                         break;
2149
2150                                 case P_INTEGER:
2151                                 case P_BYTES:
2152                                 case P_OCTAL:
2153                                 case P_ENUM:
2154                                         *(int *)dest_ptr = *(int *)src_ptr;
2155                                         break;
2156
2157                                 case P_STRING:
2158                                         lpcfg_string_set(pserviceDest,
2159                                                    (char **)dest_ptr,
2160                                                    *(char **)src_ptr);
2161                                         break;
2162
2163                                 case P_USTRING:
2164                                         lpcfg_string_set_upper(pserviceDest,
2165                                                          (char **)dest_ptr,
2166                                                          *(char **)src_ptr);
2167                                         break;
2168                                 case P_LIST:
2169                                         *(const char ***)dest_ptr = (const char **)str_list_copy(pserviceDest, 
2170                                                                                   *(const char ***)src_ptr);
2171                                         break;
2172                                 default:
2173                                         break;
2174                         }
2175                 }
2176
2177         if (bcopyall) {
2178                 init_copymap(pserviceDest);
2179                 if (pserviceSource->copymap)
2180                         bitmap_copy(pserviceDest->copymap,
2181                                     pserviceSource->copymap);
2182         }
2183
2184         data = pserviceSource->param_opt;
2185         while (data) {
2186                 not_added = true;
2187                 pdata = pserviceDest->param_opt;
2188                 /* Traverse destination */
2189                 while (pdata) {
2190                         /* If we already have same option, override it */
2191                         if (strcmp(pdata->key, data->key) == 0) {
2192                                 talloc_free(pdata->value);
2193                                 pdata->value = talloc_strdup(pdata,
2194                                                              data->value);
2195                                 not_added = false;
2196                                 break;
2197                         }
2198                         pdata = pdata->next;
2199                 }
2200                 if (not_added) {
2201                         paramo = talloc_zero(pserviceDest, struct parmlist_entry);
2202                         if (paramo == NULL)
2203                                 smb_panic("OOM");
2204                         paramo->key = talloc_strdup(paramo, data->key);
2205                         paramo->value = talloc_strdup(paramo, data->value);
2206                         DLIST_ADD(pserviceDest->param_opt, paramo);
2207                 }
2208                 data = data->next;
2209         }
2210 }
2211
2212 /**
2213  * Check a service for consistency. Return False if the service is in any way
2214  * incomplete or faulty, else True.
2215  */
2216 static bool lpcfg_service_ok(struct loadparm_service *service)
2217 {
2218         bool bRetval;
2219
2220         bRetval = true;
2221         if (service->szService[0] == '\0') {
2222                 DEBUG(0, ("The following message indicates an internal error:\n"));
2223                 DEBUG(0, ("No service name in service entry.\n"));
2224                 bRetval = false;
2225         }
2226
2227         /* The [printers] entry MUST be printable. I'm all for flexibility, but */
2228         /* I can't see why you'd want a non-printable printer service...        */
2229         if (strwicmp(service->szService, PRINTERS_NAME) == 0) {
2230                 if (!service->bPrint_ok) {
2231                         DEBUG(0, ("WARNING: [%s] service MUST be printable!\n",
2232                                service->szService));
2233                         service->bPrint_ok = true;
2234                 }
2235                 /* [printers] service must also be non-browsable. */
2236                 if (service->bBrowseable)
2237                         service->bBrowseable = false;
2238         }
2239
2240         /* If a service is flagged unavailable, log the fact at level 0. */
2241         if (!service->bAvailable)
2242                 DEBUG(1, ("NOTE: Service %s is flagged unavailable.\n",
2243                           service->szService));
2244
2245         return bRetval;
2246 }
2247
2248
2249 /*******************************************************************
2250  Keep a linked list of all config files so we know when one has changed
2251  it's date and needs to be reloaded.
2252 ********************************************************************/
2253
2254 static void add_to_file_list(struct loadparm_context *lp_ctx,
2255                              const char *fname, const char *subfname)
2256 {
2257         struct file_lists *f = lp_ctx->file_lists;
2258
2259         while (f) {
2260                 if (f->name && !strcmp(f->name, fname))
2261                         break;
2262                 f = f->next;
2263         }
2264
2265         if (!f) {
2266                 f = talloc(lp_ctx, struct file_lists);
2267                 if (!f)
2268                         return;
2269                 f->next = lp_ctx->file_lists;
2270                 f->name = talloc_strdup(f, fname);
2271                 if (!f->name) {
2272                         talloc_free(f);
2273                         return;
2274                 }
2275                 f->subfname = talloc_strdup(f, subfname);
2276                 if (!f->subfname) {
2277                         talloc_free(f);
2278                         return;
2279                 }
2280                 lp_ctx->file_lists = f;
2281                 f->modtime = file_modtime(subfname);
2282         } else {
2283                 time_t t = file_modtime(subfname);
2284                 if (t)
2285                         f->modtime = t;
2286         }
2287 }
2288
2289 /*******************************************************************
2290  Check if a config file has changed date.
2291 ********************************************************************/
2292 bool lpcfg_file_list_changed(struct loadparm_context *lp_ctx)
2293 {
2294         struct file_lists *f;
2295         DEBUG(6, ("lp_file_list_changed()\n"));
2296
2297         for (f = lp_ctx->file_lists; f != NULL; f = f->next) {
2298                 char *n2;
2299                 time_t mod_time;
2300
2301                 n2 = standard_sub_basic(lp_ctx, f->name);
2302
2303                 DEBUGADD(6, ("file %s -> %s  last mod_time: %s\n",
2304                              f->name, n2, ctime(&f->modtime)));
2305
2306                 mod_time = file_modtime(n2);
2307
2308                 if (mod_time && ((f->modtime != mod_time) || (f->subfname == NULL) || (strcmp(n2, f->subfname) != 0))) {
2309                         DEBUGADD(6, ("file %s modified: %s\n", n2,
2310                                   ctime(&mod_time)));
2311                         f->modtime = mod_time;
2312                         talloc_free(f->subfname);
2313                         f->subfname = talloc_strdup(f, n2);
2314                         return true;
2315                 }
2316         }
2317         return false;
2318 }
2319
2320 /***************************************************************************
2321  Handle the "realm" parameter
2322 ***************************************************************************/
2323
2324 static bool handle_realm(struct loadparm_context *lp_ctx, int unused,
2325                          const char *pszParmValue, char **ptr)
2326 {
2327         lpcfg_string_set(lp_ctx, ptr, pszParmValue);
2328
2329         talloc_free(lp_ctx->globals->szRealm_upper);
2330         talloc_free(lp_ctx->globals->szRealm_lower);
2331
2332         lp_ctx->globals->szRealm_upper = strupper_talloc(lp_ctx, pszParmValue);
2333         lp_ctx->globals->szRealm_lower = strlower_talloc(lp_ctx, pszParmValue);
2334
2335         return true;
2336 }
2337
2338 /***************************************************************************
2339  Handle the include operation.
2340 ***************************************************************************/
2341
2342 static bool handle_include(struct loadparm_context *lp_ctx, int unused,
2343                            const char *pszParmValue, char **ptr)
2344 {
2345         char *fname = standard_sub_basic(lp_ctx, pszParmValue);
2346
2347         add_to_file_list(lp_ctx, pszParmValue, fname);
2348
2349         lpcfg_string_set(lp_ctx, ptr, fname);
2350
2351         if (file_exist(fname))
2352                 return pm_process(fname, do_section, do_parameter, lp_ctx);
2353
2354         DEBUG(2, ("Can't find include file %s\n", fname));
2355
2356         return false;
2357 }
2358
2359 /***************************************************************************
2360  Handle the interpretation of the copy parameter.
2361 ***************************************************************************/
2362
2363 static bool handle_copy(struct loadparm_context *lp_ctx, int unused,
2364                         const char *pszParmValue, char **ptr)
2365 {
2366         bool bRetval;
2367         struct loadparm_service *serviceTemp;
2368
2369         lpcfg_string_set(lp_ctx, ptr, pszParmValue);
2370
2371         bRetval = false;
2372
2373         DEBUG(3, ("Copying service from service %s\n", pszParmValue));
2374
2375         if ((serviceTemp = getservicebyname(lp_ctx, pszParmValue)) != NULL) {
2376                 if (serviceTemp == lp_ctx->currentService) {
2377                         DEBUG(0, ("Can't copy service %s - unable to copy self!\n", pszParmValue));
2378                 } else {
2379                         copy_service(lp_ctx->currentService,
2380                                      serviceTemp,
2381                                      lp_ctx->currentService->copymap);
2382                         bRetval = true;
2383                 }
2384         } else {
2385                 DEBUG(0, ("Unable to copy service - source not found: %s\n",
2386                           pszParmValue));
2387                 bRetval = false;
2388         }
2389
2390         return bRetval;
2391 }
2392
2393 static bool handle_debuglevel(struct loadparm_context *lp_ctx, int unused,
2394                         const char *pszParmValue, char **ptr)
2395 {
2396
2397         lpcfg_string_set(lp_ctx, ptr, pszParmValue);
2398         if (lp_ctx->global) {
2399                 return debug_parse_levels(pszParmValue);
2400         }
2401         return true;
2402 }
2403
2404 static bool handle_logfile(struct loadparm_context *lp_ctx, int unused,
2405                         const char *pszParmValue, char **ptr)
2406 {
2407         debug_set_logfile(pszParmValue);
2408         if (lp_ctx->global) {
2409                 lpcfg_string_set(lp_ctx, ptr, pszParmValue);
2410         }
2411         return true;
2412 }
2413
2414 /***************************************************************************
2415  Initialise a copymap.
2416 ***************************************************************************/
2417
2418 static void init_copymap(struct loadparm_service *pservice)
2419 {
2420         int i;
2421
2422         TALLOC_FREE(pservice->copymap);
2423
2424         pservice->copymap = bitmap_talloc(NULL, NUMPARAMETERS);
2425         if (!pservice->copymap)
2426                 DEBUG(0,
2427                       ("Couldn't allocate copymap!! (size %d)\n",
2428                        (int)NUMPARAMETERS));
2429         else
2430                 for (i = 0; i < NUMPARAMETERS; i++)
2431                         bitmap_set(pservice->copymap, i);
2432 }
2433
2434 /**
2435  * Process a parametric option
2436  */
2437 static bool lp_do_parameter_parametric(struct loadparm_context *lp_ctx,
2438                                        struct loadparm_service *service,
2439                                        const char *pszParmName,
2440                                        const char *pszParmValue, int flags)
2441 {
2442         struct parmlist_entry *paramo, *data;
2443         char *name;
2444         TALLOC_CTX *mem_ctx;
2445
2446         while (isspace((unsigned char)*pszParmName)) {
2447                 pszParmName++;
2448         }
2449
2450         name = strlower_talloc(lp_ctx, pszParmName);
2451         if (!name) return false;
2452
2453         if (service == NULL) {
2454                 data = lp_ctx->globals->param_opt;
2455                 mem_ctx = lp_ctx->globals;
2456         } else {
2457                 data = service->param_opt;
2458                 mem_ctx = service;
2459         }
2460
2461         /* Traverse destination */
2462         for (paramo=data; paramo; paramo=paramo->next) {
2463                 /* If we already have the option set, override it unless
2464                    it was a command line option and the new one isn't */
2465                 if (strcmp(paramo->key, name) == 0) {
2466                         if ((paramo->priority & FLAG_CMDLINE) &&
2467                             !(flags & FLAG_CMDLINE)) {
2468                                 talloc_free(name);
2469                                 return true;
2470                         }
2471
2472                         talloc_free(paramo->value);
2473                         paramo->value = talloc_strdup(paramo, pszParmValue);
2474                         paramo->priority = flags;
2475                         talloc_free(name);
2476                         return true;
2477                 }
2478         }
2479
2480         paramo = talloc_zero(mem_ctx, struct parmlist_entry);
2481         if (!paramo)
2482                 smb_panic("OOM");
2483         paramo->key = talloc_strdup(paramo, name);
2484         paramo->value = talloc_strdup(paramo, pszParmValue);
2485         paramo->priority = flags;
2486         if (service == NULL) {
2487                 DLIST_ADD(lp_ctx->globals->param_opt, paramo);
2488         } else {
2489                 DLIST_ADD(service->param_opt, paramo);
2490         }
2491
2492         talloc_free(name);
2493
2494         return true;
2495 }
2496
2497 static bool set_variable(TALLOC_CTX *mem_ctx, int parmnum, void *parm_ptr,
2498                          const char *pszParmName, const char *pszParmValue,
2499                          struct loadparm_context *lp_ctx, bool on_globals)
2500 {
2501         int i;
2502         /* if it is a special case then go ahead */
2503         if (parm_table[parmnum].special) {
2504                 bool ret;
2505                 ret = parm_table[parmnum].special(lp_ctx, -1, pszParmValue,
2506                                                   (char **)parm_ptr);
2507                 if (!ret) {
2508                         return false;
2509                 }
2510                 goto mark_non_default;
2511         }
2512
2513         /* now switch on the type of variable it is */
2514         switch (parm_table[parmnum].type)
2515         {
2516                 case P_BOOL: {
2517                         bool b;
2518                         if (!set_boolean(pszParmValue, &b)) {
2519                                 DEBUG(0,("lp_do_parameter(%s): value is not boolean!\n", pszParmValue));
2520                                 return false;
2521                         }
2522                         *(bool *)parm_ptr = b;
2523                         }
2524                         break;
2525
2526                 case P_BOOLREV: {
2527                         bool b;
2528                         if (!set_boolean(pszParmValue, &b)) {
2529                                 DEBUG(0,("lp_do_parameter(%s): value is not boolean!\n", pszParmValue));
2530                                 return false;
2531                         }
2532                         *(bool *)parm_ptr = !b;
2533                         }
2534                         break;
2535
2536                 case P_INTEGER:
2537                         *(int *)parm_ptr = atoi(pszParmValue);
2538                         break;
2539
2540                 case P_CHAR:
2541                         *(char *)parm_ptr = *pszParmValue;
2542                         break;
2543
2544                 case P_OCTAL:
2545                         *(int *)parm_ptr = strtol(pszParmValue, NULL, 8);
2546                         break;
2547
2548                 case P_BYTES:
2549                 {
2550                         uint64_t val;
2551                         if (conv_str_size_error(pszParmValue, &val)) {
2552                                 if (val <= INT_MAX) {
2553                                         *(int *)parm_ptr = (int)val;
2554                                         break;
2555                                 }
2556                         }
2557
2558                         DEBUG(0,("lp_do_parameter(%s): value is not "
2559                             "a valid size specifier!\n", pszParmValue));
2560                         return false;
2561                 }
2562
2563                 case P_CMDLIST:
2564                         *(const char ***)parm_ptr = (const char **)str_list_make(mem_ctx,
2565                                                                   pszParmValue, NULL);
2566                         break;
2567                 case P_LIST:
2568                 {
2569                         char **new_list = str_list_make(mem_ctx,
2570                                                         pszParmValue, NULL);
2571                         for (i=0; new_list[i]; i++) {
2572                                 if (new_list[i][0] == '+' && new_list[i][1]) {
2573                                         if (!str_list_check(*(const char ***)parm_ptr,
2574                                                             &new_list[i][1])) {
2575                                                 *(const char ***)parm_ptr = str_list_add(*(const char ***)parm_ptr,
2576                                                                                          &new_list[i][1]);
2577                                         }
2578                                 } else if (new_list[i][0] == '-' && new_list[i][1]) {
2579                                         str_list_remove(*(const char ***)parm_ptr,
2580                                                         &new_list[i][1]);
2581                                 } else {
2582                                         if (i != 0) {
2583                                                 DEBUG(0, ("Unsupported list syntax for: %s = %s\n",
2584                                                           pszParmName, pszParmValue));
2585                                                 return false;
2586                                         }
2587                                         *(const char ***)parm_ptr = (const char **) new_list;
2588                                         break;
2589                                 }
2590                         }
2591                         break;
2592                 }
2593                 case P_STRING:
2594                         lpcfg_string_set(mem_ctx, (char **)parm_ptr, pszParmValue);
2595                         break;
2596
2597                 case P_USTRING:
2598                         lpcfg_string_set_upper(mem_ctx, (char **)parm_ptr, pszParmValue);
2599                         break;
2600
2601                 case P_ENUM:
2602                         for (i = 0; parm_table[parmnum].enum_list[i].name; i++) {
2603                                 if (strequal
2604                                     (pszParmValue,
2605                                      parm_table[parmnum].enum_list[i].name)) {
2606                                         *(int *)parm_ptr =
2607                                                 parm_table[parmnum].
2608                                                 enum_list[i].value;
2609                                         break;
2610                                 }
2611                         }
2612                         if (!parm_table[parmnum].enum_list[i].name) {
2613                                 DEBUG(0,("Unknown enumerated value '%s' for '%s'\n", 
2614                                          pszParmValue, pszParmName));
2615                                 return false;
2616                         }
2617                         break;
2618
2619                 case P_SEP:
2620                         break;
2621         }
2622
2623 mark_non_default:
2624         if (on_globals && (lp_ctx->flags[parmnum] & FLAG_DEFAULT)) {
2625                 lp_ctx->flags[parmnum] &= ~FLAG_DEFAULT;
2626                 /* we have to also unset FLAG_DEFAULT on aliases */
2627                 for (i=parmnum-1;i>=0 && parm_table[i].offset == parm_table[parmnum].offset;i--) {
2628                         lp_ctx->flags[i] &= ~FLAG_DEFAULT;
2629                 }
2630                 for (i=parmnum+1;i<NUMPARAMETERS && parm_table[i].offset == parm_table[parmnum].offset;i++) {
2631                         lp_ctx->flags[i] &= ~FLAG_DEFAULT;
2632                 }
2633         }
2634         return true;
2635 }
2636
2637
2638 bool lpcfg_do_global_parameter(struct loadparm_context *lp_ctx,
2639                                const char *pszParmName, const char *pszParmValue)
2640 {
2641         int parmnum = map_parameter(pszParmName);
2642         void *parm_ptr;
2643
2644         if (parmnum < 0) {
2645                 if (strchr(pszParmName, ':')) {
2646                         return lp_do_parameter_parametric(lp_ctx, NULL, pszParmName, pszParmValue, 0);
2647                 }
2648                 DEBUG(0, ("Ignoring unknown parameter \"%s\"\n", pszParmName));
2649                 return true;
2650         }
2651
2652         /* if the flag has been set on the command line, then don't allow override,
2653            but don't report an error */
2654         if (lp_ctx->flags[parmnum] & FLAG_CMDLINE) {
2655                 return true;
2656         }
2657
2658         parm_ptr = lpcfg_parm_ptr(lp_ctx, NULL, &parm_table[parmnum]);
2659
2660         return set_variable(lp_ctx->globals, parmnum, parm_ptr,
2661                             pszParmName, pszParmValue, lp_ctx, true);
2662 }
2663
2664 bool lpcfg_do_service_parameter(struct loadparm_context *lp_ctx,
2665                                 struct loadparm_service *service,
2666                                 const char *pszParmName, const char *pszParmValue)
2667 {
2668         void *parm_ptr;
2669         int i;
2670         int parmnum = map_parameter(pszParmName);
2671
2672         if (parmnum < 0) {
2673                 if (strchr(pszParmName, ':')) {
2674                         return lp_do_parameter_parametric(lp_ctx, service, pszParmName, pszParmValue, 0);
2675                 }
2676                 DEBUG(0, ("Ignoring unknown parameter \"%s\"\n", pszParmName));
2677                 return true;
2678         }
2679
2680         /* if the flag has been set on the command line, then don't allow override,
2681            but don't report an error */
2682         if (lp_ctx->flags[parmnum] & FLAG_CMDLINE) {
2683                 return true;
2684         }
2685
2686         if (parm_table[parmnum].p_class == P_GLOBAL) {
2687                 DEBUG(0,
2688                       ("Global parameter %s found in service section!\n",
2689                        pszParmName));
2690                 return true;
2691         }
2692         parm_ptr = ((char *)service) + parm_table[parmnum].offset;
2693
2694         if (!service->copymap)
2695                 init_copymap(service);
2696
2697         /* this handles the aliases - set the copymap for other
2698          * entries with the same data pointer */
2699         for (i = 0; parm_table[i].label; i++)
2700                 if (parm_table[i].offset == parm_table[parmnum].offset &&
2701                     parm_table[i].p_class == parm_table[parmnum].p_class)
2702                         bitmap_clear(service->copymap, i);
2703
2704         return set_variable(service, parmnum, parm_ptr, pszParmName,
2705                             pszParmValue, lp_ctx, false);
2706 }
2707
2708 /**
2709  * Process a parameter.
2710  */
2711
2712 static bool do_parameter(const char *pszParmName, const char *pszParmValue,
2713                          void *userdata)
2714 {
2715         struct loadparm_context *lp_ctx = (struct loadparm_context *)userdata;
2716
2717         if (lp_ctx->bInGlobalSection)
2718                 return lpcfg_do_global_parameter(lp_ctx, pszParmName,
2719                                               pszParmValue);
2720         else
2721                 return lpcfg_do_service_parameter(lp_ctx, lp_ctx->currentService,
2722                                                   pszParmName, pszParmValue);
2723 }
2724
2725 /*
2726   variable argument do parameter
2727 */
2728 bool lpcfg_do_global_parameter_var(struct loadparm_context *lp_ctx, const char *pszParmName, const char *fmt, ...) PRINTF_ATTRIBUTE(3, 4);
2729 bool lpcfg_do_global_parameter_var(struct loadparm_context *lp_ctx,
2730                                 const char *pszParmName, const char *fmt, ...)
2731 {
2732         char *s;
2733         bool ret;
2734         va_list ap;
2735
2736         va_start(ap, fmt);
2737         s = talloc_vasprintf(NULL, fmt, ap);
2738         va_end(ap);
2739         ret = lpcfg_do_global_parameter(lp_ctx, pszParmName, s);
2740         talloc_free(s);
2741         return ret;
2742 }
2743
2744
2745 /*
2746   set a parameter from the commandline - this is called from command line parameter
2747   parsing code. It sets the parameter then marks the parameter as unable to be modified
2748   by smb.conf processing
2749 */
2750 bool lpcfg_set_cmdline(struct loadparm_context *lp_ctx, const char *pszParmName,
2751                        const char *pszParmValue)
2752 {
2753         int parmnum;
2754         int i;
2755
2756         if (lp_ctx->s3_fns) {
2757                 return lp_ctx->s3_fns->set_cmdline(pszParmName, pszParmValue);
2758         }
2759
2760         parmnum = map_parameter(pszParmName);
2761
2762         while (isspace((unsigned char)*pszParmValue)) pszParmValue++;
2763
2764
2765         if (parmnum < 0 && strchr(pszParmName, ':')) {
2766                 /* set a parametric option */
2767                 return lp_do_parameter_parametric(lp_ctx, NULL, pszParmName,
2768                                                   pszParmValue, FLAG_CMDLINE);
2769         }
2770
2771         if (parmnum < 0) {
2772                 DEBUG(0,("Unknown option '%s'\n", pszParmName));
2773                 return false;
2774         }
2775
2776         /* reset the CMDLINE flag in case this has been called before */
2777         lp_ctx->flags[parmnum] &= ~FLAG_CMDLINE;
2778
2779         if (!lpcfg_do_global_parameter(lp_ctx, pszParmName, pszParmValue)) {
2780                 return false;
2781         }
2782
2783         lp_ctx->flags[parmnum] |= FLAG_CMDLINE;
2784
2785         /* we have to also set FLAG_CMDLINE on aliases */
2786         for (i=parmnum-1;i>=0 && parm_table[i].offset == parm_table[parmnum].offset;i--) {
2787                 lp_ctx->flags[i] |= FLAG_CMDLINE;
2788         }
2789         for (i=parmnum+1;i<NUMPARAMETERS && parm_table[i].offset == parm_table[parmnum].offset;i++) {
2790                 lp_ctx->flags[i] |= FLAG_CMDLINE;
2791         }
2792
2793         return true;
2794 }
2795
2796 /*
2797   set a option from the commandline in 'a=b' format. Use to support --option
2798 */
2799 bool lpcfg_set_option(struct loadparm_context *lp_ctx, const char *option)
2800 {
2801         char *p, *s;
2802         bool ret;
2803
2804         s = talloc_strdup(NULL, option);
2805         if (!s) {
2806                 return false;
2807         }
2808
2809         p = strchr(s, '=');
2810         if (!p) {
2811                 talloc_free(s);
2812                 return false;
2813         }
2814
2815         *p = 0;
2816
2817         ret = lpcfg_set_cmdline(lp_ctx, s, p+1);
2818         talloc_free(s);
2819         return ret;
2820 }
2821
2822
2823 #define BOOLSTR(b) ((b) ? "Yes" : "No")
2824
2825 /**
2826  * Print a parameter of the specified type.
2827  */
2828
2829 static void print_parameter(struct parm_struct *p, void *ptr, FILE * f)
2830 {
2831         /* For the seperation of lists values that we print below */
2832         const char *list_sep = ", ";
2833         int i;
2834         switch (p->type)
2835         {
2836                 case P_ENUM:
2837                         for (i = 0; p->enum_list[i].name; i++) {
2838                                 if (*(int *)ptr == p->enum_list[i].value) {
2839                                         fprintf(f, "%s",
2840                                                 p->enum_list[i].name);
2841                                         break;
2842                                 }
2843                         }
2844                         break;
2845
2846                 case P_BOOL:
2847                         fprintf(f, "%s", BOOLSTR(*(bool *)ptr));
2848                         break;
2849
2850                 case P_BOOLREV:
2851                         fprintf(f, "%s", BOOLSTR(!*(bool *)ptr));
2852                         break;
2853
2854                 case P_INTEGER:
2855                 case P_BYTES:
2856                         fprintf(f, "%d", *(int *)ptr);
2857                         break;
2858
2859                 case P_CHAR:
2860                         fprintf(f, "%c", *(char *)ptr);
2861                         break;
2862
2863                 case P_OCTAL: {
2864                         int val = *(int *)ptr; 
2865                         if (val == -1) {
2866                                 fprintf(f, "-1");
2867                         } else {
2868                                 fprintf(f, "0%o", val);
2869                         }
2870                         break;
2871                 }
2872
2873                 case P_CMDLIST:
2874                         list_sep = " ";
2875                         /* fall through */
2876                 case P_LIST:
2877                         if ((char ***)ptr && *(char ***)ptr) {
2878                                 char **list = *(char ***)ptr;
2879                                 for (; *list; list++) {
2880                                         /* surround strings with whitespace in double quotes */
2881                                         if (*(list+1) == NULL) {
2882                                                 /* last item, no extra separator */
2883                                                 list_sep = "";
2884                                         }
2885                                         if ( strchr_m( *list, ' ' ) ) {
2886                                                 fprintf(f, "\"%s\"%s", *list, list_sep);
2887                                         } else {
2888                                                 fprintf(f, "%s%s", *list, list_sep);
2889                                         }
2890                                 }
2891                         }
2892                         break;
2893
2894                 case P_STRING:
2895                 case P_USTRING:
2896                         if (*(char **)ptr) {
2897                                 fprintf(f, "%s", *(char **)ptr);
2898                         }
2899                         break;
2900                 case P_SEP:
2901                         break;
2902         }
2903 }
2904
2905 /**
2906  * Check if two parameters are equal.
2907  */
2908
2909 static bool equal_parameter(parm_type type, void *ptr1, void *ptr2)
2910 {
2911         switch (type) {
2912                 case P_BOOL:
2913                 case P_BOOLREV:
2914                         return (*((bool *)ptr1) == *((bool *)ptr2));
2915
2916                 case P_INTEGER:
2917                 case P_ENUM:
2918                 case P_OCTAL:
2919                 case P_BYTES:
2920                         return (*((int *)ptr1) == *((int *)ptr2));
2921
2922                 case P_CHAR:
2923                         return (*((char *)ptr1) == *((char *)ptr2));
2924
2925                 case P_LIST:
2926                 case P_CMDLIST:
2927                         return str_list_equal(*(const char ***)ptr1, *(const char ***)ptr2);
2928
2929                 case P_STRING:
2930                 case P_USTRING:
2931                 {
2932                         char *p1 = *(char **)ptr1, *p2 = *(char **)ptr2;
2933                         if (p1 && !*p1)
2934                                 p1 = NULL;
2935                         if (p2 && !*p2)
2936                                 p2 = NULL;
2937                         return (p1 == p2 || strequal(p1, p2));
2938                 }
2939                 case P_SEP:
2940                         break;
2941         }
2942         return false;
2943 }
2944
2945 /**
2946  * Process a new section (service).
2947  *
2948  * At this stage all sections are services.
2949  * Later we'll have special sections that permit server parameters to be set.
2950  * Returns True on success, False on failure.
2951  */
2952
2953 static bool do_section(const char *pszSectionName, void *userdata)
2954 {
2955         struct loadparm_context *lp_ctx = (struct loadparm_context *)userdata;
2956         bool bRetval;
2957         bool isglobal = ((strwicmp(pszSectionName, GLOBAL_NAME) == 0) ||
2958                          (strwicmp(pszSectionName, GLOBAL_NAME2) == 0));
2959         bRetval = false;
2960
2961         /* if we've just struck a global section, note the fact. */
2962         lp_ctx->bInGlobalSection = isglobal;
2963
2964         /* check for multiple global sections */
2965         if (lp_ctx->bInGlobalSection) {
2966                 DEBUG(4, ("Processing section \"[%s]\"\n", pszSectionName));
2967                 return true;
2968         }
2969
2970         /* if we have a current service, tidy it up before moving on */
2971         bRetval = true;
2972
2973         if (lp_ctx->currentService != NULL)
2974                 bRetval = lpcfg_service_ok(lp_ctx->currentService);
2975
2976         /* if all is still well, move to the next record in the services array */
2977         if (bRetval) {
2978                 /* We put this here to avoid an odd message order if messages are */
2979                 /* issued by the post-processing of a previous section. */
2980                 DEBUG(4, ("Processing section \"[%s]\"\n", pszSectionName));
2981
2982                 if ((lp_ctx->currentService = lpcfg_add_service(lp_ctx, lp_ctx->sDefault,
2983                                                                    pszSectionName))
2984                     == NULL) {
2985                         DEBUG(0, ("Failed to add a new service\n"));
2986                         return false;
2987                 }
2988         }
2989
2990         return bRetval;
2991 }
2992
2993
2994 /**
2995  * Determine if a particular base parameter is currently set to the default value.
2996  */
2997
2998 static bool is_default(struct loadparm_service *sDefault, int i)
2999 {
3000         void *def_ptr = ((char *)sDefault) + parm_table[i].offset;
3001         if (!defaults_saved)
3002                 return false;
3003         switch (parm_table[i].type) {
3004                 case P_CMDLIST:
3005                 case P_LIST:
3006                         return str_list_equal((const char **)parm_table[i].def.lvalue, 
3007                                               (const char **)def_ptr);
3008                 case P_STRING:
3009                 case P_USTRING:
3010                         return strequal(parm_table[i].def.svalue,
3011                                         *(char **)def_ptr);
3012                 case P_BOOL:
3013                 case P_BOOLREV:
3014                         return parm_table[i].def.bvalue ==
3015                                 *(bool *)def_ptr;
3016                 case P_INTEGER:
3017                 case P_CHAR:
3018                 case P_OCTAL:
3019                 case P_BYTES:
3020                 case P_ENUM:
3021                         return parm_table[i].def.ivalue ==
3022                                 *(int *)def_ptr;
3023                 case P_SEP:
3024                         break;
3025         }
3026         return false;
3027 }
3028
3029 /**
3030  *Display the contents of the global structure.
3031  */
3032
3033 static void dump_globals(struct loadparm_context *lp_ctx, FILE *f,
3034                          bool show_defaults)
3035 {
3036         int i;
3037         struct parmlist_entry *data;
3038
3039         fprintf(f, "# Global parameters\n[global]\n");
3040
3041         for (i = 0; parm_table[i].label; i++)
3042                 if (parm_table[i].p_class == P_GLOBAL &&
3043                     (i == 0 || (parm_table[i].offset != parm_table[i - 1].offset))) {
3044                         if (!show_defaults && (lp_ctx->flags[i] & FLAG_DEFAULT))
3045                                 continue;
3046                         fprintf(f, "\t%s = ", parm_table[i].label);
3047                         print_parameter(&parm_table[i], lpcfg_parm_ptr(lp_ctx, NULL, &parm_table[i]), f);
3048                         fprintf(f, "\n");
3049         }
3050         if (lp_ctx->globals->param_opt != NULL) {
3051                 for (data = lp_ctx->globals->param_opt; data;
3052                      data = data->next) {
3053                         if (!show_defaults && (data->priority & FLAG_DEFAULT)) {
3054                                 continue;
3055                         }
3056                         fprintf(f, "\t%s = %s\n", data->key, data->value);
3057                 }
3058         }
3059
3060 }
3061
3062 /**
3063  * Display the contents of a single services record.
3064  */
3065
3066 static void dump_a_service(struct loadparm_service * pService, struct loadparm_service *sDefault, FILE * f,
3067                            unsigned int *flags)
3068 {
3069         int i;
3070         struct parmlist_entry *data;
3071
3072         if (pService != sDefault)
3073                 fprintf(f, "\n[%s]\n", pService->szService);
3074
3075         for (i = 0; parm_table[i].label; i++) {
3076                 if (parm_table[i].p_class == P_LOCAL &&
3077                     (*parm_table[i].label != '-') &&
3078                     (i == 0 || (parm_table[i].offset != parm_table[i - 1].offset)))
3079                 {
3080                         if (pService == sDefault) {
3081                                 if (flags && (flags[i] & FLAG_DEFAULT)) {
3082                                         continue;
3083                                 }
3084                                 if&nbs