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
142int 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
208int 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
322int 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
396int 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}
410