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