File: developers.html

package info (click to toggle)
libcli 1.9.1~20080302-1
  • links: PTS
  • area: main
  • in suites: lenny, squeeze
  • size: 184 kB
  • ctags: 190
  • sloc: ansic: 1,982; makefile: 98
file content (498 lines) | stat: -rw-r--r-- 17,150 bytes parent folder | download | duplicates (2)
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
<HTML>
<HEAD>
<TITLE>libcli Developer's Reference</TITLE>
</HEAD>
<BODY>

<H1>libcli Developer's Reference</H1>

<H2><A NAME="TOC">Table of Contents</A></H2>
<OL>
	<LI><A HREF="#Introduction">Introduction</A></LI>
	<LI><A HREF="#auth">Authentication</A></LI>
	<LI><A HREF="#tutorial">Tutorial</A></LI>
	<LI><A HREF="#funcref">Function Reference</A></LI>
	<OL>
		<LI><A HREF="#cli_init">cli_init()</A></LI>
		<LI><A HREF="#cli_done">cli_done()</A></LI>
		<LI><A HREF="#cli_register_command">cli_register_command()</A></LI>
		<LI><A HREF="#cli_unregister_command">cli_unregister_command()</A></LI>
		<LI><A HREF="#cli_loop">cli_loop()</A></LI>
		<LI><A HREF="#cli_set_auth_callback">cli_set_auth_callback()</A></LI>
		<LI><A HREF="#cli_allow_user">cli_allow_user()</A></LI>
		<LI><A HREF="#cli_deny_user">cli_deny_user()</A></LI>
		<LI><A HREF="#cli_set_banner">cli_set_banner()</A></LI>
		<LI><A HREF="#cli_set_hostname">cli_set_hostname()</A></LI>
		<LI><A HREF="#cli_regular">cli_regular()</A></LI>
		<LI><A HREF="#cli_file">cli_file()</A></LI>
		<LI><A HREF="#cli_print">cli_print()</A></LI>
		<LI><A HREF="#cli_error">cli_error()</A></LI>
		<LI><A HREF="#cli_print_callback">cli_print_callback()</A></LI>
		<LI><A HREF="#cli_set_enable_callback">cli_set_enable_callback()</A></LI>
		<LI><A HREF="#cli_allow_enable">cli_allow_enable()</A></LI>
		<LI><A HREF="#cli_set_configmode">cli_set_configmode()</A></LI>
	</OL>
</OL>

<H2><A NAME="Introduction">1.0 Introduction</A></H2>

<P>
libcli provides a telnet command-line environment which can be embedded
in other programs.  This environment includes useful features such as
automatic authentication, history, and command-line editing.
</P>

<P>
This guide should show you everything you need to embed libcli into
your program.  If you have any corrections, suggestions or modifications,
please E-mail David Parrish &lt;david@dparrish.com&gt;.
</P>

<H2><A NAME="auth">2.0 Authentication</A></H2>

<P>
Two methods of authentcation are supported by libcli - internal and callback.
</P>

<P>
Internal authentication is based on a list of username / password
combinations that are set up before <A HREF="#cli_loop">cli_loop()</A>
is called.  Passwords may be clear text, MD5 encrypted, or DES
encrypted (requires a <B>{crypt}</B> prefix to distinguish from clear
text).
</P>

<P>
Callback based authentication calls a callback with the username and
password that the user enters, and must return a <EM>CLI_OK</EM> or
<EM>CLI_ERROR</EM>.  This can be used for checking passwords against
some other database such as LDAP.
</P>

<P>
If neither <A HREF="#cli_set_auth_callback">cli_set_auth_callback()</A>
or <A HREF="#cli_allow_user">cli_allow_user()</A> have been called before
<A HREF="#cli_loop">cli_loop()</A>, then authentication will be
disabled and the user will not be prompted for a username / password
combination.
</P>

<P>
Authentication for the privileged state can also be defined by a
static password or by a callback.  Use the
<A HREF="#cli_set_enable_callback">cli_set_enable_callback()</A> or
<A HREF="#cli_allow_enable">cli_allow_enable</A> functions to set the
enable password.
</P>

<H2><A NAME="tutorial">3.0 Tutorial</A></H2>

This section will guide you through implementing libcli in a basic server.

<OL>

<LI>Create a file libclitest.c.
<PRE>
#include &lt;sys/types.h&gt;
#include &lt;sys/socket.h&gt;
#include &lt;arpa/inet.h&gt;
#include &lt;unistd.h&gt;
#include &lt;string.h&gt;
#include &lt;libcli.h&gt;

int main(int argc, char *argv[])
{
	struct sockaddr_in servaddr;
	struct cli_command *c;
	struct cli_def *cli;
	int on = 1, x, s;

	<FONT COLOR=green>// Must be called first to setup data structures</FONT>
	cli = <A HREF="#cli_init">cli_init</A>();

	<FONT COLOR=green>// Set the hostname (shown in the the prompt)</FONT>
	<A HREF="#cli_set_hostname">cli_set_hostname</A>(cli, "test");

	<FONT COLOR=green>// Set the greeting</FONT>
	<A HREF="#cli_set_banner">cli_set_banner</A>(cli, "Welcome to the CLI test program.");

	<FONT COLOR=green>// Enable 2 username / password combinations</FONT>
	<A HREF="#cli_allow_user">cli_allow_user</A>(cli, "fred", "nerk");
	<A HREF="#cli_allow_user">cli_allow_user</A>(cli, "foo", "bar");

	<FONT COLOR=green>// Set up a few simple one-level commands</FONT>
	<A HREF="#cli_register_command">cli_register_command</A>(cli, NULL, "test", cmd_test, PRIVILEGE_UNPRIVILEGED, MODE_EXEC, NULL);
	<A HREF="#cli_register_command">cli_register_command</A>(cli, NULL, "simple", cmd_test, PRIVILEGE_UNPRIVILEGED, MODE_EXEC, NULL);
	<A HREF="#cli_register_command">cli_register_command</A>(cli, NULL, "simon", NULL, PRIVILEGE_UNPRIVILEGED, MODE_EXEC, NULL);

	<FONT COLOR=green>// This command takes arguments, and requires privileged mode (enable)</FONT>
	<A HREF="#cli_register_command">cli_register_command</A>(cli, NULL, "set", cmd_set, PRIVILEGE_PRIVILEGED, MODE_EXEC, NULL);

	<FONT COLOR=green>// Set up 2 commands "show counters" and "show junk"</FONT>
	c = <A HREF="#cli_register_command">cli_register_command</A>(cli, NULL, "show", NULL, PRIVILEGE_UNPRIVILEGED, MODE_EXEC, NULL);
	<FONT COLOR=green>// Note how we store the previous command and use it as the parent for this one.</FONT>
	<A HREF="#cli_register_command">cli_register_command</A>(cli, c, "junk", cmd_test, PRIVILEGE_UNPRIVILEGED, MODE_EXEC, NULL);
	<FONT COLOR=green>// This one has some help text</FONT>
	<A HREF="#cli_register_command">cli_register_command</A>(cli, c, "counters", cmd_test, PRIVILEGE_UNPRIVILEGED, MODE_EXEC, "Show the counters that the system uses");

	<FONT COLOR=green>// Create a socket</FONT>
	s = socket(AF_INET, SOCK_STREAM, 0);
	setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &amp;on, sizeof(on));

	<FONT COLOR=green>// Listen on port 12345</FONT>
	memset(&amp;servaddr, 0, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
	servaddr.sin_port = htons(12345);
	bind(s, (struct sockaddr *)&amp;servaddr, sizeof(servaddr));

	<FONT COLOR=green>// Wait for a connection</FONT>
	listen(s, 50);

	while ((x = accept(s, NULL, 0)))
	{
		<FONT COLOR=green>// Pass the connection off to libcli</FONT>
		<A HREF="#cli_loop">cli_loop</A>(cli, x);
		close(x);
	}

	<FONT COLOR=green>// Free data structures</FONT>
	<A HREF="#cli_done">cli_done</A>(cli);

	return 0;
}
</PRE>
<P>
This code snippet is all that's required to enable a libcli
program.  However it's not yet compilable because we haven't created the
callback functions.
</P>

<P>
A few commands have been created:
<UL>
	<LI>test</LI>
	<LI>simple</LI>
	<LI>set</LI>
	<LI>show junk</LI>
	<LI>show counters</LI>
</UL>

<P>
<B>Note</B> that <EM>simon</EM> isn't on this list because <EM>callback</EM> was
NULL when it was registered, so the command will not be available.
</P>

<P>
Also, the standard libcli commands <EM>help</EM>, <EM>exit</EM>,
<EM>logout</EM>, <EM>quit</EM> and <EM>history</EM> are also available
automatically.
</P>

</LI>

<LI>
Make this program complete by adding the callback functions.
<PRE>
int cmd_test(struct cli_def *cli, char *command, char *argv[], int argc)
{
    <A HREF="#cli_print">cli_print</A>(cli, "called %s with %s\r\n", __FUNCTION__, command);
    return CLI_OK;
}

int cmd_set(struct cli_def *cli, char *command, char *argv[], int argc)
{
    if (argc &lt; 2)
    {
	<A HREF="#cli_print">cli_print</A>(cli, "Specify a variable to set\r\n");
	return CLI_OK;
    }
    <A HREF="#cli_print">cli_print</A>(cli, "Setting %s to %s\r\n", argv[0], argv[1]);
    return CLI_OK;
}
</PRE>

<P>
2 callback functions are defined here, <EM>cmd_test()</EM> and
<EM>cmd_set()</EM>.  <EM>cmd_test()</EM> is called by many of the
commands defined in the tutorial, although in reality you would
usually use a callback for a single command.
</P>

<P>
<EM>cmd_test()</EM> simply echos the command entered back to the
client.  Note that it shows the full expanded command, so you can enter
"<CODE>te</CODE>" at the prompt and it will print back "<CODE>called
with test</CODE>".
</P>

<P>
<EM>cmd_set</EM> handles the arguments given on the command line.  This
allows you to use a single callback to handle lots of arguments like:
<UL>
<LI>set colour green</LI>
<LI>set name David</LI>
<LI>set email "I don't have an e-mail address"</LI>
<LI>etc...</LI>
</UL>
</P>

</LI>

<LI>
Compile the code
<PRE>
gcc libclitest.c -o libclitest -lcli
</PRE>

You can now run the program with ./libclitest and telnet to port 12345
to see your work in action.

</LI>
</OL>

<H2><A NAME="funcref">4.0 Function Reference</A></H2>

<H3><A NAME="cli_init">4.1 cli_init()</A></H3>

<P>
This must be called before any other cli_<EM>xxx</EM> function.  It sets
up the internal data structures used for command-line processing.
</P>

<P>
Returns a <CODE>struct cli_def *</CODE> which must be passed to all
other cli_<EM>xxx</EM> functions.
</P>

<H3><A NAME="cli_done">4.2 cli_done(<EM>struct cli_def *cli</EM>)</A></H3>

<P>
This is optional, but it's a good idea to call this when you are finished
with libcli.  This frees memory used by libcli.
</P>

<H3><A NAME="cli_register_command">4.3 cli_register_command(<EM>struct cli_def *cli, struct cli_command *parent, char *command, int (*callback)(struct cli_def *, char *, char **, int), int privilege, int mode, char *help</EM>)</A></H3>

<P>
Add a command to the internal command tree.  Returns a <EM>struct
cli_command *</EM>, which you can pass as <EM>parent</EM> to another
call to <A HREF="#cli_register_command">cli_register_command()</A>.
</P>

<P>When the command has been entered by the user, <EM>callback</EM>
is checked.  If it is not NULL, then the callback is called with:</P>
<OL>
	<LI>struct cli_def * - the handle of the cli structure.  This
	    must be passed to all cli functions, including
	    <A HREF="#cli_print">cli_print()</A>.</LI>
	<LI>char * - the entire command which was entered.  This is after command
	expansion.</LI>
	<LI>char ** - the list of arguments entered</LI>
	<LI>int - the number of arguments entered</LI>
</OL>

<P>The callback must return <EM>CLI_OK</EM> if the command was successful,
<EM>CLI_ERROR</EM> if processing wasn't successful and the next matching
command should be tried (if any), or <EM>CLI_QUIT</EM> to drop the
connection (e.g. on a fatal error).</P>

<P>If <EM>parent</EM> is NULL, the command is added to the top level of
commands, otherwise it is a subcommand of <EM>parent</EM></P>

<P>
<EM>privilege</EM> should be set to either PRIVILEGE_PRIVILEGED or
PRIVILEGE_UNPRIVILEGED.  If set to PRIVILEGE_PRIVILEGED then the user must have
entered <EM>enable</EM> before running this command.
</P>

<P>
<EM>mode</EM> should be set to MODE_EXEC for no configuration mode, MODE_CONFIG
for generic configuration commands, or your own config level.  The user can enter
the generic configuration level by entering <EM>configure terminal</EM>, and can
return to MODE_EXEC by entering <EM>exit</EM> or <EM>CTRL-Z</EM>.  You can define
commands to enter your own configuration levels, which should call the
<A HREF="#cli_set_configmode">cli_set_configmode()</A> function.
</P>

<P>If <EM>help</EM> is provided, it is given to the user when the use
the <EM>help</EM> command or press <B>?</B>.</P>

<H3><A NAME="cli_unregister_command">4.4 cli_unregister_command(<EM>struct cli_def *cli, char *command</EM>)</A></H3>

<P>
Remove a command <EM>command</EM> and all children.  There is not provision
yet for removing commands at lower than the top level.
</P>

<H3><A NAME="cli_loop">4.5 cli_loop(<EM>struct cli_def *cli, int sockfd</EM>)</A></H3>

<P>
The main loop of the command-line environment.  This must be called with
the FD of a socket open for bi-directional communication (<EM>sockfd</EM>).
</P>

<P>
<A HREF="#cli_loop">cli_loop()</A> handles the telnet negotiation
and authentication.  It returns only when the connection is finished,
either by a server or client disconnect.
</P>

<P>
Returns <EM>CLI_OK</EM>.
</P>

<H3><A NAME="cli_set_auth_callback">4.6 cli_set_auth_callback(<EM>struct cli_def *cli, int (*auth_callback)(char *, char *)</EM>)</A></H3>

<P>
Enables or disables callback based authentication.
</P>

<P>If <EM>auth_callback</EM> is not NULL, then authentication will be
required on connection.  <EM>auth_callback</EM> will be called with the
<EM>username</EM> and <EM>password</EM> that the user enters.  </P>

<P><EM>auth_callback</EM> must return a non-zero value if authentication
is successful.  </P>

<P> If <EM>auth_callback</EM> is NULL, then callback based authentication
will be disabled.  </P>

<H3><A NAME="cli_allow_user">4.7 cli_allow_user(<EM>struct cli_def *cli, char *username, char *password</EM>)</A></H3>

<P> Enables internal authentication, and adds <EM>username/password</EM>
to the list of allowed users.  <P>

<P> The internal list of users will be checked before callback based
authentication is tried.  </P>

<H3><A NAME="cli_deny_user">4.8 cli_deny_user(<EM>struct cli_def *cli, char *username</EM>)</A></H3>

<P>
Removes <EM>username/password</EM> from the list of allowed users.
</P>

<P> If this is the last combination in the list, then internal
authentication will be disabled.</P>

<H3><A NAME="cli_set_banner">4.9 cli_set_banner(<EM>struct cli_def *cli, char *banner</EM>)</A></H3>

<P>
Sets the greeting that clients will be presented with when they
connect.  This may be a security warning for example.
</P>

<P>
If this function is not called or called with a NULL argument, no banner will be presented.
</P>

<H3><A NAME="cli_set_hostname">4.10 cli_set_hostname(<EM>struct cli_def *cli, char *hostname</EM>)</A></H3>

<P>
Sets the hostname to be displayed as the first part of the prompt.
</P>

<H3><A NAME="cli_regular">4.11 cli_regular(<EM>struct cli_def *cli, int(*callback)(struct cli_def *)</EM>)</A></H3>

<P>
Adds a callback function which will be called every second that a user
is connected to the cli.  This can be used for regular processing such
as debugging, time counting or implementing idle timeouts.
</P>

<P>
Pass NULL as the callback function to disable this at runtime.
</P>

<P>
If the callback function does not return CLI_OK, then the user will
be disconnected.
</P>

<H3><A NAME="cli_file">4.12 cli_file(<EM>struct cli_def *cli, FILE *f, int privilege, int mode</EM>)</A></H3>

<P>
This reads and processes every line read from <EM>f</EM> as if it were
entered at the console.  The privilege level will be set to <EM>privilege</EM>
and mode set to <EM>mode</EM> during the processing of the file.
</P>

<H3><A NAME="cli_print">4.13 cli_print(<EM>struct cli_def *cli, char *format, ...</EM>)</A></H3>

<P>
This function should be called for any output generated by a command
callback.
</P>

<P>
It takes a printf() style format string and a variable number of arguments.
</P>

<P>
Be aware that any output generated by cli_print will be passed through
any filter currently being applied, and the output will be redirected
to the <A HREF="#cli_print_callback">cli_print_callback()</A> if one has been
specified.
</P>

<H3><A NAME="cli_error">4.13 cli_error(<EM>struct cli_def *cli, char *format, ...</EM>)</A></H3>

<P>
A variant of <A HREF="#cli_print">cli_print()</A> which does not have
filters applied.  
</P>

<H3><A NAME="cli_print_callback">4.15 cli_print_callback(<EM>struct cli_def *cli, void (*callback)(struct cli_def *, char *)</EM>)</A></H3>

<P>
Whenever <A HREF="#cli_print">cli_print()</A> or <A HREF="#cli_error">cli_error()</A>
is called, the output generally goes to the user.  If you specify a
callback using this function, then the output will be sent to that
callback.  The function will be called once for each line, and it will
be passed a single null-terminated string, without any newline
characters.
</P>

<P>
Specifying NULL as the callback parameter will make libcli use the
default <A HREF="#cli_print">cli_print()</A> function.
</P>

<H3><A NAME="cli_set_enable_callback">4.16 cli_set_enable_callback(<EM>struct cli_def *cli, void (*callback)(struct cli_def *, char *)</EM>)</A></H3>

<P>
Just like <A HREF="#cli_set_auth_callback">cli_set_auth_callback</A> this takes a pointer to a callback
function to authorize privileged access.  However this callback only takes a
single string - the password.
</P>

<H3><A NAME="cli_allow_enable">4.17 cli_allow_enable(<EM>struct cli_def *cli, char *password</EM>)</A></H3>

<P>
This will allow a static password to be used for the <EM>enable</EM> command.
This static password will be checked before running any enable callbacks.
</P>

<P>
Set this to NULL to not have a static enable password.
</P>

<H3><A NAME="cli_set_configmode">4.18 cli_set_configmode(<EM>struct cli_def *cli, int mode, char *string</EM>)</A></H3>

<P>
This will set the configuration mode.  Once set, commands will be restricted to
only ones in the selected configuration mode, plus any set to MODE_ANY.
The previous mode value is returned.
</P>

<P>
The string passed will be used to build the prompt in the set configuration
mode.  e.g. if you set the string <B>test</B>, the prompt will become:
<PRE>
hostname(config-test)#
</PRE>
</P>

<SMALL>David Parrish &lt;david@dparrish.com&gt; 2004-06-25</SMALL>
</BODY>
</HTML>