convert-from-bsd-to-posix-string-and-memory-functions-20010807
[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 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     memset(gpbuf, 0, 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++) memset(zero_argv[i], 0, 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         memset(as->parms[aPASSWORD].items->data, 0, strlen(as->parms[aPASSWORD].items->data));
254     }
255
256     if (as->parms[aLIFETIME].items) {
257         char *life = as->parms[aLIFETIME].items->data;
258         char *sp;                       /* string ptr to rest of life */
259         lifetime = 3600*strtol (life, &sp, 0); /* hours */
260         if (sp == life) {
261 bad_lifetime:
262             if (!Silent) fprintf (stderr, "%s: translating '%s' to lifetime\n",
263                                rn, life);
264             return -1;
265         }
266         if (*sp == ':') {
267             life = sp+1;                /* skip the colon */
268             lifetime += 60*strtol (life, &sp, 0); /* minutes */
269             if (sp == life) goto bad_lifetime;
270             if (*sp == ':') {
271                 life = sp+1;
272                 lifetime += strtol (life, &sp, 0); /* seconds */
273                 if (sp == life) goto bad_lifetime;
274                 if (*sp) goto bad_lifetime;
275             } else if (*sp) goto bad_lifetime;
276         } else if (*sp) goto bad_lifetime;
277         if (lifetime > MAXKTCTICKETLIFETIME) {
278             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);
279             exit (1);
280         }
281     } else lifetime = 0;
282
283     if (as->parms[aREPCOUNT].items) {
284       reps = atoi(as->parms[aREPCOUNT].items->data);
285     }
286
287     if (!foundExplicitCell) strcpy (realm, lcell);
288     if (code = ka_CellToRealm (realm, realm, &local)) {
289         if (!Silent) com_err (rn, code, "Can't convert cell to realm");
290         exit (code);
291     }
292
293     /* Get the password if it wasn't provided. */
294     if (!foundPassword) {
295         if (Pipe) {
296             strncpy(passwd, getpipepass(), sizeof(passwd));
297         }
298         else {
299             if (ka_UserReadPassword
300                 ("Password:", passwd, sizeof(passwd), &reason)) {
301                 fprintf (stderr, "Unable to login because %s.\n", reason);
302                 exit (1);
303             }
304         }
305     }
306
307     if (explicit) ka_ExplicitCell (realm, serverList);
308
309     /* we really want this to fail repeatedly, though we only check one return
310      * code.  I hope it's representative...
311      */
312     for (i=0; i<reps; i++) {
313       code = ka_UserAuthenticateGeneral (KA_USERAUTH_VERSION, pw->pw_name,
314              instance, realm, passwd, lifetime, &password_expires, 0, &reason);
315       if (code)
316         storecode = code;
317     }
318     code = storecode;
319
320     memset(passwd, 0, sizeof(passwd));
321     if (code) {
322         if (!Silent) {
323             fprintf (stderr,
324                      "Unable to authenticate to AFS because %s.\n", reason);
325           }
326         exit (code);
327     }
328
329     if (writeTicketFile) {
330         code = krb_write_ticket_file (realm);
331         if (!Silent) {
332             if (code) 
333                 com_err (rn, code, "writing Kerberos ticket file");
334             else fprintf (stderr, "Wrote ticket file to /tmp\n");
335         }
336     }
337
338 #ifdef DEBUGEXPIRES
339        if (password_expires >= 0) {
340          printf ("password expires at %ld\n", password_expires);
341        }
342 #endif DEBUGEXPIRES
343
344     exit (0);
345 }