afsconfig-and-rcsid-all-around-20010705
[openafs.git] / src / kauth / test / multiklog.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /* this is a version of klog which attempts to authenticate many times
11  * in a loop.  It is a test program, and isn't really intended for general
12  * use. 
13  */
14
15 /* These two needed for rxgen output to work */
16
17 #include <afs/param.h>
18 #include <afsconfig.h>
19
20 RCSID("$Header$");
21
22 #include <afs/stds.h>
23 #include <sys/types.h>
24 #include <rx/xdr.h>
25
26 #include <lock.h>
27 #include <ubik.h>
28
29 #include <stdio.h>
30 #include <pwd.h>
31 #include <afs/com_err.h>
32 #include <afs/auth.h>
33 #include <afs/cellconfig.h>
34 #include <afs/cmd.h>
35 #include "kauth.h"
36 #include "kautils.h"
37
38 /* Current Usage:
39      mutliklog [principal [password]] [-t] [-c cellname] [-servers <hostlist>] [-number n]
40
41      where:
42        principal is of the form 'name' or 'name@cell' which provides the
43           cellname.  See the -c option below.
44        password is the user's password.  This form is NOT recommended for
45           interactive users.
46        -t advises klog to write a Kerberos style ticket file in /tmp.
47        -c identifies cellname as the cell in which authentication is to take
48           place.
49        -servers allows the explicit specification of the hosts providing
50           authentication services for the cell being used for authentication.
51           This is a debugging option and will disappear.
52        -repeat is the number of times to iterate over the authentication
53  */
54
55 int CommandProc();
56
57 static int zero_argc;
58 static char **zero_argv;
59
60 int osi_audit()
61 {
62 /* this sucks but it works for now.
63 */
64 return 0;
65 }
66
67 main (argc, argv)
68   int   argc;
69   char *argv[];
70 {   struct cmd_syndesc *ts;
71     long code;
72
73     zero_argc = argc;
74     zero_argv = argv;
75
76     ts = cmd_CreateSyntax((char *) 0, CommandProc, 0, "obtain Kerberos authentication");
77
78 #define aXFLAG 0
79 #define aPRINCIPAL 1
80 #define aPASSWORD 2
81 #define aTMP 3
82 #define aCELL 4
83 #define aSERVERS 5
84 #define aPIPE 6
85 #define aSILENT 7
86 #define aLIFETIME 8
87 #define aREPCOUNT 9
88
89     cmd_AddParm(ts, "-x", CMD_FLAG, CMD_OPTIONAL, "(obsolete, noop)");
90     cmd_Seek(ts, aPRINCIPAL);
91     cmd_AddParm(ts, "-principal", CMD_SINGLE, CMD_OPTIONAL, "user name");
92     cmd_AddParm(ts, "-password", CMD_SINGLE, CMD_OPTIONAL, "user's password");
93     cmd_AddParm(ts, "-tmp", CMD_FLAG, CMD_OPTIONAL, "write Kerberos-style ticket file in /tmp");
94     cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell name");
95     cmd_AddParm(ts, "-servers", CMD_LIST, CMD_OPTIONAL, "explicit list of servers");
96     cmd_AddParm(ts, "-pipe", CMD_FLAG, CMD_OPTIONAL, "read password from stdin");
97     cmd_AddParm(ts, "-silent", CMD_FLAG, CMD_OPTIONAL, "silent operation");
98     cmd_AddParm(ts, "-lifetime", CMD_SINGLE, CMD_OPTIONAL, "ticket lifetime in hh[:mm[:ss]]");
99     cmd_AddParm(ts, "-repeat", CMD_SINGLE, CMD_OPTIONAL, "number of times to repeat authentication");
100
101     code = cmd_Dispatch(argc, argv);
102     exit(code);
103 }
104
105 extern struct passwd *getpwuid();
106
107 static char *getpipepass() {
108     static char gpbuf[BUFSIZ];
109     /* read a password from stdin, stop on \n or eof */
110     register int i, tc;
111     bzero(gpbuf, sizeof(gpbuf));
112     for(i=0; i<(sizeof(gpbuf)-1); i++) {
113         tc = fgetc(stdin);
114         if (tc == '\n' || tc == EOF) break;
115         gpbuf[i] = tc;
116     }
117     return gpbuf;
118 }
119
120 CommandProc (as, arock)
121   char *arock;
122   struct cmd_syndesc *as;
123 {
124     char  name[MAXKTCNAMELEN];
125     char  instance[MAXKTCNAMELEN];
126     char  cell[MAXKTCREALMLEN];
127     char  realm[MAXKTCREALMLEN];
128     long  serverList[MAXSERVERS];
129     char *lcell;                        /* local cellname */
130     char  lrealm[MAXKTCREALMLEN];       /* uppercase copy of local cellname */
131     int   code;
132     int   i;
133     Date  lifetime;                     /* requested ticket lifetime */
134
135     struct passwd pwent;
136     struct passwd *pw = &pwent;
137     struct passwd *lclpw = &pwent;
138     char passwd[BUFSIZ];
139
140     static char rn[] = "klog";          /*Routine name*/
141     static int Pipe = 0;                /* reading from a pipe */
142     static int Silent = 0;              /* Don't want error messages */
143     static int reps = 1;
144     static long storecode = 0;          /* hold a non-zero error code, if any */
145
146     int explicit;                       /* servers specified explicitly */
147     int local;                          /* explicit cell is same a local one */
148     int foundPassword = 0;              /*Not yet, anyway*/
149     int foundExplicitCell = 0;          /*Not yet, anyway*/
150     int writeTicketFile = 0;            /* write ticket file to /tmp */
151     long password_expires = -1;
152
153     char *reason;                       /* string describing errors */
154
155     /* blow away command line arguments */
156     for (i=1; i<zero_argc; i++) bzero (zero_argv[i], strlen(zero_argv[i]));
157     zero_argc = 0;
158
159     /* first determine quiet flag based on -silent switch */
160     Silent = (as->parms[aSILENT].items ? 1 : 0);
161     Pipe = (as->parms[aPIPE].items ? 1 : 0);
162
163     code = ka_Init(0);
164     if (code ||
165         !(lcell = ka_LocalCell())) {
166       nocell:
167         if (!Silent) 
168            com_err (rn, code, "Can't get local cell name!");
169         exit (code);
170     }
171     if (code = ka_CellToRealm (lcell, lrealm, 0)) goto nocell;
172
173     strcpy (instance, "");
174
175     /* Parse our arguments. */
176
177     if (as->parms[aTMP].items) {
178         writeTicketFile = 1;
179     }
180
181     if (as->parms[aCELL].items) {
182         /*
183          * cell name explicitly mentioned; take it in if no other cell name
184          * has already been specified and if the name actually appears.  If
185          * the given cell name differs from our own, we don't do a lookup.
186          */
187         foundExplicitCell = 1;
188         strncpy (realm, as->parms[aCELL].items->data, sizeof(realm));
189     }
190
191     if (as->parms[aSERVERS].items) {
192         /* explicit server list */
193         int i;
194         struct cmd_item *ip;
195         char *ap[MAXSERVERS+2];
196
197         for (ip = as->parms[aSERVERS].items, i=2; ip; ip=ip->next, i++)
198             ap[i] = ip->data;
199         ap[0] = "";
200         ap[1] = "-servers";
201         code = ubik_ParseClientList(i, ap, serverList);
202         if (code) {
203             if (!Silent) {
204                com_err (rn, code, "could not parse server list");
205              }
206             return code;
207         }
208         explicit = 1;
209     } else explicit = 0;
210
211     if (as->parms[aPRINCIPAL].items) {
212         ka_ParseLoginName (as->parms[aPRINCIPAL].items->data,
213                            name, instance, cell);
214         if (strlen (instance) > 0)
215             if (!Silent) {
216                 fprintf (stderr, 
217                          "Non-null instance (%s) may cause strange behavior.\n",
218                          instance);
219               }
220         if (strlen(cell) > 0) {
221             if (foundExplicitCell) {
222                 if (!Silent) {
223                     fprintf (stderr, 
224                           "%s: May not specify an explicit cell twice.\n", rn);
225                   }
226                 return -1;
227             }
228             foundExplicitCell = 1;
229             strncpy (realm, cell, sizeof(realm));
230         }
231         lclpw->pw_name = name;
232     } else {
233         /* No explicit name provided: use Unix uid. */
234         pw = getpwuid(getuid());
235         if (pw == 0) {
236             if (!Silent) {
237                 fprintf (stderr, "Can't figure out your name in local cell %s from your user id.\n", lcell);
238                 fprintf (stderr, "Try providing the user name.\n");
239             }
240             exit (1);
241         }
242         lclpw = pw;
243     }
244
245     if (as->parms[aPASSWORD].items) {
246         /*
247          * Current argument is the desired password string.  Remember it in
248          * our local buffer, and zero out the argument string - anyone can
249          * see it there with ps!
250          */
251         foundPassword = 1;
252         strncpy (passwd, as->parms[aPASSWORD].items->data, sizeof(passwd));
253         bzero (as->parms[aPASSWORD].items->data,
254                strlen(as->parms[aPASSWORD].items->data));
255     }
256
257     if (as->parms[aLIFETIME].items) {
258         char *life = as->parms[aLIFETIME].items->data;
259         char *sp;                       /* string ptr to rest of life */
260         lifetime = 3600*strtol (life, &sp, 0); /* hours */
261         if (sp == life) {
262 bad_lifetime:
263             if (!Silent) fprintf (stderr, "%s: translating '%s' to lifetime\n",
264                                rn, life);
265             return -1;
266         }
267         if (*sp == ':') {
268             life = sp+1;                /* skip the colon */
269             lifetime += 60*strtol (life, &sp, 0); /* minutes */
270             if (sp == life) goto bad_lifetime;
271             if (*sp == ':') {
272                 life = sp+1;
273                 lifetime += strtol (life, &sp, 0); /* seconds */
274                 if (sp == life) goto bad_lifetime;
275                 if (*sp) goto bad_lifetime;
276             } else if (*sp) goto bad_lifetime;
277         } else if (*sp) goto bad_lifetime;
278         if (lifetime > MAXKTCTICKETLIFETIME) {
279             if (!Silent) fprintf (stderr, "%s: a lifetime of %.2f hours is too long, must be less than %d.\n", rn, (double)lifetime/3600.0, MAXKTCTICKETLIFETIME/3600);
280             exit (1);
281         }
282     } else lifetime = 0;
283
284     if (as->parms[aREPCOUNT].items) {
285       reps = atoi(as->parms[aREPCOUNT].items->data);
286     }
287
288     if (!foundExplicitCell) strcpy (realm, lcell);
289     if (code = ka_CellToRealm (realm, realm, &local)) {
290         if (!Silent) com_err (rn, code, "Can't convert cell to realm");
291         exit (code);
292     }
293
294     /* Get the password if it wasn't provided. */
295     if (!foundPassword) {
296         if (Pipe) {
297             strncpy(passwd, getpipepass(), sizeof(passwd));
298         }
299         else {
300             if (ka_UserReadPassword
301                 ("Password:", passwd, sizeof(passwd), &reason)) {
302                 fprintf (stderr, "Unable to login because %s.\n", reason);
303                 exit (1);
304             }
305         }
306     }
307
308     if (explicit) ka_ExplicitCell (realm, serverList);
309
310     /* we really want this to fail repeatedly, though we only check one return
311      * code.  I hope it's representative...
312      */
313     for (i=0; i<reps; i++) {
314       code = ka_UserAuthenticateGeneral (KA_USERAUTH_VERSION, pw->pw_name,
315              instance, realm, passwd, lifetime, &password_expires, 0, &reason);
316       if (code)
317         storecode = code;
318     }
319     code = storecode;
320
321     bzero (passwd, sizeof(passwd));
322     if (code) {
323         if (!Silent) {
324             fprintf (stderr,
325                      "Unable to authenticate to AFS because %s.\n", reason);
326           }
327         exit (code);
328     }
329
330     if (writeTicketFile) {
331         code = krb_write_ticket_file (realm);
332         if (!Silent) {
333             if (code) 
334                 com_err (rn, code, "writing Kerberos ticket file");
335             else fprintf (stderr, "Wrote ticket file to /tmp\n");
336         }
337     }
338
339 #ifdef DEBUGEXPIRES
340        if (password_expires >= 0) {
341          printf ("password expires at %ld\n", password_expires);
342        }
343 #endif DEBUGEXPIRES
344
345     exit (0);
346 }