Release 0.0r
[heimdal.git] / lib / auth / sia / sia.c
blob44f9b8a446219e712f596eeeca932e1208dd6cb9
1 /*
2 * Copyright (c) 1995, 1996, 1997, 1998 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by the Kungliga Tekniska
20 * Högskolan and its contributors.
22 * 4. Neither the name of the Institute nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
26 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
39 #ifdef HAVE_CONFIG_H
40 #include <config.h>
41 RCSID("$Id$");
42 #endif
43 #include <ctype.h>
44 #include <stdio.h>
45 #include <string.h>
46 #include <siad.h>
47 #include <pwd.h>
48 #include <sys/types.h>
49 #include <sys/socket.h>
50 #include <netinet/in.h>
52 #include <krb.h>
53 #include <kafs.h>
54 #include <kadm.h>
55 #include <kadm_err.h>
56 #include <roken.h>
59 #ifndef POSIX_GETPWNAM_R
61 /* These functions translate from the old Digital UNIX 3.x interface
62 * to POSIX.1c.
65 static int
66 posix_getpwnam_r(const char *name, struct passwd *pwd,
67 char *buffer, int len, struct passwd **result)
69 int ret = getpwnam_r(name, pwd, buffer, len);
70 if(ret == 0)
71 *result = pwd;
72 else{
73 *result = NULL;
74 ret = _Geterrno();
75 if(ret == 0){
76 ret = ERANGE;
77 _Seterrno(ret);
80 return ret;
83 #define getpwnam_r posix_getpwnam_r
85 static int
86 posix_getpwuid_r(uid_t uid, struct passwd *pwd,
87 char *buffer, int len, struct passwd **result)
89 int ret = getpwuid_r(uid, pwd, buffer, len);
90 if(ret == 0)
91 *result = pwd;
92 else{
93 *result = NULL;
94 ret = _Geterrno();
95 if(ret == 0){
96 ret = ERANGE;
97 _Seterrno(ret);
100 return ret;
103 #define getpwuid_r posix_getpwuid_r
105 #endif /* POSIX_GETPWNAM_R */
107 #ifndef DEBUG
108 #define SIA_DEBUG(X)
109 #else
110 #define SIA_DEBUG(X) SIALOG X
111 #endif
113 struct state{
114 char ticket[MaxPathLen];
115 int valid;
118 int
119 siad_init(void)
121 return SIADSUCCESS;
124 int
125 siad_chk_invoker(void)
127 SIA_DEBUG(("DEBUG", "siad_chk_invoker"));
128 return SIADFAIL;
131 int
132 siad_ses_init(SIAENTITY *entity, int pkgind)
134 struct state *s = malloc(sizeof(*s));
135 SIA_DEBUG(("DEBUG", "siad_ses_init"));
136 if(s == NULL)
137 return SIADFAIL;
138 memset(s, 0, sizeof(*s));
139 entity->mech[pkgind] = (int*)s;
140 return SIADSUCCESS;
143 static int
144 setup_name(SIAENTITY *e, prompt_t *p)
146 SIA_DEBUG(("DEBUG", "setup_name"));
147 e->name = malloc(SIANAMEMIN+1);
148 if(e->name == NULL){
149 SIA_DEBUG(("DEBUG", "failed to malloc %u bytes", SIANAMEMIN+1));
150 return SIADFAIL;
152 p->prompt = (unsigned char*)"login: ";
153 p->result = (unsigned char*)e->name;
154 p->min_result_length = 1;
155 p->max_result_length = SIANAMEMIN;
156 p->control_flags = 0;
157 return SIADSUCCESS;
160 static int
161 setup_password(SIAENTITY *e, prompt_t *p)
163 SIA_DEBUG(("DEBUG", "setup_password"));
164 e->password = malloc(SIAMXPASSWORD+1);
165 if(e->password == NULL){
166 SIA_DEBUG(("DEBUG", "failed to malloc %u bytes", SIAMXPASSWORD+1));
167 return SIADFAIL;
169 p->prompt = (unsigned char*)"Password: ";
170 p->result = (unsigned char*)e->password;
171 p->min_result_length = 0;
172 p->max_result_length = SIAMXPASSWORD;
173 p->control_flags = SIARESINVIS;
174 return SIADSUCCESS;
178 static int
179 common_auth(sia_collect_func_t *collect,
180 SIAENTITY *entity,
181 int siastat,
182 int pkgind)
184 prompt_t prompts[2], *pr;
185 char *toname, *toinst;
186 char *name;
188 SIA_DEBUG(("DEBUG", "common_auth"));
189 if((siastat == SIADSUCCESS) && (geteuid() == 0))
190 return SIADSUCCESS;
191 if(entity == NULL) {
192 SIA_DEBUG(("DEBUG", "entity == NULL"));
193 return SIADFAIL | SIADSTOP;
195 name = entity->name;
196 if(entity->acctname)
197 name = entity->acctname;
199 if((collect != NULL) && entity->colinput) {
200 int num;
201 pr = prompts;
202 if(name == NULL){
203 if(setup_name(entity, pr) != SIADSUCCESS)
204 return SIADFAIL;
205 pr++;
207 if(entity->password == NULL){
208 if(setup_password(entity, pr) != SIADSUCCESS)
209 return SIADFAIL;
210 pr++;
212 num = pr - prompts;
213 if(num == 1){
214 if((*collect)(240, SIAONELINER, (unsigned char*)"", num,
215 prompts) != SIACOLSUCCESS){
216 SIA_DEBUG(("DEBUG", "collect failed"));
217 return SIADFAIL | SIADSTOP;
219 } else if(num > 0){
220 if((*collect)(0, SIAFORM, (unsigned char*)"", num,
221 prompts) != SIACOLSUCCESS){
222 SIA_DEBUG(("DEBUG", "collect failed"));
223 return SIADFAIL | SIADSTOP;
227 if(name == NULL)
228 name = entity->name;
229 if(name == NULL || name[0] == '\0'){
230 SIA_DEBUG(("DEBUG", "name is null"));
231 return SIADFAIL;
234 if(entity->password == NULL || strlen(entity->password) > SIAMXPASSWORD){
235 SIA_DEBUG(("DEBUG", "entity->password is null"));
236 return SIADFAIL;
240 char realm[REALM_SZ];
241 int ret;
242 struct passwd pw, *pwd, fpw, *fpwd;
243 char pwbuf[1024], fpwbuf[1024];
244 struct state *s = (struct state*)entity->mech[pkgind];
246 if(getpwnam_r(name, &pw, pwbuf, sizeof(pwbuf), &pwd) != 0){
247 SIA_DEBUG(("DEBUG", "failed to getpwnam(%s)", name));
248 return SIADFAIL;
251 snprintf(s->ticket, sizeof(s->ticket),
252 TKT_ROOT "%u_%u", (unsigned)pwd->pw_uid, (unsigned)getpid());
253 krb_get_lrealm(realm, 1);
254 toname = name;
255 toinst = "";
256 if(entity->authtype == SIA_A_SUAUTH){
257 uid_t ouid;
258 #ifdef SIAENTITY_HAS_OUID
259 ouid = entity->ouid;
260 #else
261 ouid = getuid();
262 #endif
263 if(getpwuid_r(ouid, &fpw, fpwbuf, sizeof(fpwbuf), &fpwd) != 0){
264 SIA_DEBUG(("DEBUG", "failed to getpwuid(%u)", ouid));
265 return SIADFAIL;
267 snprintf(s->ticket, sizeof(s->ticket), TKT_ROOT "_%s_to_%s_%d",
268 fpwd->pw_name, pwd->pw_name, getpid());
269 if(strcmp(pwd->pw_name, "root") == 0){
270 toname = fpwd->pw_name;
271 toinst = pwd->pw_name;
274 if(entity->authtype == SIA_A_REAUTH)
275 snprintf(s->ticket, sizeof(s->ticket), "%s", tkt_string());
277 krb_set_tkt_string(s->ticket);
279 setuid(0); /* XXX fix for fix in tf_util.c */
280 if(krb_kuserok(toname, toinst, realm, name)){
281 SIA_DEBUG(("DEBUG", "%s.%s@%s is not allowed to login as %s",
282 toname, toinst, realm, name));
283 return SIADFAIL;
285 ret = krb_verify_user(toname, toinst, realm,
286 entity->password, getuid() == 0, NULL);
287 if(ret){
288 SIA_DEBUG(("DEBUG", "krb_verify_user: %s", krb_get_err_text(ret)));
289 if(ret != KDC_PR_UNKNOWN)
290 /* since this is most likely a local user (such as
291 root), just silently return failure when the
292 principal doesn't exist */
293 SIALOG("WARNING", "krb_verify_user(%s.%s): %s",
294 toname, toinst, krb_get_err_text(ret));
295 return SIADFAIL;
297 if(sia_make_entity_pwd(pwd, entity) == SIAFAIL)
298 return SIADFAIL;
299 s->valid = 1;
301 return SIADSUCCESS;
305 int
306 siad_ses_authent(sia_collect_func_t *collect,
307 SIAENTITY *entity,
308 int siastat,
309 int pkgind)
311 SIA_DEBUG(("DEBUG", "siad_ses_authent"));
312 return common_auth(collect, entity, siastat, pkgind);
315 int
316 siad_ses_estab(sia_collect_func_t *collect,
317 SIAENTITY *entity, int pkgind)
319 SIA_DEBUG(("DEBUG", "siad_ses_estab"));
320 return SIADFAIL;
323 int
324 siad_ses_launch(sia_collect_func_t *collect,
325 SIAENTITY *entity,
326 int pkgind)
328 static char env[MaxPathLen];
329 struct state *s = (struct state*)entity->mech[pkgind];
330 SIA_DEBUG(("DEBUG", "siad_ses_launch"));
331 if(s->valid){
332 chown(s->ticket, entity->pwd->pw_uid, entity->pwd->pw_gid);
333 snprintf(env, sizeof(env), "KRBTKFILE=%s", s->ticket);
334 putenv(env);
336 if (k_hasafs()) {
337 char cell[64];
338 k_setpag();
339 if(k_afs_cell_of_file(entity->pwd->pw_dir, cell, sizeof(cell)) == 0)
340 krb_afslog(cell, 0);
341 krb_afslog(0, 0);
343 return SIADSUCCESS;
346 int
347 siad_ses_release(SIAENTITY *entity, int pkgind)
349 SIA_DEBUG(("DEBUG", "siad_ses_release"));
350 if(entity->mech[pkgind])
351 free(entity->mech[pkgind]);
352 return SIADSUCCESS;
355 int
356 siad_ses_suauthent(sia_collect_func_t *collect,
357 SIAENTITY *entity,
358 int siastat,
359 int pkgind)
361 SIA_DEBUG(("DEBUG", "siad_ses_suauth"));
362 if(geteuid() != 0)
363 return SIADFAIL;
364 if(entity->name == NULL)
365 return SIADFAIL;
366 if(entity->name[0] == 0) {
367 free(entity->name);
368 entity->name = strdup("root");
369 if (entity->name == NULL)
370 return SIADFAIL;
372 return common_auth(collect, entity, siastat, pkgind);
375 /* The following functions returns the default fail */
378 siad_ses_reauthent (sia_collect_func_t *collect,
379 SIAENTITY *entity,
380 int siastat,
381 int pkgind)
383 int ret;
384 SIA_DEBUG(("DEBUG", "siad_ses_reauthent"));
385 if(entity == NULL || entity->name == NULL)
386 return SIADFAIL;
387 ret = common_auth(collect, entity, siastat, pkgind);
388 if((ret & SIADSUCCESS)){
389 /* launch isn't (always?) called when doing reauth, so we must
390 duplicate some code here... */
391 struct state *s = (struct state*)entity->mech[pkgind];
392 chown(s->ticket, entity->pwd->pw_uid, entity->pwd->pw_gid);
393 if(k_hasafs()) {
394 char cell[64];
395 if(k_afs_cell_of_file(entity->pwd->pw_dir,
396 cell, sizeof(cell)) == 0)
397 krb_afslog(cell, 0);
398 krb_afslog(0, 0);
401 return ret;
405 siad_chg_finger (sia_collect_func_t *collect,
406 const char *username,
407 int argc,
408 char *argv[])
410 SIA_DEBUG(("DEBUG", "siad_chg_finger"));
411 return SIADFAIL;
414 static void
415 sia_message(sia_collect_func_t *collect, int rendition,
416 const char *title, const char *message)
418 prompt_t prompt;
419 prompt.prompt = (unsigned char*)message;
420 (*collect)(0, rendition, (unsigned char*)title, 1, &prompt);
423 static int
424 init_change(sia_collect_func_t *collect, krb_principal *princ)
426 prompt_t prompt;
427 char old_pw[MAX_KPW_LEN+1];
428 char *msg;
429 char tktstring[128];
430 int ret;
432 SIA_DEBUG(("DEBUG", "init_change"));
433 prompt.prompt = (unsigned char*)"Old password: ";
434 prompt.result = (unsigned char*)old_pw;
435 prompt.min_result_length = 0;
436 prompt.max_result_length = sizeof(old_pw) - 1;
437 prompt.control_flags = SIARESINVIS;
438 asprintf(&msg, "Changing password for %s", krb_unparse_name(princ));
439 if(msg == NULL){
440 SIA_DEBUG(("DEBUG", "out of memory"));
441 return SIADFAIL;
443 ret = (*collect)(60, SIAONELINER, (unsigned char*)msg, 1, &prompt);
444 free(msg);
445 SIA_DEBUG(("DEBUG", "ret = %d", ret));
446 if(ret != SIACOLSUCCESS)
447 return SIADFAIL;
448 snprintf(tktstring, sizeof(tktstring),
449 TKT_ROOT "_cpw_%u", (unsigned)getpid());
450 krb_set_tkt_string(tktstring);
452 ret = krb_get_pw_in_tkt(princ->name, princ->instance, princ->realm,
453 PWSERV_NAME, KADM_SINST, 1, old_pw);
454 if (ret != KSUCCESS) {
455 SIA_DEBUG(("DEBUG", "krb_get_pw_in_tkt: %s", krb_get_err_text(ret)));
456 if (ret == INTK_BADPW)
457 sia_message(collect, SIAWARNING, "", "Incorrect old password.");
458 else
459 sia_message(collect, SIAWARNING, "", "Kerberos error.");
460 memset(old_pw, 0, sizeof(old_pw));
461 return SIADFAIL;
463 if(chown(tktstring, getuid(), -1) < 0){
464 dest_tkt();
465 return SIADFAIL;
467 memset(old_pw, 0, sizeof(old_pw));
468 return SIADSUCCESS;
472 siad_chg_password (sia_collect_func_t *collect,
473 const char *username,
474 int argc,
475 char *argv[])
477 prompt_t prompts[2];
478 krb_principal princ;
479 int ret;
480 char new_pw1[MAX_KPW_LEN+1];
481 char new_pw2[MAX_KPW_LEN+1];
482 static struct et_list *et_list;
484 set_progname(argv[0]);
486 SIA_DEBUG(("DEBUG", "siad_chg_password"));
487 if(collect == NULL)
488 return SIADFAIL;
490 if(username == NULL)
491 username = getlogin();
493 ret = krb_parse_name(username, &princ);
494 if(ret)
495 return SIADFAIL;
496 if(princ.realm[0] == '\0')
497 krb_get_lrealm(princ.realm, 1);
499 if(et_list == NULL) {
500 initialize_kadm_error_table_r(&et_list);
501 initialize_krb_error_table_r(&et_list);
504 ret = init_change(collect, &princ);
505 if(ret != SIADSUCCESS)
506 return ret;
508 again:
509 prompts[0].prompt = (unsigned char*)"New password: ";
510 prompts[0].result = (unsigned char*)new_pw1;
511 prompts[0].min_result_length = MIN_KPW_LEN;
512 prompts[0].max_result_length = sizeof(new_pw1) - 1;
513 prompts[0].control_flags = SIARESINVIS;
514 prompts[1].prompt = (unsigned char*)"Verify new password: ";
515 prompts[1].result = (unsigned char*)new_pw2;
516 prompts[1].min_result_length = MIN_KPW_LEN;
517 prompts[1].max_result_length = sizeof(new_pw2) - 1;
518 prompts[1].control_flags = SIARESINVIS;
519 if((*collect)(120, SIAFORM, (unsigned char*)"", 2, prompts) !=
520 SIACOLSUCCESS) {
521 dest_tkt();
522 return SIADFAIL;
524 if(strcmp(new_pw1, new_pw2) != 0){
525 sia_message(collect, SIAWARNING, "", "Password mismatch.");
526 goto again;
528 ret = kadm_check_pw(new_pw1);
529 if(ret) {
530 sia_message(collect, SIAWARNING, "", com_right(et_list, ret));
531 goto again;
534 memset(new_pw2, 0, sizeof(new_pw2));
535 ret = kadm_init_link (PWSERV_NAME, KRB_MASTER, princ.realm);
536 if (ret != KADM_SUCCESS)
537 sia_message(collect, SIAWARNING, "Error initing kadmin connection",
538 com_right(et_list, ret));
539 else {
540 des_cblock newkey;
541 char *pw_msg; /* message from server */
543 des_string_to_key(new_pw1, &newkey);
544 ret = kadm_change_pw_plain((unsigned char*)&newkey, new_pw1, &pw_msg);
545 memset(newkey, 0, sizeof(newkey));
547 if (ret == KADM_INSECURE_PW)
548 sia_message(collect, SIAWARNING, "Insecure password", pw_msg);
549 else if (ret != KADM_SUCCESS)
550 sia_message(collect, SIAWARNING, "Error changing password",
551 com_right(et_list, ret));
553 memset(new_pw1, 0, sizeof(new_pw1));
555 if (ret != KADM_SUCCESS)
556 sia_message(collect, SIAWARNING, "", "Password NOT changed.");
557 else
558 sia_message(collect, SIAINFO, "", "Password changed.");
560 dest_tkt();
561 if(ret)
562 return SIADFAIL;
563 return SIADSUCCESS;
567 siad_chg_shell (sia_collect_func_t *collect,
568 const char *username,
569 int argc,
570 char *argv[])
572 return SIADFAIL;
576 siad_getpwent(struct passwd *result,
577 char *buf,
578 int bufsize,
579 struct sia_context *context)
581 return SIADFAIL;
585 siad_getpwuid (uid_t uid,
586 struct passwd *result,
587 char *buf,
588 int bufsize,
589 struct sia_context *context)
591 return SIADFAIL;
595 siad_getpwnam (const char *name,
596 struct passwd *result,
597 char *buf,
598 int bufsize,
599 struct sia_context *context)
601 return SIADFAIL;
605 siad_setpwent (struct sia_context *context)
607 return SIADFAIL;
611 siad_endpwent (struct sia_context *context)
613 return SIADFAIL;
617 siad_getgrent(struct group *result,
618 char *buf,
619 int bufsize,
620 struct sia_context *context)
622 return SIADFAIL;
626 siad_getgrgid (gid_t gid,
627 struct group *result,
628 char *buf,
629 int bufsize,
630 struct sia_context *context)
632 return SIADFAIL;
636 siad_getgrnam (const char *name,
637 struct group *result,
638 char *buf,
639 int bufsize,
640 struct sia_context *context)
642 return SIADFAIL;
646 siad_setgrent (struct sia_context *context)
648 return SIADFAIL;
652 siad_endgrent (struct sia_context *context)
654 return SIADFAIL;
658 siad_chk_user (const char *logname, int checkflag)
660 if(checkflag != CHGPASSWD)
661 return SIADFAIL;
662 return SIADSUCCESS;