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