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