2 * Copyright 2000, International Business Machines Corporation and others.
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
11 * Revision 2.6 1991/04/15 10:44:53
12 * Initialize "explicit" local variable in false case.
14 * Revision 2.5 90/10/02 15:48:55
15 * Change -x parm to CMD_FLAG.
17 * Revision 2.4 90/10/01 11:28:01
18 * Cleaups for HC compiler.
19 * Add the -x option back as a noop for existing programs/scripts.
21 * Revision 2.3 90/09/26 14:19:23
22 * Remove support for -x option. This controlled checking the /etc/passwd file.
23 * We no longer do this under an circumstances.
25 * Revision 2.2 90/08/09 08:41:24
26 * Check for lifetimes longer than 30 days and reject them. Otherwise such
27 * bogus lifetimes make the kaserver think the password is wrong.
29 * Revision 2.1 90/08/07 19:11:58
30 * Start with clean version to sync test and dev trees.
33 /* These two needed for rxgen output to work */
34 #include <afs/param.h>
36 #include <sys/types.h>
47 #include <afs/com_err.h>
49 #include <afs/cellconfig.h>
56 /* This code borrowed heavily from the previous version of log. Here is the
57 intro comment for that program: */
60 log -- tell the Andrew Cache Manager your password
62 modified February 1986
64 Further modified in August 1987 to understand cell IDs.
68 klog [principal [password]] [-t] [-c cellname] [-servers <hostlist>]
71 principal is of the form 'name' or 'name@cell' which provides the
72 cellname. See the -c option below.
73 password is the user's password. This form is NOT recommended for
75 -t advises klog to write a Kerberos style ticket file in /tmp.
76 -c identifies cellname as the cell in which authentication is to take
78 -servers allows the explicit specification of the hosts providing
79 authentication services for the cell being used for authentication.
82 #define KLOGEXIT(code) assert(!code || code >= KAMINERROR); \
84 (!code ? exit(0) : exit((code)-KAMINERROR+1))
88 static char **zero_argv;
98 { struct cmd_syndesc *ts;
102 * The following signal action for AIX is necessary so that in case of a
103 * crash (i.e. core is generated) we can include the user's data section
104 * in the core dump. Unfortunately, by default, only a partial core is
105 * generated which, in many cases, isn't too useful.
107 struct sigaction nsa;
109 sigemptyset(&nsa.sa_mask);
110 nsa.sa_handler = SIG_DFL;
111 nsa.sa_flags = SA_FULLDUMP;
112 sigaction(SIGSEGV, &nsa, NULL);
117 ts = cmd_CreateSyntax((char *) 0, CommandProc, 0, "obtain Kerberos authentication");
131 cmd_AddParm(ts, "-x", CMD_FLAG, CMD_OPTIONAL, "(obsolete, noop)");
132 cmd_Seek(ts, aPRINCIPAL);
133 cmd_AddParm(ts, "-principal", CMD_SINGLE, CMD_OPTIONAL, "user name");
134 cmd_AddParm(ts, "-password", CMD_SINGLE, CMD_OPTIONAL, "user's password");
135 cmd_AddParm(ts, "-tmp", CMD_FLAG, CMD_OPTIONAL, "write Kerberos-style ticket file in /tmp");
136 cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell name");
137 cmd_AddParm(ts, "-servers", CMD_LIST, CMD_OPTIONAL, "explicit list of servers");
138 cmd_AddParm(ts, "-pipe", CMD_FLAG, CMD_OPTIONAL, "read password from stdin");
139 cmd_AddParm(ts, "-silent", CMD_FLAG, CMD_OPTIONAL, "silent operation");
140 cmd_AddParm(ts, "-lifetime", CMD_SINGLE, CMD_OPTIONAL, "ticket lifetime in hh[:mm[:ss]]");
141 cmd_AddParm(ts, "-setpag", CMD_FLAG, CMD_OPTIONAL, "Create a new setpag before authenticating");
142 cmd_AddParm(ts, "-names", CMD_LIST, CMD_OPTIONAL, "multiple user names");
144 code = cmd_Dispatch(argc, argv);
148 extern struct passwd *getpwuid();
150 static char *getpipepass() {
151 static char gpbuf[BUFSIZ];
152 /* read a password from stdin, stop on \n or eof */
154 bzero(gpbuf, sizeof(gpbuf));
155 for(i=0; i<(sizeof(gpbuf)-1); i++) {
157 if (tc == '\n' || tc == EOF) break;
163 CommandProc (as, arock)
165 struct cmd_syndesc *as;
167 char name[MAXKTCNAMELEN];
168 char instance[MAXKTCNAMELEN];
169 char cell[MAXKTCREALMLEN];
170 char realm[MAXKTCREALMLEN];
171 afs_int32 serverList[MAXSERVERS];
172 char *lcell; /* local cellname */
173 char lrealm[MAXKTCREALMLEN]; /* uppercase copy of local cellname */
176 Date lifetime; /* requested ticket lifetime */
179 struct passwd *pw = &pwent;
180 struct passwd *lclpw = &pwent;
183 static char rn[] = "klog"; /*Routine name*/
184 static int Pipe = 0; /* reading from a pipe */
185 static int Silent = 0; /* Don't want error messages */
187 int explicit; /* servers specified explicitly */
188 int local; /* explicit cell is same a local one */
189 int foundPassword = 0; /*Not yet, anyway*/
190 int foundExplicitCell = 0; /*Not yet, anyway*/
191 int writeTicketFile = 0; /* write ticket file to /tmp */
192 afs_int32 password_expires = -1;
194 char *reason; /* string describing errors */
196 /* blow away command line arguments */
197 for (i=1; i<zero_argc; i++) bzero (zero_argv[i], strlen(zero_argv[i]));
200 /* first determine quiet flag based on -silent switch */
201 Silent = (as->parms[aSILENT].items ? 1 : 0);
202 Pipe = (as->parms[aPIPE].items ? 1 : 0);
204 /* Determine if we should also do a setpag based on -setpag switch */
205 dosetpag = (as->parms[aSETPAG].items ? 1 : 0);
207 if (as->parms[aCELL].items) {
209 * cell name explicitly mentioned; take it in if no other cell name
210 * has already been specified and if the name actually appears. If
211 * the given cell name differs from our own, we don't do a lookup.
213 foundExplicitCell = 1;
214 strncpy (realm, as->parms[aCELL].items->data, sizeof(realm));
215 /* XXX the following is just a hack to handle the afscell environment XXX */
216 (void) afsconf_GetCellInfo((struct afsconf_dir *)0, realm, 0, (struct afsconf_cell *)0);
221 !(lcell = ka_LocalCell())) {
224 com_err (rn, code, "Can't get local cell name!");
227 if (code = ka_CellToRealm (lcell, lrealm, 0)) goto nocell;
229 strcpy (instance, "");
231 /* Parse our arguments. */
233 if (as->parms[aTMP].items) {
237 if (as->parms[aCELL].items) {
239 * cell name explicitly mentioned; take it in if no other cell name
240 * has already been specified and if the name actually appears. If
241 * the given cell name differs from our own, we don't do a lookup.
243 foundExplicitCell = 1;
244 strncpy (realm, as->parms[aCELL].items->data, sizeof(realm));
247 if (as->parms[aSERVERS].items) {
248 /* explicit server list */
251 char *ap[MAXSERVERS+2];
253 for (ip = as->parms[aSERVERS].items, i=2; ip; ip=ip->next, i++)
257 code = ubik_ParseClientList(i, ap, serverList);
260 com_err (rn, code, "could not parse server list");
267 if (as->parms[aPRINCIPAL].items) {
268 ka_ParseLoginName (as->parms[aPRINCIPAL].items->data,
269 name, instance, cell);
270 if (strlen (instance) > 0)
273 "Non-null instance (%s) may cause strange behavior.\n",
276 if (strlen(cell) > 0) {
277 if (foundExplicitCell) {
280 "%s: May not specify an explicit cell twice.\n", rn);
284 foundExplicitCell = 1;
285 strncpy (realm, cell, sizeof(realm));
287 lclpw->pw_name = name;
289 /* No explicit name provided: use Unix uid. */
290 pw = getpwuid(getuid());
293 fprintf (stderr, "Can't figure out your name in local cell %s from your user id.\n", lcell);
294 fprintf (stderr, "Try providing the user name.\n");
296 KLOGEXIT( KABADARGUMENT );
301 if (as->parms[aPASSWORD].items) {
303 * Current argument is the desired password string. Remember it in
304 * our local buffer, and zero out the argument string - anyone can
305 * see it there with ps!
308 strncpy (passwd, as->parms[aPASSWORD].items->data, sizeof(passwd));
309 bzero (as->parms[aPASSWORD].items->data,
310 strlen(as->parms[aPASSWORD].items->data));
313 if (as->parms[aLIFETIME].items) {
314 char *life = as->parms[aLIFETIME].items->data;
315 char *sp; /* string ptr to rest of life */
316 lifetime = 3600*strtol (life, &sp, 0); /* hours */
319 if (!Silent) fprintf (stderr, "%s: translating '%s' to lifetime\n",
324 life = sp+1; /* skip the colon */
325 lifetime += 60*strtol (life, &sp, 0); /* minutes */
326 if (sp == life) goto bad_lifetime;
329 lifetime += strtol (life, &sp, 0); /* seconds */
330 if (sp == life) goto bad_lifetime;
331 if (*sp) goto bad_lifetime;
332 } else if (*sp) goto bad_lifetime;
333 } else if (*sp) goto bad_lifetime;
334 if (lifetime > MAXKTCTICKETLIFETIME) {
335 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);
336 KLOGEXIT( KABADARGUMENT );
340 if (!foundExplicitCell) strcpy (realm, lcell);
341 if (code = ka_CellToRealm (realm, realm, &local)) {
342 if (!Silent) com_err (rn, code, "Can't convert cell to realm");
346 /* Get the password if it wasn't provided. */
347 if (!foundPassword) {
349 strncpy(passwd, getpipepass(), sizeof(passwd));
352 if (ka_UserReadPassword
353 ("Password:", passwd, sizeof(passwd), &reason)) {
354 fprintf (stderr, "Unable to login because %s.\n", reason);
355 KLOGEXIT( KABADARGUMENT );
360 if (explicit) ka_ExplicitCell (realm, serverList);
362 for (itp = as->parms[aNAMES].items; itp; itp = itp->next) {
363 *name = *instance = *cell = '\0';
364 ka_ParseLoginName (itp->data, name, instance, cell);
365 if (strlen(cell) > 0) {
366 foundExplicitCell = 1;
367 strncpy (realm, cell, sizeof(realm));
370 code = ka_UserAuthenticateGeneral (KA_USERAUTH_VERSION +
371 (dosetpag ? KA_USERAUTH_DOSETPAG2:0),
372 name, instance, realm, passwd, lifetime,
373 &password_expires, 0, &reason);
377 "Unable to authenticate to AFS because %s.\n", reason);
382 if (password_expires >= 0) {
383 printf ("password expires at %ld\n", password_expires);