static krb5_error_code check_an2ln(krb5_context context, krb5_const_principal principal, const char *luser, krb5_boolean *result) { krb5_error_code ret; char *lname; #if 0 /* XXX Should we make this an option? */ /* multi-component principals can never match */ if (krb5_principal_get_comp_string(context, principal, 1) != NULL) { *result = FALSE; return 0; } #endif lname = malloc(strlen(luser) + 1); if (lname == NULL) return krb5_enomem(context); ret = krb5_aname_to_localname(context, principal, strlen(luser)+1, lname); if (ret) goto out; if (strcmp(lname, luser) == 0) *result = TRUE; else *result = FALSE; out: free(lname); return 0; }
/* * Determine whether principal is authorized to log in as luser according to * aname-to-localname translation. Return ACCEPT if principal translates to * luser or PASS if it does not. */ static enum result an2ln_ok(krb5_context context, krb5_principal principal, const char *luser) { krb5_error_code ret; char kuser[MAX_USERNAME]; ret = krb5_aname_to_localname(context, principal, sizeof(kuser), kuser); if (ret != 0) return PASS; return (strcmp(kuser, luser) == 0) ? ACCEPT : PASS; }
int ssh_krb5_kuserok(krb5_context krb5_ctx, krb5_principal krb5_user, const char *client) { if (options.use_kuserok) return krb5_kuserok(krb5_ctx, krb5_user, client); else { char kuser[65]; if (krb5_aname_to_localname(krb5_ctx, krb5_user, sizeof(kuser), kuser)) return 0; return strcmp(kuser, client) == 0; } }
OM_uint32 GSSAPI_CALLCONV _gsskrb5_pname_to_uid(OM_uint32 *minor_status, const gss_name_t pname, const gss_OID mech_type, uid_t *uidp) { #ifdef NO_LOCALNAME *minor_status = KRB5_NO_LOCALNAME; return GSS_S_FAILURE; #else krb5_error_code ret; krb5_context context; krb5_const_principal princ = (krb5_const_principal)pname; char localname[256]; #ifdef POSIX_GETPWNAM_R char pwbuf[2048]; struct passwd pw, *pwd; #else struct passwd *pwd; #endif GSSAPI_KRB5_INIT(&context); *minor_status = 0; ret = krb5_aname_to_localname(context, princ, sizeof(localname), localname); if (ret != 0) { *minor_status = ret; return GSS_S_FAILURE; } #ifdef POSIX_GETPWNAM_R if (getpwnam_r(localname, &pw, pwbuf, sizeof(pwbuf), &pwd) != 0) { *minor_status = KRB5_NO_LOCALNAME; return GSS_S_FAILURE; } #else pwd = getpwnam(localname); #endif if (pwd == NULL) { *minor_status = KRB5_NO_LOCALNAME; return GSS_S_FAILURE; } *uidp = pwd->pw_uid; return GSS_S_COMPLETE; #endif /* NO_LOCALNAME */ }
OM_uint32 _gsskrb5_pname_to_uid(OM_uint32 *minor_status, const gss_name_t pname, const gss_OID mech, uid_t *uidp) { krb5_context context; krb5_const_principal name = (krb5_const_principal) pname; krb5_error_code kret; char lname[MAXLOGNAME + 1], buf[1024], *bufp; struct passwd pwd, *pw; size_t buflen; int error; OM_uint32 ret; static size_t buflen_hint = 1024; GSSAPI_KRB5_INIT (&context); kret = krb5_aname_to_localname(context, name, sizeof(lname), lname); if (kret) { *minor_status = kret; return (GSS_S_FAILURE); } *minor_status = 0; buflen = buflen_hint; for (;;) { pw = NULL; bufp = buf; if (buflen > sizeof(buf)) bufp = malloc(buflen); if (bufp == NULL) break; error = getpwnam_r(lname, &pwd, bufp, buflen, &pw); if (error != ERANGE) break; if (buflen > sizeof(buf)) free(bufp); buflen += 1024; if (buflen > buflen_hint) buflen_hint = buflen; } if (pw) { *uidp = pw->pw_uid; ret = GSS_S_COMPLETE; } else { ret = GSS_S_FAILURE; } if (bufp != NULL && buflen > sizeof(buf)) free(bufp); return (ret); }
int check(const char* principal) { krb5_context ctx = NULL; krb5_principal princ = NULL; krb5_error_code code; char lname[MAX_USERNAME]; int result = 0; code = krb5_init_context(&ctx); if (code != 0) { fprintf(stderr, "%s: error in krb5_init_context: %d\n", prog, code); result = 1; goto end; } code = krb5_parse_name(ctx, principal, &princ); if (code != 0) { fprintf(stderr, "%s: error in krb5_parse_name: %d\n", prog, code); result = 1; goto end; } code = krb5_aname_to_localname(ctx, princ, MAX_USERNAME-1, lname); if (code != 0) { fprintf(stderr, "%s: error in krb5_aname_to_localname: %d\n", prog, code); result = 1; goto end; } if (strcmp(lname, "user") != 0) { fprintf(stderr, "%s: error, got %s, expected %s\n", prog, lname, "user"); result = 1; goto end; } fprintf(stderr, "%s: ok\n", prog); end: if (princ != NULL) { krb5_free_principal(ctx, princ); } if (ctx != NULL) { krb5_free_context(ctx); } return result; }
static void test_alname(krb5_context context, krb5_const_realm realm, const char *user, const char *inst, const char *localuser, int ok) { krb5_principal p; char localname[1024]; krb5_error_code ret; char *princ; ret = krb5_make_principal(context, &p, realm, user, inst, NULL); if (ret) krb5_err(context, 1, ret, "krb5_build_principal"); ret = krb5_unparse_name(context, p, &princ); if (ret) krb5_err(context, 1, ret, "krb5_unparse_name"); ret = krb5_aname_to_localname(context, p, sizeof(localname), localname); krb5_free_principal(context, p); free(princ); if (ret) { if (!ok) return; krb5_err(context, 1, ret, "krb5_aname_to_localname: %s -> %s", princ, localuser); } if (strcmp(localname, localuser) != 0) { if (ok) errx(1, "compared failed %s != %s (should have succeded)", localname, localuser); } else { if (!ok) errx(1, "compared failed %s == %s (should have failed)", localname, localuser); } }
char *kerberos_login (char *user,char *authuser,int argc,char *argv[]) { krb5_context ctx; krb5_principal prnc; char kuser[NETMAXUSER]; char *ret = NIL; /* make a context */ if (!krb5_init_context (&ctx)) { /* build principal */ if (!krb5_parse_name (ctx,authuser,&prnc)) { /* can get local name for this principal? */ if (!krb5_aname_to_localname (ctx,prnc,NETMAXUSER-1,kuser)) { /* yes, local name permitted login as user? */ if (authserver_login (user,kuser,argc,argv) || authserver_login (lcase (user),kuser,argc,argv)) ret = myusername (); /* yes, return user name */ } krb5_free_principal (ctx,prnc); } krb5_free_context (ctx); /* finished with context */ } return ret; }
int auks_cred_init(auks_cred_t * credential, char *data, size_t length) { int fstatus = AUKS_ERROR ; char *tmp_string = NULL; size_t tmp_size = 0; /* kerberos related variables */ krb5_error_code err_code; krb5_context context; krb5_auth_context auth_context; krb5_data kdata; krb5_creds **creds; krb5_replay_data krdata; char username[AUKS_PRINCIPAL_MAX_LENGTH + 1]; struct passwd user_pwent; struct passwd *p_pwent; size_t pwnam_buffer_length = sysconf(_SC_GETPW_R_SIZE_MAX); char pwnam_buffer[pwnam_buffer_length]; credential->info.principal[0] = '\0'; credential->info.uid = AUKS_CRED_INVALID_UID; credential->info.starttime = AUKS_CRED_INVALID_TIME; credential->info.endtime = AUKS_CRED_INVALID_TIME; credential->info.renew_till = AUKS_CRED_INVALID_TIME; credential->info.addressless = 1; credential->data[1] = '\0'; credential->length = 0; credential->max_length = AUKS_CRED_DATA_MAX_LENGTH; credential->status = AUKS_SUCCESS; /* check input buffer length versus auks credential internal buffer */ /* max length */ if ((unsigned int) length > (unsigned int) credential->max_length) { auks_error("input buffer is bigger than auks credential internal " "buffer (%u versus %u)",length, credential->max_length); fstatus = AUKS_ERROR_CRED_INIT_BUFFER_TOO_LARGE ; goto exit; } /* extract informations from buffer */ if (data == NULL) { auks_error("input buffer is NULL"); fstatus = AUKS_ERROR_CRED_INIT_BUFFER_IS_NULL ; goto exit; } fstatus = AUKS_ERROR ; /* initialize kerberos context */ err_code = krb5_init_context(&context); if (err_code) { auks_error("unable to initialize kerberos context : %s", error_message(err_code)); fstatus = AUKS_ERROR_CRED_INIT_KRB_CTX_INIT ; goto exit; } auks_log("kerberos context successfully initialized"); /* initialize a nullified kerberos authentication context in order to decode credential from buffer */ err_code = krb5_auth_con_init(context,&auth_context); if (err_code) { auks_error("unable to initialize connection " "authentication context : %s", error_message(err_code)); fstatus = AUKS_ERROR_CRED_INIT_KRB_AUTH_CTX_INIT ; goto ctx_exit; } /* clear kerberos authentication context flags */ krb5_auth_con_setflags(context,auth_context,0); /* set a kerberos data structure with input buffer */ kdata.data = data ; kdata.length = (unsigned int) length ; /* build kerberos credential structure using this data structure */ err_code = krb5_rd_cred(context,auth_context,&kdata, &creds,&krdata); if (err_code) { auks_error("unable to deserialize input buffer credential : %s", error_message(err_code)); fstatus = AUKS_ERROR_CRED_INIT_KRB_RD_BUFFER ; goto auth_ctx_exit; } auks_log("input buffer credential successfully unserialized"); err_code = krb5_unparse_name_ext(context,(*creds)->client,&tmp_string, (unsigned int *) &tmp_size); if (err_code) { auks_error("unable to unparse principal : %s", error_message(err_code)); fstatus = AUKS_ERROR_CRED_INIT_KRB_RD_PRINC ; goto creds_exit; } else if (tmp_size > AUKS_PRINCIPAL_MAX_LENGTH) { auks_error("unable to unparse principal : %s", "principal is too long (more than %d characters)", AUKS_PRINCIPAL_MAX_LENGTH); free(tmp_string); fstatus = AUKS_ERROR_CRED_INIT_KRB_PRINC_TOO_LONG ; goto creds_exit; } auks_log("principal successfully unparse"); memcpy(credential->info.principal,tmp_string,tmp_size); credential->info.principal[tmp_size] = '\0'; /* associated username from principal */ err_code = krb5_aname_to_localname(context,(*creds)->client, AUKS_PRINCIPAL_MAX_LENGTH,username); if (err_code) { auks_error("unable to get username from principal %s : %s", credential->info.principal,error_message(err_code)); fstatus = AUKS_ERROR_CRED_INIT_KRB_PRINC_TO_UNAME ; goto string_exit; } /* associated uid from username */ fstatus = getpwnam_r(username,&user_pwent,pwnam_buffer, pwnam_buffer_length,&p_pwent) ; if (fstatus) { auks_log("unable to get %s pwnam entry : %s",username, strerror(fstatus)) ; fstatus = AUKS_ERROR_CRED_INIT_GETPWNAM ; goto string_exit; } /* uid information */ credential->info.uid = user_pwent.pw_uid; credential->info.starttime = (time_t) (*creds)->times.starttime ; credential->info.endtime = (time_t) (*creds)->times.endtime ; credential->info.renew_till = (time_t) (*creds)->times.renew_till ; /* addresslessness */ if (((*creds)->addresses) != NULL) credential->info.addressless = 0; /* duplicate input buffer */ credential->length = (unsigned int) length; memcpy(credential->data,data,(unsigned int) length); fstatus = AUKS_SUCCESS; string_exit: free(tmp_string); creds_exit: krb5_free_creds(context,*creds); free(creds); auth_ctx_exit: krb5_auth_con_free(context,auth_context); ctx_exit: krb5_free_context(context); exit: /* if valid buffer, store it */ if (fstatus != 0) { /* bad credential buffer in input, clean this auks credential */ auks_cred_free_contents(credential); } return fstatus; }
krb5_boolean KRB5_CALLCONV krb5_kuserok(krb5_context context, krb5_principal principal, const char *luser) { struct stat sbuf; struct passwd *pwd; char pbuf[MAXPATHLEN]; krb5_boolean isok = FALSE; FILE *fp; char kuser[MAX_USERNAME]; char *princname; char linebuf[BUFSIZ]; char *newline; int gobble; /* no account => no access */ char pwbuf[BUFSIZ]; struct passwd pwx; if (k5_getpwnam_r(luser, &pwx, pwbuf, sizeof(pwbuf), &pwd) != 0) return(FALSE); (void) strncpy(pbuf, pwd->pw_dir, sizeof(pbuf) - 1); pbuf[sizeof(pbuf) - 1] = '\0'; (void) strncat(pbuf, "/.k5login", sizeof(pbuf) - 1 - strlen(pbuf)); if (access(pbuf, F_OK)) { /* not accessible */ /* * if he's trying to log in as himself, and there is no .k5login file, * let him. To find out, call * krb5_aname_to_localname to convert the principal to a name * which we can string compare. */ if (!(krb5_aname_to_localname(context, principal, sizeof(kuser), kuser)) && (strcmp(kuser, luser) == 0)) { return(TRUE); } } if (krb5_unparse_name(context, principal, &princname)) return(FALSE); /* no hope of matching */ /* open ~/.k5login */ if ((fp = fopen(pbuf, "r")) == NULL) { free(princname); return(FALSE); } set_cloexec_file(fp); /* * For security reasons, the .k5login file must be owned either by * the user himself, or by root. Otherwise, don't grant access. */ if (fstat(fileno(fp), &sbuf)) { fclose(fp); free(princname); return(FALSE); } if (sbuf.st_uid != pwd->pw_uid && !FILE_OWNER_OK(sbuf.st_uid)) { fclose(fp); free(princname); return(FALSE); } /* check each line */ while (!isok && (fgets(linebuf, BUFSIZ, fp) != NULL)) { /* null-terminate the input string */ linebuf[BUFSIZ-1] = '\0'; newline = NULL; /* nuke the newline if it exists */ if ((newline = strchr(linebuf, '\n'))) *newline = '\0'; if (!strcmp(linebuf, princname)) { isok = TRUE; continue; } /* clean up the rest of the line if necessary */ if (!newline) while (((gobble = getc(fp)) != EOF) && gobble != '\n'); } free(princname); fclose(fp); return(isok); }
/* * Verify the user authorization. Call krb5_kuserok if this is a local * account, or do the krb5_aname_to_localname verification if ignore_k5login * was requested. For non-local accounts, the principal must match the * authentication identity. */ int pamk5_authorized(struct pam_args *args) { struct context *ctx; krb5_context c; struct passwd *pwd; char kuser[65]; /* MAX_USERNAME == 65 (MIT Kerberos 1.4.1). */ if (args == NULL || args->ctx == NULL || args->ctx->context == NULL) return PAM_SERVICE_ERR; ctx = args->ctx; if (ctx->name == NULL) return PAM_SERVICE_ERR; c = ctx->context; /* * If alt_auth_map was set, authorize the user if the authenticated * principal matches the mapped principal. alt_auth_map essentially * serves as a supplemental .k5login. */ if (args->alt_auth_map != NULL) { char *mapped; char *authed; int retval; krb5_principal princ; if (pamk5_map_principal(args, ctx->name, &mapped) != PAM_SUCCESS) return PAM_SERVICE_ERR; retval = krb5_parse_name(c, mapped, &princ); if (retval != 0) { free(mapped); return PAM_SERVICE_ERR; } free(mapped); retval = krb5_unparse_name(c, princ, &mapped); if (retval != 0) return PAM_SERVICE_ERR; retval = krb5_unparse_name(c, ctx->princ, &authed); if (retval != 0) { free(mapped); return PAM_SERVICE_ERR; } if (strcmp(authed, mapped) == 0) { free(authed); free(mapped); return PAM_SUCCESS; } free(authed); free(mapped); } /* * If the name to which we're authenticating contains @ (is fully * qualified), it must match the principal exactly. */ if (strchr(ctx->name, '@') != NULL) { char *principal; int retval; retval = krb5_unparse_name(c, ctx->princ, &principal); if (retval != 0) return PAM_SERVICE_ERR; if (strcmp(principal, ctx->name) != 0) { free(principal); return PAM_AUTH_ERR; } return PAM_SUCCESS; } /* * Otherwise, apply either krb5_aname_to_localname or krb5_kuserok * depending on the situation. */ pwd = pam_modutil_getpwnam(args->pamh, ctx->name); if (args->ignore_k5login || pwd == NULL) { if (krb5_aname_to_localname(c, ctx->princ, sizeof(kuser), kuser) != 0) return PAM_AUTH_ERR; if (strcmp(kuser, ctx->name) != 0) return PAM_AUTH_ERR; } else { if (!krb5_kuserok(c, ctx->princ, ctx->name)) return PAM_AUTH_ERR; } return PAM_SUCCESS; }