summaryrefslogtreecommitdiffstats
path: root/doc/format-specifiers.txt
blob: 8919d7a58db591d061e8378f3d1713c3d78b61cb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
== Function Specifiers ==

Both the NIS Server and Schema Compatibility plugins use format
specifiers given in their respective configurations to control how they
massage the contents of entries which are already in the directory
server into entries in either NIS maps or the compatibility area of the
directory.

=== Basics ===

Format specifiers can reference values of attributes in the entry which
is currently being examined like so:
  %{attribute}

The values of multiple attributes can be mixed together like so:
  %{one_attribute}:%{another_attribute}

Like shell variables, a reference to an attribute can specify a default
value to be used in cases where the entry has no value for the specified
attribute:
  %{gecos:-%{cn:-}}

Again, like shell variables, a reference can also specify an alternate
value to be provided when the entry has a value (though this is not
expected to be used as frequently) which should be overridden:
  %{cn:+%{cn},,,}%{cn:-%{gecos}}

Or to use a more concrete (but still simplified) example:
  %{uid}:*:%{uidNumber}:%{gidNumber}:%{gecos:-%{cn:-}}:%{homeDirectory:-/}:%{loginShell:-/bin/sh}

Additional operators include "#", "##", "%", "%%", "/", "//", which
operate in ways similar to their shell counterparts (with one notable
exception: patterns for the "/" operator can not currently be anchored
to the beginning or end of the string).

Strictly speaking, references to attributes return ''lists'' of values,
or produce an evaluation error if no values are found.  This helps
prevent invalid entries from showing up in NIS maps and in the
directory.

=== Functions ===

Additionally, several built-in "function"s are available.  These can be
used to modify data that's been read from the current entry before it's
incorporated into the result, or for importing values from other entries
and combining them with data from the current entry.  Generally,
function invocations look like this:

  %function(ARG[,...])

A function invocation uses a comma-separated list of double-quoted
arguments.  Any arguments which themselves contain a double-quote need
to escape the double-quote using a '\' character.  Naturally, the '\'
character itself also needs to be escaped whenever it appears.  Some
functions can take expressions as arguments, allowing functions to
operate on data after it has been acted on by other functions.

== Implemented Functions ==

=== first ===

  first(''EXPRESSION''[,''DEFAULT''])

Evaluates ''EXPRESSION'', and if one or more values is produced,
provides only the first value.  (Here, ''first'' refers to the first
value in the list of values after they've been sorted.)  If no values
result, then ''DEFAULT'' is evaluated as an expression and its result is
provided.  Nothing is done to ensure that ''DEFAULT'' provides only one
value, however.

=== match ===

  match(''EXPRESSION'',''PATTERN''[,''DEFAULT''])

Selects the single value of ''EXPRESSION'' which matches the globbing
pattern ''PATTERN''.  If no value matches, and a ''DEFAULT'' was
specified, then ''DEFAULT'' is evaluated as an expression and its value
is provided.

Here's an example entry:

  dn: cn=group
  member: bob
  member: dave

And here's how it evaluates out:

  %match("%{member}","b*")        -> bob
  %match("%{member}","d*")        -> dave
  %match("%{member}","e*")        no value
  %match("%{member}","*e*")       -> dave
  %match("%{member}","e*","jim")  -> jim
  %match("%{member}","*","%{cn}") -> group

=== mmatch ===

  mmatch(''EXPRESSION'',''PATTERN''])

Similar to match, except that any number of matching values may be found
and returned.

=== regmatch ===

  regmatch(''EXPRESSION'',''PATTERN''[,''DEFAULT''])

Selects the value of ''EXPRESSION'' which matches the extended regular
expression ''PATTERN''.  If no values match, and a ''DEFAULT'' was
specified, then ''DEFAULT'' is evaluated as an expression and its value
is produced.

Here's an example entry:

  dn: cn=group
  member: bob
  member: dave

And here's how it evaluates out:

  %regmatch("%{member}","^b.*")       -> bob
  %regmatch("%{member}","^d.*")       -> dave
  %regmatch("%{member}","e")          -> dave
  %regmatch("%{member}","^e")         no value
  %regmatch("%{member}","^e.*","jim") -> jim
  %regmatch("%{member}",".*","%{cn}") -> group

=== regmatchi ===

  regmatchi(''EXPRESSION'',''PATTERN''[,''DEFAULT''])

Exactly the same as regmatch, except that pattern matching is performed in a
case-insensitive manner.

=== mregmatch ===

  mregmatch(''EXPRESSION'',''PATTERN''])

Similar to regmatch, except that any number of matching values may be found
and returned.

=== mregmatchi ===

  mregmatchi(''EXPRESSION'',''PATTERN''])

Exactly the same as mregmatch, except that pattern matching is performed in
a case-insensitive manner.

=== regsub ===

  regsub(''EXPRESSION'',''PATTERN'',''TEMPLATE''[,''DEFAULT''])

Selects the value of ''EXPRESSION'' which matches the extended regular
expression ''PATTERN'' and uses ''TEMPLATE'' to build the result.  If no
values match, and a ''DEFAULT'' was specified, then ''DEFAULT'' is
evaluated as an expression and its value is produced, otherwise an error
occurs.

The template is treated as a literal value, but is allowed to
incorporate the n'th substring (one of the first nine) from the matched
value by including the sequence "%n" in the template.

Here's an example entry:

  dn: cn=group
  member: bob
  member: dave

And here's how it evaluates out:

  %regsub("%{member}","o","%0")          -> bob
  %regsub("%{member}","o","%1")          -> 
  %regsub("%{member}","^o","%0")         no value
  %regsub("%{member}","^d(.).*","%1")    -> a
  %regsub("%{member}","^(.*)e","t%1y")   -> tdavy
  %regsub("%{member}","^o","%0","jim")   -> jim
  %regsub("%{member}","^o","%0","%{cn}") -> group

=== regsubi ===

  regsubi(''EXPRESSION'',''PATTERN'',''TEMPLATE''[,''DEFAULT''])

Exactly the same as regsub, except that pattern matching is performed in a
case-insensitive manner.

=== mregsub ===

  mregsub(''EXPRESSION'',''PATTERN'',''TEMPLATE'')

Similar to regsub, except that any number of matching values may be found,
processed, and returned.

=== regsubi ===

  mregsubi(''EXPRESSION'',''PATTERN'',''TEMPLATE'')

Exactly the same as regsubi, except that pattern matching is performed in a
case-insensitive manner.

=== deref ===

  deref(''THISATTRIBUTE'',''THATATTRIBUTE'')

Returns a list of the values of ''THATATTRIBUTE'' for directory entries
named by this entry's ''THISATTRIBUTE''.  Its function is similar in
principle to the indirect CoS functionality provided by the directory
server.

Here are some example entries:

  dn: cn=group
  member: uid=bob
  member: uid=pete

  dn: uid=bob
  uid: bob

  dn: uid=pete
  uid: pete

And here's how various expressions evaluate for ''cn=group'':

  %deref("member","foo") -> no values
  %deref("member","uid") -> (bob,pete)

Because the plugin attempts to track updates, the ''THISATTRIBUTE''
attribute should be indexed and defined with a proper syntax and
equality test in the directory server schema.

=== deref_f ===

  deref_f(''THISATTRIBUTE'',''FILTER'',''THATATTRIBUTE'')

Returns a list of the values of ''THATATTRIBUTE'' for directory entries
named by this entry's ''THISATTRIBUTE'' which match ''FILTER''.  Its function
is similar in principle to the indirect CoS functionality provided by the
directory server.

Here are some example entries:

  dn: cn=group
  member: uid=bob
  member: uid=pete

  dn: uid=bob
  uid: bob

  dn: uid=pete
  uid: pete

And here's how various expressions evaluate for ''cn=group'':

  %deref("member","objectclass=*","foo") -> no values
  %deref("member","objectclass=*","uid") -> (bob,pete)
  %deref("member","uid=pete","uid") -> (pete)

Because the plugin attempts to track updates, the ''THISATTRIBUTE''
attribute should be indexed and defined with a proper syntax and
equality test in the directory server schema.

=== deref_r ===

  deref_r(''ATTRIBUTE''[,''OTHERATTRIBUTE''[...]],''VALUEATTRIBUTE'')

Looks for entries named by this entry's ''ATTRIBUTE'', and then by those
entries' ''ATTRIBUTE'', repeating the search until there are no more
entries to find named by ''ATTRIBUTE'' in the set of entries seen.

Taking that set as a new starting point, searches for entries named by
that set's ''OTHERATTRIBUTE'' values, similarly repeating until a new
complete set of entries is determined.  The process continues to be
repeated for each listed attribute except the last.

When the final set of entries is determined, their ''VALUEATTRIBUTE''
values will be used to construct the result list.

Here are some example entries:

  dn: cn=group
  member: cn=othergroup
  member: uid=bob
  includedgroup: clan=macleod

  dn: cn=othergroup
  member: uid=pete
  uid: bogus

  dn: uid=bob
  uid: bob

  dn: uid=pete
  uid: pete

  dn: clan=macleod
  includedgroup: cn=foundlings

  dn: cn=foundlings
  member: uid=cmacleod
  member: uid=dmacleod

  dn: uid=cmacleod
  uid: cmacleod

  dn: uid=dmacleod
  uid: dmacleod

And here's how various expressions evaluate for ''cn=group'':

  %deref_r("member","foo") -> no values
  %deref_r("member","uid") -> (bogus,bob,pete)

When evaluating the first attribute, the ''member'' attribute of
''cn=group'' produces this set of entries:

    * cn=group (the original entry)
    * cn=othergroup (added because it was named by ''cn=group'')
    * uid=bob (added because it was named by ''cn=group'')
    * uid=pete (added because it was named by ''cn=othergroup'')

The result list is pulled from this set of entries.

Here's another example:

  %deref_r("includedgroup","member","uid") -> (bogus,bob,cmacleod,dmacleod,pete)

When evaluating the first attribute, the ''includedgroup'' attribute
of ''cn=group'' leads to this set of entries:

    * cn=group (the original entry)
    * clan=macleod (named by cn=group)
    * cn=foundlings (named by clan=macleod)

When evaluating the second attribute, the ''member'' attribute values
for the previous set of entries produces this set of entries:

    * cn=othergroup (named by cn=group)
    * uid=bob (named by cn=group)
    * uid=cmacleod (named by cn=foundlings)
    * uid=dmacleod (named by cn=foundlings)
    * uid=pete (named by cn=othergroup)

The result list is pulled from this set of entries.

Because the plugin attempts to track updates, every attribute used here
(except for ''VALUEATTRIBUTE'') should be indexed and defined with a
proper syntax and equality test in the directory server schema.

=== deref_rf ===

  deref_r(''ATTRIBUTE'',''FILTER''[,''OTHERATTRIBUTE'',''OTHERFILTER''[,...]],''VALUEATTRIBUTE'')

Looks for entries named by this entry's ''ATTRIBUTE'' which match the
''FILTER'', and then by those entries' ''ATTRIBUTE'' which also match
the ''FILTER'', repeating the search until there are no more entries to
find named by ''ATTRIBUTE'' in the set of entries seen.

Taking that set as a new starting point, searches for entries named by
that set's ''OTHERATTRIBUTE'' values which match ''OTHERFILTER'',
similarly repeating until a new complete set of entries is determined.
The process continues to be repeated for each listed attribute except
the last.

When the final set of entries is determined, their ''VALUEATTRIBUTE''
values will be used to construct the result list.

Here are some example entries:

  dn: cn=group
  objectclass: group
  member: cn=othergroup
  member: uid=bob
  includedgroup: clan=macleod

  dn: cn=othergroup
  objectclass: group
  member: uid=pete
  uid: bogus

  dn: uid=bob
  objectclass: user
  uid: bob

  dn: uid=pete
  objectclass: user
  uid: pete

  dn: clan=macleod
  objectclass: group
  includedgroup: cn=foundlings

  dn: cn=foundlings
  objectclass: group
  member: uid=cmacleod
  member: uid=dmacleod

  dn: uid=cmacleod
  objectclass: user
  uid: cmacleod

  dn: uid=dmacleod
  objectclass: user
  uid: dmacleod

And here's how various expressions evaluate for ''cn=group'':

  %deref_rf("member","objectclass=*","foo") -> no values
  %deref_rf("member","objectclass=user","uid") -> (bob)

When evaluating the first attribute, the ''member'' attribute of
''cn=group'' against filter 'objectclass=user', produces this set of
entries:

    * uid=bob (added because it was named by ''cn=group'' and matches
               the filter)

The result list is pulled from this set of entries.

Here's another example:

  %deref_rf("includedgroup","objectclass=group","member","objectclass=user","uid") -> no values

When evaluating the first attribute, the ''includedgroup'' attribute
of ''cn=group'' leads to this set of ''objectclass=group'' entries:

    * clan=macleod (named by cn=group)

When evaluating the second attribute, the ''member'' attribute values
for the previous set of entries produces no ''objectclass=user'' entries.

The result list is, therefore, empty.

Because the plugin attempts to track updates, every attribute used here
(except for ''VALUEATTRIBUTE'') should be indexed and defined with a
proper syntax and equality test in the directory server schema.  This
function can also be invoked as ''deref_fr''.

=== referred ===

  referred(''SET'',''THATATTRIBUTE'',''THATOTHERATTRIBUTE'')

Creates a separated list of the values of ''THATOTHERATTRIBUTE'' stored
in directory entries which have entries in the current group in the
named ''SET'' and which also have this entry's name as a value for
''THATATTRIBUTE''.

Here are some example entries:

  dn: cn=group

  dn: uid=bob
  memberof: cn=group
  uid: bob

  dn: uid=pete
  memberof: cn=group
  uid: pete

And here's how various expressions evaluate for ''cn=group'', if
''uid=bob'' and ''uid=pete'' are both part of a set of entries named
''SET'':

  %referred("SET","memberof","foo") -> no values
  %referred("SET","memberof","uid") -> (bob,pete)

Because the plugin performs searches internally, ''THATATTRIBUTE''
should be indexed and defined with a proper syntax and equality test in
the directory server schema.

=== referred_r ===

  referred_r(''SET'',''ATTRIBUTE''[,''OTHERSET'',''OTHERATTRIBUTE''[,...],''VALUEATTRIBUTE'')

Searches for entries in the current group in both the current set and
''SET'' which refer to this entry using ''ATTRIBUTE'', then searches for
entries which refer to any of the just-found entries, repeating the
process until a complete set of referring entries is formed.

Then, searches for entries in ''SET'' and ''OTHERSET'' which refer to
entries in the just-found set, repeating the process until a new
complete set is formed.

The value of ''VALUEATTRIBUTE'' for every entry encountered along the
way will be returned.

Here are some example entries:

  dn: cn=group

  dn: cn=othergroup
  memberOf: cn=group

  dn: uid=bob
  uid: bob
  memberOf: cn=group

  dn: uid=pete
  uid: pete
  memberOf: cn=othergroup

And here's how various expressions evaluate for ''cn=group'', if all of
the entries with ''uid'' values are in a set named ''people'':

  %referred("people","memberof","foo") -> no values
  %referred("people","memberof","uid") -> (bob,pete)

Because the plugin performs searches internally, every attribute used
here (except for ''VALUEATTRIBUTE'') should be indexed and defined with
a proper syntax and equality test in the directory server schema.

=== merge ===

  merge(''SEPARATOR'',''EXPRESSION''[,...])

Evaluates and then creates a single value using multiple expressions
which may evaluate to either single values or lists.  Any expressions
which cannot be evaluated are ignored.

Here are some example entries:

  dn: cn=group
  membername: jim
  member: uid=bob
  member: uid=pete

  dn: uid=bob
  uid: bob

  dn: uid=pete
  uid: pete

And here's how an example expression evaluates for ''cn=group'':

  %merge(":","%{membername}","%deref(\"member\",\"uid\")") -> jim:bob:pete
  %merge(":","%{madeup}") -> (empty string)

=== collect ===

  collect(''EXPRESSION''[,...])

Evaluates each ''EXPRESSION'' in turn, creating one large list by
appending to it all of the values which are produced by evaluating every
expression.  Any expressions which cannot be evaluated are ignored.

Here's an example entry:

  dn: cn=group
  cn: group
  membername: jim
  member: uid=bob
  member: uid=pete

And here's how some example expressions evaluate for ''cn=group'':

  %collect("%{bogus}","%{member}","%{membername}") -> (uid=bob,uid=pete,jim)

=== link ===

  link(''EXPRESSION'',''PAD''[,''SEPARATOR'',''EXPRESSION2'',''PAD2''[,...])

Evaluates each ''EXPRESSION'' and ''PAD'' in turn to produce a list of
values.  If the lists produced by each of the expressions are not of the
same length, then each ''EXPRESSION'''s corresponding ''PAD'' value is
appended to each list to pad them out until they are all of equal length
(i.e., the length of the longest list).

Then, one list of values is produced by using the first value from each
list (separated by the corresponding SEPARATOR), then using the second
values from each list, continuing until all lists have been exhausted.

Here's an example entry:

  dn: cn=group
  cn: group
  membername: jim
  member: uid=bob
  member: uid=pete

And here's how an example expression evaluates for ''cn=group'':

  %link("%{member}","?","/","%{membername}","?") -> (uid=bob/jim,uid=pete/?)

=== ifeq ===

  ifeq(''ATTRIBUTE'',''EXPRESSION'',''MATCH-EXPRESSION'',''NONMATCH-EXPRESSION'')

Evaluates ''EXPRESSION'', and if the entry's ''ATTRIBUTE'' attribute
matches the value provided by the expression (as determined by the
server's matching rules for the attribute), evaluates and returns
''MATCH-EXPRESSION'', otherwise ''NONMATCH-EXPRESSION'' will be
evaluated and returned.

Here's an example entry:

  dn: cn=group
  cn: group
  membername: jim
  member: uid=bob
  member: uid=pete

And here's how an example expression evaluates for ''cn=group'':

  %ifeq("member","jim","","%{membername}") -> (jim)

=== default ===

  default(''EXPRESSION1'',''EXPRESSION2''[,...])

Evaluates ''EXPRESSION1'', returning its values if any are produced.  If no
result is produced, evaluates ''EXPRESSION2'', returning its values if any are
produced.  Keeps trying successive expressions until it gets results or runs
out of expressions.

Here's an example entry:

  dn: cn=group
  cn: group
  membername: jim
  member: uid=bob
  member: uid=pete

And here's how an example expression evaluates for ''cn=group'':

  %default("%{member}","jim") -> (uid=bob,uid=pete)
  %default("%{membername}","bob") -> (jim)
  %default("%{nosuchvalue}","bob") -> (bob)

=== sort ===

  sort(''EXPRESSION'')

Evaluates ''EXPRESSION'', returning its values if any are produced, sorted by
binary value.  This is more useful for ensuring consistency than prettiness,
as the sorting is not case-aware and doesn't recognize numbers.