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 <david@dparrish.com>.
</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 <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <libcli.h>
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, &on, sizeof(on));
<FONT COLOR=green>// Listen on port 12345</FONT>
memset(&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 *)&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 < 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 <david@dparrish.com> 2004-06-25</SMALL>
</BODY>
</HTML>
|