include-afsconfig-before-param-h-20010712
[openafs.git] / src / sia / siad.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 /* AFS SIA mechanism library. 
11  *
12  */
13
14 #include <afsconfig.h>
15 #include <afs/param.h>
16
17 RCSID("$Header$");
18
19 #include <afs/stds.h>
20 #include <sys/types.h>
21 #include <rx/xdr.h>
22 #include <lock.h>
23
24 #include <stdio.h>
25 #include <pwd.h>
26 #include <afs/com_err.h>
27 #include <afs/auth.h>
28 #include <afs/cellconfig.h>
29 #include <afs/cmd.h>
30 #include <afs/kautils.h>
31
32 #include <sia.h>
33 #include <siad.h>
34 #include <stdarg.h>
35
36
37 /* afs_sia_log logs to the standard sialog. */
38 static void
39 afs_sia_log(char *fmt, ...)
40 {
41     va_list args;
42     va_start(args, fmt);
43     sia_log("AFS", fmt, args);
44     va_end(args);
45 }
46
47 #if defined(AFS_KERBEROS_ENV)
48 extern char *ktc_tkt_string();
49 #endif
50
51 /* afs_siad_debug gives more detailed debugging information for AFS 
52  * than I want to put into the regular sialog.
53  */
54 #include <sys/stat.h>
55 #include <time.h>
56 #define DEBUG_FILE "/var/adm/afssialog"
57 /* Modify VERS to ensure you're testing with the current libafssiad.so.
58  * To make SIA recognize a new library, touch /etc/sia/matrix.conf.
59  */
60 #define VERS "AFS3"
61 static void afs_siad_debug(char *fmt, ...)
62 {
63     struct stat sbuf;
64     FILE *fp;
65     time_t now;
66     char *when;
67
68     va_list args;
69
70     /* Only print if file exists. */
71     if (stat(DEBUG_FILE, &sbuf)<0)
72         return;
73
74     if ((fp=fopen(DEBUG_FILE, "a")) == NULL)
75         return;
76
77     (void) time(&now);
78     when = ctime(&now);
79     when[24] = '\0';
80
81     fprintf(fp, "%s %s: ", VERS, when);
82     va_start(args, fmt);
83     vfprintf(fp, fmt, args);
84     va_end(args);
85
86     fflush(fp);
87     fclose(fp);
88
89 }
90
91 /* siad_init - Once per reboot processing goes here. */
92 int siad_init(void)
93 {
94     return SIADSUCCESS;
95 }
96
97 /* malloc any needed space required over the authentication session here. */
98 int siad_ses_init(SIAENTITY *entity, int pkgind)
99 {
100     return SIADSUCCESS;
101 }
102
103 /* We set the pwd entry in siad_ses_authent if we succeed in authenticating. 
104  * Otherwise the BSD mechanism will incur a core dump.
105  */
106 int siad_ses_estab(sia_collect_func_t *collect, SIAENTITY *entity, int pkgind)
107 {
108     return SIASUCCESS;
109 }
110
111 int siad_ses_launch(sia_collect_func_t *collect, SIAENTITY *entity, int pkgind)
112 {
113     return SIADSUCCESS;
114 }
115
116 /* Free up space malloc'd in siad_ses_init() */
117 int siad_ses_release(SIAENTITY *entity, int pkgind)
118 {
119     return SIADSUCCESS;
120 }
121
122 int siad_get_groups(struct sia_context *context, const char *username,
123                     gid_t *buf, int *numgroups, int maxgroups)
124 {
125     afs_siad_debug("siad_get_groups returning failure.\n");
126     return SIADFAIL;
127 }
128
129 /* Print the reason we failed to authenticate. */
130 static void afs_siad_authent_print_reason(sia_collect_func_t *collect,
131                                           char *reason)
132 {
133     unsigned char err_msg[128];
134
135     if (collect) {
136         (void) sprintf(err_msg, "Unable to authenticate to AFS because %s",
137                        reason);
138         sia_warning(collect, err_msg);
139     }
140 }
141
142 /* afs_siad_get_name_password
143  *
144  * Common code for siad_ses_authent and siad_ses_reauthent. Gather name and 
145  * password if required.
146  *
147  * Arguments:
148  * collect - prompt collection function.
149  * entity - SIA entity
150  * got_pass - set to 1 if we gather'd the password ourselves.
151  *
152  *
153  * Return value:
154  * SIADFAIL - failed to malloc, calling routine should return SIADFAIL.
155  * SIADSUCESS - name and password have been collected (maybe not by us).
156  * SIADFAIL | SIADSTOP - calling routine should return.
157  */
158 int
159 afs_siad_get_name_password(sia_collect_func_t *collect,SIAENTITY * entity,
160                            int* got_pass)
161 {
162     int need_name = 0;
163     int need_pass = 0;
164     int code = 0;
165     struct prompt_t prompts[2];
166     int n_prompts = 0;
167
168     *got_pass = 0;
169
170     if ((!entity->name) || (!(*entity->name))) {
171         entity->name = malloc(SIANAMEMIN+1);
172         if(entity->name == NULL) {
173           afs_siad_debug("afs_siad_get_name_password: failed to malloc name.\n");
174           code = SIADFAIL;
175           goto fail_free;
176         }
177         *(entity->name) = '\0';
178         need_name = 1;
179     }
180     if ((!entity->password) || (!(*entity->password))) {
181         entity->password = malloc(SIAMXPASSWORD+1);
182         if(entity->password == NULL) {
183           afs_siad_debug("afs_siad_get_name_password: failed to malloc password.\n");
184           code = SIADFAIL;
185           goto fail_free;
186         }
187         *(entity->password) = '\0';
188         need_pass = 1;
189     }
190
191     if (need_name || need_pass) {
192         if (!collect || !entity->colinput) {
193             code = SIADFAIL;
194             goto fail_free;
195         }
196         if (need_name) {
197             prompts[0].prompt = (unsigned char*)"login: ";
198             prompts[0].result = (unsigned char*)entity->name;
199             prompts[0].min_result_length = 1;
200             prompts[0].max_result_length = SIANAMEMIN;
201             prompts[0].control_flags = SIAPRINTABLE;
202             n_prompts = 1;
203         }
204         if (need_pass) {
205             prompts[n_prompts].prompt = (unsigned char*)"Password:";
206             prompts[n_prompts].result = (unsigned char*)entity->password;
207             prompts[n_prompts].min_result_length = 0;
208             prompts[n_prompts].max_result_length = SIAMXPASSWORD;
209             prompts[n_prompts].control_flags = SIARESINVIS;
210             n_prompts++;
211         }
212         if (n_prompts>1)
213             code = (*collect)(0, SIAFORM, (uchar_t *)"", n_prompts, prompts);
214         else
215             code = (*collect)(240, SIAONELINER, (uchar_t *)"", 1, prompts);
216         if (code != SIACOLSUCCESS) {
217             code = SIADFAIL | SIADSTOP;
218             goto fail_free;
219         }
220     }
221     *got_pass = need_pass;
222     return SIADSUCCESS;
223
224  fail_free:
225     if (need_name) {
226         free(entity->name);
227         entity->name = (char*)0;
228     }
229     if (need_pass) {
230         free(entity->password);
231         entity->password = (char*)0;
232     }
233     return code;
234 }
235
236 /* siad_ses_authent
237  *
238  * Authenticate user for AFS.
239  *
240  * Rules on when to authenticate, from the AFS SysAdmin Guide:
241  * 1) If no entry in password file, try the authentication.
242  * 2) If '*' in password file, don't attempt to authenticate.
243  * NOTE: If enhanced security is turned on, '*' means to check the data base
244  * for the encrypted password.
245  * 3) If passwd field is not 13 characters long, try AFS authentication.
246  * 4) If passwd field is 13 characters, try to authenticate.
247  * Comes down to:
248  * 1) Don't try to authenticate if '*' in password field.
249  * 2) Use "Entry AFS Password" if password field is not 13 charaters long.
250  *    This really isn't possible if the CDE login is being used since it
251  *    prints it's own prompts. 
252  *
253  * This is an integrated login environement. So I do not print any AFS
254  * specific login messages.
255  *
256  * entityhdl->colinput == 1 means the collect function can be used to prompt
257  * for input. If it's 0, then it can only be used to print messages.
258  * For this case, one also has to test for a non-null collect function.
259  *
260  * DCE, AFS, BSD is the proper order to do the authentication. Generally
261  * speaking AFS should come just before BSD which is last. The reason is that
262  * if some other mechanism succeeds in authenticating it will probably want to
263  * set the entity->pwd field to something other than /etc/passwd. 
264  */
265 int siad_ses_authent(sia_collect_func_t *collect, SIAENTITY *entity,
266                      int siastat, int pkgind)
267 {
268     int got_pass = 0;
269     int code = 0;
270     char *reason; /* returned by authenticate. */
271     int password_expires = -1;
272     struct passwd *pwd = (struct passwd*)0;
273     extern struct passwd *getpwnam();
274
275     code = afs_siad_get_name_password(collect, entity, &got_pass);
276     if (code != SIADSUCCESS)
277         return code;
278
279     pwd = getpwnam(entity->name);
280     if (!pwd) {
281         /* Only authenticate if user is in /etc/passwd. */
282         code = SIADFAIL;
283         goto authent_fail;
284     }
285     if ((pwd->pw_passwd[0] == '*') && (pwd->pw_passwd[1] == '\0')) {
286         afs_siad_debug("siad_ses_authent: refusing to authenticate\n");
287         code = SIADFAIL;
288         goto authent_fail;
289     }
290
291     code = ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION | KA_USERAUTH_DOSETPAG,
292                                       entity->name,
293                                       (char*)0, /* instance */
294                                       (char*)0, /* realm */
295                                       entity->password,
296                                       0, /* lifetime */
297                                       &password_expires,
298                                       0 /* spare2 */,
299                                       &reason);
300
301     if (code) {
302         afs_siad_debug("siad_sis_authent: auth1 failure: %s\n", reason);
303     }
304
305     if (code) {
306         code = SIADFAIL;
307         goto authent_fail;
308     }
309
310     if (!entity->pwd) {
311         entity->pwd = (struct passwd*)malloc(sizeof(struct passwd));
312         if (!entity->pwd) {
313             code = SIADFAIL;
314             goto authent_fail;
315         }
316         memset((void*)entity->pwd, '\0', sizeof(struct passwd));
317         if (sia_make_entity_pwd(pwd, entity) != SIASUCCESS) {
318             afs_siad_debug("siad_ses_authent: Can't set pwd into entity.\n");
319             code = SIADFAIL;
320             goto authent_fail;
321         }
322     }
323
324     /* Set PASSWORD_EXPIRES env variable if necessary */
325     if (password_expires >= 0 && password_expires < 255) {
326         char sbuffer[10];
327         sprintf(sbuffer, "%d", password_expires);
328         (void)setenv("PASSWORD_EXPIRES", sbuffer, 1);
329     }
330
331 #if defined(AFS_KERBEROS_ENV)
332     if (pwd)
333     {
334         if ( chown(ktc_tkt_string(), pwd->pw_uid, pwd->pw_gid) < 0 )
335             afs_siad_debug("siad_ses_authent fails - krb chown.\n");
336     }
337 #endif
338
339     afs_siad_debug("siad_ses_authent returning success.\n");
340     afs_sia_log("siad_ses_authent returning success.\n");
341     return SIADSUCCESS;
342
343  authent_fail:
344     afs_sia_log("siad_ses_authent fails, code=%d.\n", code);
345     afs_siad_debug("siad_ses_authent fails, code=%d.\n", code);
346     return code;
347
348 }
349
350
351 /* siad_ses_reauthent.
352  * Used for such things as as locking/unlocking terminal. This implies
353  * authenticate, but do not set a pag. The oher differences is that we
354  * accept vouching from other mechanism.
355  *
356  * Note the dtsession collects the password itself and will always pass it
357  * in. Also, colinput is typically false in this case as well as collect
358  * being null.
359  */
360 int siad_ses_reauthent(sia_collect_func_t *collect, SIAENTITY *entity,
361                                 int siastat, int pkgind)
362 {
363     int got_pass = 0;
364     int code = 0;
365     char *reason; /* returned by authenticate. */
366     struct passwd *pwd = (struct passwd*)0;
367     extern struct passwd *getpwnam();
368
369     if (siastat == SIADSUCCESS)
370         return;
371
372     code = afs_siad_get_name_password(collect, entity, &got_pass);
373     if (code != SIADSUCCESS)
374         return code;
375
376     pwd = getpwnam(entity->name);
377     if (!pwd) {
378         code = SIADFAIL;
379         goto reauthent_fail;
380     }
381
382     code = ka_VerifyUserPassword(KA_USERAUTH_VERSION, entity->name,
383                                  (char*)0, /* instance */
384                                  (char*)0, /* realm */
385                                  entity->password,
386                                  0 /* spare2 */,
387                                  &reason);
388
389     if (code) {
390         afs_siad_debug("siad_sis_reauthent: auth failure: %s\n", reason);
391     }
392
393     if (code) {
394         code = SIADFAIL;
395         goto reauthent_fail;
396     }
397
398     if (!entity->pwd) {
399         entity->pwd = (struct passwd*)malloc(sizeof(struct passwd));
400         if (!entity->pwd) {
401             code = SIADFAIL;
402             goto reauthent_fail;
403         }
404         memset((void*)entity->pwd, '\0', sizeof(struct passwd));
405         if (sia_make_entity_pwd(pwd, entity) != SIASUCCESS) {
406             afs_siad_debug("siad_ses_reauthent: Can't set pwd into entity.\n");
407             code = SIADFAIL;
408             goto reauthent_fail;
409         }
410     }
411
412     afs_siad_debug("siad_ses_reauthent returning success.\n");
413     afs_sia_log("siad_ses_reauthent returning success.\n");
414     return SIADSUCCESS;
415
416  reauthent_fail:
417     afs_sia_log("siad_ses_reauthent fails, code=%d.\n", code);
418     afs_siad_debug("siad_ses_reauthent fails, code=%d.\n", code);
419     return code;
420 }
421
422 int siad_chk_invoker(void)
423 {
424     afs_siad_debug("siad_chk_invoker returning failure.\n");
425     return SIADFAIL;
426 }
427
428 int siad_ses_suauthent(sia_collect_func_t *collect, SIAENTITY *entity,
429                        int siastat, int pkgind)
430 {
431     afs_siad_debug("siad_ses_suauthent returning failure.\n");
432     return SIADFAIL;
433 }
434
435
436 int siad_chg_finger(sia_collect_func_t *collect, const char *username,
437                     int argc, char *argv[])
438 {
439     afs_siad_debug("siad_chg_finger returning failure.\n");
440     return SIADFAIL;
441 }
442
443 int siad_chg_password(sia_collect_func_t *collect, const char *username,
444                       int argc, char *argv[])
445 {
446     afs_siad_debug("siad_chg_passwd returning failure.\n");
447     return SIADFAIL;
448 }
449
450 int siad_chg_shell(sia_collect_func_t *collect, const char *username,
451                    int argc, char *argv[])
452 {
453     afs_siad_debug("siad_chg_shell returning failure.\n");
454     return SIADFAIL;
455 }
456
457 int siad_getpwent(struct passwd *result, char *buf, int bufsize,
458                   struct sia_context *context)
459 {
460     afs_siad_debug("siad_getpwent returning failure.\n");
461     return SIADFAIL;
462 }
463
464 int siad_getpwuid(uid_t uid, struct passwd *result, char *buf, int bufsize,
465                   struct sia_context *context)
466 {
467     
468     afs_siad_debug("siad_getpwuid returning failure.\n");
469     return SIADFAIL;
470 }
471
472 int siad_getpwnam(const char *name, struct passwd *result, char *buf,
473                   int bufsize, struct sia_context *context)
474 {
475     afs_siad_debug("siad_ses_getpwnam returning failure.\n");
476     return SIADFAIL;
477 }
478
479 int siad_setpwent(struct sia_context *context)
480 {
481     afs_siad_debug("siad_ses_setpwent returning failure.\n");
482     return SIADFAIL;
483 }
484
485 int siad_endpwent(struct sia_context *context)
486 {
487     afs_siad_debug("siad_ses_endpwent returning failure.\n");
488     return SIADFAIL;
489 }
490
491 int siad_getgrent(struct group *result, char *buf, int bufsize,
492                   struct sia_context *context)
493 {
494     afs_siad_debug("siad_ses_getgrent returning failure.\n");
495     return SIADFAIL;
496 }
497
498 int siad_getgrgid(gid_t gid, struct group *result, char *buf, int bufsize,
499                   struct sia_context *context)
500 {
501     afs_siad_debug("siad_ses_getgrgid returning failure.\n");
502     return SIADFAIL;
503 }
504
505 int siad_getgrnam(const char *name, struct group *result, char *buf, 
506                   int bufsize, struct sia_context *context)
507 {
508     afs_siad_debug("siad_ses_getgrnam returning failure.\n");
509     return SIADFAIL;
510 }
511
512 int siad_setgrent(struct sia_context *context)
513 {
514     afs_siad_debug("siad_ses_setgrent returning failure.\n");
515     return SIADFAIL;
516 }
517
518 int siad_endgrent(struct sia_context *context)
519 {
520     afs_siad_debug("siad_ses_endgrent returning failure.\n");
521     return SIADFAIL;
522 }
523
524 int siad_chk_user(const char *logname, int checkflag)
525 {
526     afs_siad_debug("siad_ses_chk_user returning success.\n");
527     return SIADFAIL;
528 }
529
530
531 #ifdef notdef
532 /* These are not in the current implementation. */
533 void siad_ses_toggle_privs(SIAENTITY *entity, int pkgind, int elevate)
534 {
535     afs_siad_debug("siad_ses_toggle_privs.\n");
536     return;
537 }
538
539
540 void siad_ses_update_audit_record(SIAENTITY *entity, int pkgind, int event,
541                                   char *tokenp, char **datap, int *used,
542                                   int maxused)
543 {
544     afs_siad_debug("siad_ses_update_audit_record.\n");
545     return;
546 }
547 #endif