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
10 #include <afsconfig.h>
11 #include <afs/param.h>
18 #include <afs/kautils.h>
19 #include <afs/dirpath.h>
20 #include "cm_config.h"
24 #define AFS_KERBEROS_ENV
26 #define BAD_ARGUMENT 1
27 #define KLOGEXIT(code) exit(code)
29 static int CommandProc(struct cmd_syndesc *, void *);
32 static char **zero_argv;
34 void main (argc, argv)
37 { struct cmd_syndesc *ts;
44 /* Start up sockets */
45 WSAStartup(0x0101, &WSAjunk);
47 ts = cmd_CreateSyntax(NULL, CommandProc, NULL, "obtain Kerberos authentication");
61 cmd_AddParm(ts, "-x", CMD_FLAG, CMD_OPTIONAL, "(obsolete, noop)");
62 cmd_Seek(ts, aPRINCIPAL);
63 cmd_AddParm(ts, "-principal", CMD_SINGLE, CMD_OPTIONAL, "user name");
64 cmd_AddParm(ts, "-password", CMD_SINGLE, CMD_OPTIONAL, "user's password");
65 cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell name");
66 cmd_AddParm(ts, "-servers", CMD_LIST, CMD_OPTIONAL, "explicit list of servers");
67 cmd_AddParm(ts, "-pipe", CMD_FLAG, CMD_OPTIONAL, "read password from stdin");
68 cmd_AddParm(ts, "-silent", CMD_FLAG, CMD_OPTIONAL, "silent operation");
69 cmd_AddParm(ts, "-lifetime", CMD_SINGLE, CMD_OPTIONAL, "ticket lifetime in hh[:mm[:ss]]");
70 cmd_AddParm(ts, "-setpag", CMD_FLAG, CMD_OPTIONAL, "Create a new setpag before authenticating");
71 cmd_AddParm(ts, "-tmp", CMD_FLAG, CMD_OPTIONAL, "write Kerberos-style ticket file in /tmp");
73 code = cmd_Dispatch(argc, argv);
77 static char *getpipepass() {
78 static char gpbuf[BUFSIZ];
79 /* read a password from stdin, stop on \n or eof */
81 memset(gpbuf, 0, sizeof(gpbuf));
82 for(i=0; i<(sizeof(gpbuf)-1); i++) {
84 if (tc == '\n' || tc == EOF) break;
90 /* good_gets is like gets except that it take a max string length and won't
91 * write past the end of its input buffer. It returns a variety of negative
92 * numbers in case of errors and zero if there was no characters read (a blank
93 * line for instance). Otherwise it returns the length of the string read in.
96 static int good_gets (s, max)
99 { int l; /* length of string read */
100 if (!fgets (s, max, stdin)) {
101 if (feof(stdin)) return EOF; /* EOF on input, nothing read */
102 else return -2; /* I don't think this can happen */
105 if (l && (s[l-1] == '\n')) s[--l] = 0;
109 static int read_pw_string(char *s, int max)
116 h = GetStdHandle (STD_INPUT_HANDLE);
117 GetConsoleMode (h, &md);
118 SetConsoleMode (h, md & ~ENABLE_ECHO_INPUT);
123 if (good_gets(s, max) <= 0) {
124 printf("\n"); fflush(stdout);
125 if (feof (stdin)) break; /* just give up */
126 else continue; /* try again: blank line */
135 SetConsoleMode (h, md);
136 printf("\n"); fflush(stdout);
138 s[max-1] = 0; /* force termination */
143 CommandProc (struct cmd_syndesc *as, void *arock)
145 char name[MAXKTCNAMELEN];
146 char instance[MAXKTCNAMELEN];
147 char cell[MAXKTCREALMLEN];
148 char defaultCell[256];
149 char realm[MAXKTCREALMLEN];
152 int lifetime; /* requested ticket lifetime */
156 static char rn[] = "klog"; /*Routine name*/
157 static int Pipe = 0; /* reading from a pipe */
158 static int Silent = 0; /* Don't want error messages */
160 int foundPassword = 0; /*Not yet, anyway*/
161 int foundExplicitCell = 0; /*Not yet, anyway*/
162 int writeTicketFile = 0; /* write ticket file to /tmp */
163 int password_expires = -1;
165 char *reason; /* string describing errors */
172 /* blow away command line arguments */
173 for (i=1; i<zero_argc; i++) memset (zero_argv[i], 0, strlen(zero_argv[i]));
176 /* first determine quiet flag based on -silent switch */
177 Silent = (as->parms[aSILENT].items ? 1 : 0);
178 Pipe = (as->parms[aPIPE].items ? 1 : 0);
180 /* Determine if we should also do a setpag based on -setpag switch */
181 dosetpag = (as->parms[aSETPAG].items ? 1 : 0);
183 if (as->parms[aTMP].items) {
187 cm_GetRootCellName(defaultCell);
190 /* Parse our arguments. */
192 if (as->parms[aCELL].items) {
194 * cell name explicitly mentioned; take it in if no other cell name
195 * has already been specified and if the name actually appears. If
196 * the given cell name differs from our own, we don't do a lookup.
198 foundExplicitCell = 1;
199 if (strlen(as->parms[aCELL].items->data) >= sizeof(realm)) {
202 "Cell name too long - maximum length is %d\n",
206 strncpy (realm, as->parms[aCELL].items->data, sizeof(realm));
207 realm[sizeof(realm) - 1] = '\0';
210 if (as->parms[aSERVERS].items) {
211 fprintf (stderr, "SERVERS option not available.\n");
214 if (as->parms[aPRINCIPAL].items) {
215 ka_ParseLoginName (as->parms[aPRINCIPAL].items->data,
216 name, instance, cell);
217 if (strlen (instance) > 0)
220 "Non-null instance (%s) may cause strange behavior.\n",
223 if (strlen(cell) > 0) {
224 if (foundExplicitCell) {
227 "%s: May not specify an explicit cell twice.\n", rn);
231 foundExplicitCell = 1;
232 if (strlen(cell) >= sizeof(realm)) {
235 "Cell too long - maximum length is %d\n",
239 strncpy (realm, cell, sizeof(realm));
240 realm[sizeof(realm) - 1] = '\0';
243 /* No explicit name provided. */
244 DWORD size = GetEnvironmentVariable("USERNAME", name, sizeof(name) - 1);
245 if (size <= 0 || size >= sizeof(name)) {
246 size = sizeof(name) - 1;
247 if (!GetUserName(name, &size)) {
248 KLOGEXIT( BAD_ARGUMENT );
253 if (as->parms[aPASSWORD].items) {
255 * Current argument is the desired password string. Remember it in
256 * our local buffer, and zero out the argument string - anyone can
257 * see it there with ps!
260 if (strlen(as->parms[aPASSWORD].items->data) >= sizeof(passwd)) {
263 "Password too long - maximum length is %d\n",
267 strncpy (passwd, as->parms[aPASSWORD].items->data, sizeof(passwd));
268 passwd[sizeof(passwd) - 1] = '\0';
269 memset (as->parms[aPASSWORD].items->data, 0,
270 strlen(as->parms[aPASSWORD].items->data));
273 if (as->parms[aLIFETIME].items) {
274 char *life = as->parms[aLIFETIME].items->data;
275 char *sp; /* string ptr to rest of life */
276 lifetime = 3600*strtol (life, &sp, 0); /* hours */
279 if (!Silent) fprintf (stderr, "%s: translating '%s' to lifetime failed\n",
284 life = sp+1; /* skip the colon */
285 lifetime += 60*strtol (life, &sp, 0); /* minutes */
286 if (sp == life) goto bad_lifetime;
289 lifetime += strtol (life, &sp, 0); /* seconds */
290 if (sp == life) goto bad_lifetime;
291 if (*sp) goto bad_lifetime;
292 } else if (*sp) goto bad_lifetime;
293 } else if (*sp) goto bad_lifetime;
294 if (lifetime > MAXKTCTICKETLIFETIME) {
297 "%s: a lifetime of %.2f hours is too long, must be less than %d.\n",
298 rn, (double)lifetime/3600.0, MAXKTCTICKETLIFETIME/3600);
299 KLOGEXIT( BAD_ARGUMENT );
303 if (!foundExplicitCell) strcpy (realm, defaultCell);
305 /* Get the password if it wasn't provided. */
306 if (!foundPassword) {
308 strncpy(passwd, getpipepass(), sizeof(passwd));
311 if (read_pw_string(passwd, sizeof(passwd)))
312 reason = "can't read password from terminal";
313 else if (strlen(passwd) == 0)
314 reason = "zero length password is illegal";
318 fprintf (stderr, "Unable to login because %s.\n", reason);
319 KLOGEXIT( BAD_ARGUMENT );
324 code = ka_UserAuthenticateGeneral (KA_USERAUTH_VERSION,
325 name, instance, realm, passwd, lifetime,
326 &password_expires, 0, &reason);
327 memset (passwd, 0, sizeof(passwd));
331 "Unable to authenticate to AFS because %s.\n", reason);
336 #ifndef AFS_KERBEROS_ENV
337 if (writeTicketFile) {
338 code = krb_write_ticket_file (realm);
341 afs_com_err (rn, code, "writing Kerberos ticket file");
342 else fprintf (stderr, "Wrote ticket file to /tmp\n");
348 if (password_expires >= 0) {
349 printf ("password expires at %ld\n", password_expires);
351 #endif /* DEBUGEXPIRES */