chatchat stuff from gpk@onramp.net
[ppp.git] / scripts / chatchat / chatchat.c
1 /* ************************************************************************* 
2 * NAME: chatchat.c
3 *
4 * DESCRIPTION:
5 *
6 * This program creates a pipe for the chat process to read. The user
7 * can supply information (like a password) that will be picked up
8 * by chat and sent just like the regular contents of a chat script.
9 *
10 * Usage is:
11 *
12 * chatchat <filename>
13 *
14 *   where <filename> matches the option given in the chat script.
15 *
16 * for instance the chat script fragment:
17 *
18 *       ...
19 *        name:           \\dmyname  \
20 *        word:           @/var/tmp/p \
21 *       ...
22 *                                   ^
23 *                    (note: leave some whitespace after the filename)
24 *
25 * expect "name:", reply with a delay followed by "myname"
26 * expect "word:", reply with the data read from the pipe /var/tmp/p 
27 *
28 * the matching usage of chatchat would be:
29 *
30 * chatchat /var/tmp/p
31 *
32 * eg:
33 *
34 * $chatchat /var/tmp/p
35 * ...
36 *                           some other process eventually starts:
37 *                           chat ...
38 *                           chat parses the "@/var/tmp/p" option and opens
39 *                              /var/tmp/p
40 *  (chatchat prompts:)
41 *
42 * type PIN into SecurID card
43 *   enter resulting passcode: [user inputs something]
44 *
45 *                           chat reads /var/tmp/p & gets what the
46 *                              user typed at chatchat's "enter string" prompt
47 *                           chat removes the pipe file
48 *                           chat sends the user's input as a response in
49 *                              place of "@/var/tmp/p"
50 *                             
51 * PROCESS:
52 *
53 * gcc -g -o chatchat chatchat.c
54 *
55
56 * GLOBALS: none
57 *
58 * REFERENCES:
59 *
60 * see the man pages and documentation that come with the 'chat' program
61 * (part of the ppp package). you will need to use the modified chat
62 * program that accepts the '@' operator.
63 *
64 * LIMITATIONS:
65 *
66 * REVISION HISTORY:
67 *
68 *   STR                Description                          Author
69 *
70 *   23-Mar-99          initial coding                        gpk
71 *   12-May-99          unlink the pipe after closing         paulus
72 *
73 * TARGET: ANSI C
74 * This program is in the public domain.
75
76 *
77 * ************************************************************************* */
78
79
80
81
82 #include <sys/time.h>
83 #include <stdio.h>
84 #include <sys/types.h>
85 #include <sys/stat.h>
86 #include <fcntl.h>
87 #include <unistd.h>
88 #include <string.h>
89
90 /* MAXINPUT - the data typed into chatchat must be fewer   */
91 /* characters than this.                                 */
92
93 #define MAXINPUT 80
94
95
96
97
98
99
100 /* ************************************************************************* 
101
102
103    NAME:  main
104
105
106    USAGE: 
107
108    int argc;
109    char * argv[];
110
111    main(argc, argv[]);
112
113    returns: int
114
115    DESCRIPTION:
116                  if the pipe file name is given on the command line,
117                     create the pipe, prompt the user and put whatever
118                     is typed into the pipe.
119
120                  returns -1 on error
121                      else # characters entered
122    REFERENCES:
123
124    LIMITATIONS:
125
126    GLOBAL VARIABLES:
127
128       accessed: none
129
130       modified: none
131
132    FUNCTIONS CALLED:
133
134    REVISION HISTORY:
135
136         STR                  Description of Revision                 Author
137
138      25-Mar-99               initial coding                           gpk
139
140  ************************************************************************* */
141
142 int main(int argc, char * argv[])
143 {
144   int retval;
145   
146   int create_and_write_pipe(char * pipename);
147
148   if (argc != 2)
149     {
150       fprintf(stderr, "usage: %s pipename\n", argv[0]);
151       retval = -1;
152     }
153   else
154     {
155      retval =  create_and_write_pipe(argv[1]);
156     }
157   return (retval);
158 }
159
160
161
162
163 /* ************************************************************************* 
164
165
166    NAME:  create_and_write_pipe
167
168
169    USAGE: 
170
171    int some_int;
172    char * pipename;
173
174    some_int =  create_and_write_pipe(pipename);
175
176    returns: int
177
178    DESCRIPTION:
179                  given the pipename, create the pipe, open it,
180                  prompt the user for a string to put into the
181                  pipe, write the string, and close the pipe
182
183                  on error, print out an error message and return -1
184                  
185                  returns -1 on error
186                    else #bytes written into the pipe
187    REFERENCES:
188
189    LIMITATIONS:
190
191    GLOBAL VARIABLES: 
192
193       accessed: none
194
195       modified: none
196
197    FUNCTIONS CALLED:
198
199    REVISION HISTORY:
200
201         STR                  Description of Revision                 Author
202
203      25-Mar-99               initial coding                           gpk
204      12-May-99               remove pipe after closing               paulus
205
206  ************************************************************************* */
207
208 int create_and_write_pipe(char * pipename)
209 {
210   int retval, created, pipefd, nread, nwritten;
211   char input[MAXINPUT];
212   char errstring[180];
213   
214   int create_pipe(char * pipename);
215   int write_to_pipe(int pipefd, char * input, int nchar);
216
217   created = create_pipe(pipename);
218
219   if (-1 == created)
220     {
221       sprintf(errstring, "unable to create pipe '%s'", pipename);
222       perror(errstring);
223       retval = -1;
224     }
225   else
226     {
227
228       /* note: this open won't succeed until chat has the pipe  */
229       /* open and ready to read. this makes for nice timing.    */
230       
231       pipefd = open(pipename, O_WRONLY);
232
233       if (-1 == pipefd)
234         {
235           sprintf(errstring, "unable to open pipe '%s'", pipename);
236           perror(errstring);
237           retval =  -1;
238         }
239       else
240         {
241           fprintf(stderr, "%s \n %s",
242                   "type PIN into SecurID card and",
243                   "enter resulting passcode:");
244           nread = read(STDIN_FILENO, (void *)input, MAXINPUT);
245
246           
247           if (0 >= nread)
248             {
249               perror("unable to read from stdin");
250               retval = -1;
251             }
252           else
253             {
254               /* munch off the newline character, chat supplies  */
255               /* a return when it sends the string out.          */
256               input[nread -1] = 0;
257               nread--;
258               nwritten = write_to_pipe(pipefd, input, nread);
259               /* printf("wrote [%d]: '%s'\n", nwritten, input); */
260               retval = nwritten;
261             }
262           close(pipefd);
263
264           /* Now make the pipe go away.  It won't actually go away
265              completely until chat closes it. */
266           if (unlink(pipename) < 0)
267               perror("Warning: couldn't remove pipe");
268         }
269     }
270   return(retval);
271 }
272
273
274
275
276
277
278
279 /* ************************************************************************* 
280
281
282    NAME:  create_pipe
283
284
285    USAGE: 
286
287    int some_int;
288    char * pipename;
289    
290    some_int =  create_pipe(pipename);
291    
292    returns: int
293    
294    DESCRIPTION:
295                  create a pipe of the given name
296
297                  if there is an error (like the pipe already exists)
298                     print an error message and return
299                     
300                  return -1 on failure else success
301
302    REFERENCES:
303
304    LIMITATIONS:
305
306    GLOBAL VARIABLES:
307
308       accessed: none
309
310       modified: none
311
312    FUNCTIONS CALLED:
313
314    REVISION HISTORY:
315
316         STR                  Description of Revision                 Author
317
318      25-Mar-99               initial coding                           gpk
319
320  ************************************************************************* */
321
322 int create_pipe(char * pipename)
323 {
324   mode_t old_umask;
325   int created;
326
327   /* hijack the umask temporarily to get the mode I want  */
328   /* on the pipe.                                         */
329   
330   old_umask = umask(000);
331
332   created = mknod(pipename, S_IFIFO | S_IRWXU | S_IWGRP | S_IWOTH,
333                   (dev_t)NULL);
334
335   /* now restore umask.  */
336   
337   (void)umask(old_umask);
338   
339   if (-1 == created)
340     {
341       perror("unable to create pipe");
342     }
343
344   return(created);
345 }
346
347
348
349
350
351
352 /* ************************************************************************* 
353
354
355    NAME:  write_to_pipe
356
357
358    USAGE: 
359
360    int some_int;
361    int pipefd;
362    char * input;
363    int nchar;
364
365    some_int =  write_to_pipe(pipefd, input, nchar);
366
367    returns: int
368
369    DESCRIPTION:
370                  write nchars of data from input to pipefd
371
372                  on error print a message to stderr
373
374                  return -1 on error, else # bytes written
375    REFERENCES:
376
377    LIMITATIONS:
378
379    GLOBAL VARIABLES:
380
381       accessed: none
382
383       modified: none
384
385    FUNCTIONS CALLED:
386
387    REVISION HISTORY:
388
389         STR                  Description of Revision                 Author
390
391      25-Mar-99               initial coding                           gpk
392      12-May-99               don't write count word first             paulus
393
394  ************************************************************************* */
395
396 int write_to_pipe(int pipefd, char * input, int nchar)
397 {
398   int nwritten;
399
400   /* nwritten = write(pipefd, (void *)&nchar, sizeof(nchar)); */
401   nwritten = write(pipefd, (void *)input, nchar);
402
403   if (-1 == nwritten)
404     {
405       perror("unable to write to pipe");
406     }
407
408   return(nwritten);
409 }