# # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # Copyright 2014 Nexenta Systems, Inc. # # lib/pam_modules/Makefile # include $(SRC)/Makefile.master # Hammerhead: pam_krb5 / pam_krb5_migrate removed (rootfs/etc/pam.conf # already excluded these from the live PAM stack — see the simplification # header comment in pam.conf). # Hammerhead: pam_ldap removed (libsldap chain removal, Phase 1). # Hammerhead: PAM audit orphan sweep — pam_allow (GDM-autologin only; # GDM never shipped), pam_dhkeys (NIS gone), pam_dial_auth (tip gone), # pam_rhosts_auth (r-commands gone, Phase A), pam_sample (upstream # example) removed. See docs/roadmap/PAM_AUDIT_2026-06-01.md. SUBDIRS = \ authtok_get \ authtok_check \ authtok_store \ deny \ list \ passwd_auth \ roles \ timestamp \ tsol_acct \ unix_auth \ unix_account \ unix_cred \ unix_session all : TARGET= all catalog : TARGET= _msg clean : TARGET= clean clobber : TARGET= clobber install : TARGET= install _msg : TARGET= _msg .KEEP_STATE: all clean clobber install _msg: $(SUBDIRS) $(SUBDIRS): FRC @cd $@; pwd; $(MAKE) $(TARGET) FRC: # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" # # # Common build macros used by (most every) PAM module. # include $(SRC)/lib/Makefile.lib TEXT_DOMAIN= SUNW_OST_SYSOSPAM LIBS= $(DYNLIB) CFLAGS += $(CCVERBOSE) CPPFLAGS += -D_REENTRANT ROOTLIBDIR= $(ROOT)/usr/lib/security # Hammerhead: 64-bit only - flatten security library path ROOTLIBDIR64= $(ROOT)/usr/lib/security .KEEP_STATE: # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # include ../../Makefile.lib TEXT_DOMAIN= SUNW_OST_SYSOSPAM POFILE= authtok_check.po MSGFILES= authtok_check.c # Hammerhead: amd64-only SUBDIRS= $(MACH64) all : TARGET= all clean : TARGET= clean clobber : TARGET= clobber install : TARGET= install .KEEP_STATE: all clean clobber install: $(SUBDIRS) _msg: $(MSGDOMAINPOFILE) $(SUBDIRS): FRC @cd $@; pwd; $(MAKE) $(TARGET) FRC: include $(SRC)/Makefile.msg.targ include ../../Makefile.targ # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # Copyright (c) 2018, Joyent, Inc. LIBRARY= pam_authtok_check.a VERS= .1 OBJECTS= authtok_check.o \ dict.o fascist.o packer.o packlib.o rules.o stringlib.o include ../../Makefile.pam_modules LDLIBS += -lpam -lc CPPFLAGS += -D_FILE_OFFSET_BITS=64 CERRWARN += -Wno-parentheses # not linted SMATCH=off all: $(LIBS) include $(SRC)/lib/Makefile.targ * This program is copyright Alec Muffett 1993. The author disclaims all * responsibility or liability with respect to it's usage or its effect * upon hardware or computer systems, and maintains copyright as set out * in the "LICENCE" document which accompanies distributions of Crack v4.0 * and upwards. CRACKLIB SOFTWARE # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License, Version 1.0 only # (the "License"). You may not use this file except in compliance # with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2004 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" # include ../Makefile.com include ../../../Makefile.lib.64 # Hammerhead: 64-bit only - flatten passwdutil path DYNFLAGS += $(ROOT)/usr/lib/passwdutil.so.1 install: all $(ROOTLIBS64) $(ROOTLINKS64) /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * Copyright (c) 2016 by Delphix. All rights reserved. * Copyright 2023 OmniOS Community Edition (OmniOSce) Association. * Copyright 2025 RackTop Systems, Inc. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "packer.h" #include #define PWADMIN "/etc/default/passwd" #define MINLENGTH 6 #define MINDIFF 3 #define MINALPHA 2 #define MINNONALPHA 1 mutex_t dictlock = DEFAULTMUTEX; /* * We implement: * PASSLENGTH (int) minimum password length * NAMECHECK (yes/no) perform comparison of password and loginname * MINDIFF (int) minimum number of character-positions in which * the old and the new password should differ. * MINALPHA (int) minimum number of Alpha characters * MINUPPER (int) minimum number of upper-case characters * MINLOWER (int) minimum number of lower-case characters * MAXREPEATS (int) maximum number of consecutively repeating chars * WHITESPACE (yes/no) Are whitespaces allowed? * * Furthermore, these two mutualy exclusive groups of options are allowed: * * MINNONALPHA (int) minimum number of characters from the * character classes [ punct, space, digit ] * if WHITESPACE == NO, whitespaces don't count. * and * MINSPECIAL (int) minimum number of punctuation characters. * if WHITESPACE != NO, whitespace is seen as * a "special" character. * MINDIGIT (int) minimum number of digits * * specifying options from both groups results in an error to syslog and * failure to change the password. * * NOTE: * HISTORY is implemented at the repository level (passwdutil). */ /* * default password-strength-values, compiled-in or stored in PWADMIN * are kept in here */ struct pwdefaults { boolean_t server_policy; /* server policy flag from pam.conf */ uint_t minlength; /* minimum password length */ uint_t maxlength; /* maximum (significant) length */ boolean_t do_namecheck; /* check password against user's gecos */ char db_location[MAXPATHLEN]; /* location of the generated database */ boolean_t do_dictcheck; /* perform dictionary lookup */ char *dicts; /* list of dictionaries configured */ uint_t mindiff; /* old and new should differ by this much */ uint_t minalpha; /* minimum alpha characters required */ uint_t minupper; /* minimum uppercase characters required */ uint_t minlower; /* minimum lowercase characters required */ uint_t minnonalpha; /* minimum special (non alpha) required */ uint_t maxrepeat; /* maximum number of repeating chars allowed */ uint_t minspecial; /* punctuation characters */ uint_t mindigit; /* minimum number of digits required */ boolean_t whitespace; /* is whitespace allowed in a password */ }; /*PRINTFLIKE3*/ void error(pam_handle_t *pamh, int flags, char *fmt, ...) { va_list ap; char msg[1][PAM_MAX_MSG_SIZE]; va_start(ap, fmt); (void) vsnprintf(msg[0], sizeof (msg[0]), fmt, ap); va_end(ap); if ((flags & PAM_SILENT) == 0) (void) __pam_display_msg(pamh, PAM_ERROR_MSG, 1, msg, NULL); } int defread_int(char *name, uint_t *ip, void *defp) { char *q; int r = 0; if ((q = defread_r(name, defp)) != NULL) { if (!isdigit(*q)) { syslog(LOG_ERR, "pam_authtok_check: %s contains " "non-integer value for %s: %s. " "Using default instead.", PWADMIN, name, q); } else { *ip = atoi(q); r = 1; } } return (r); } /* * fill in static defaults, and augment with settings from PWADMIN * get system defaults with regard to maximum password length */ int get_passwd_defaults(pam_handle_t *pamh, const char *user, struct pwdefaults *p) { char *q; boolean_t minnonalpha_defined = B_FALSE; pwu_repository_t *pwu_rep; const struct pam_repository *pam_rep; attrlist attr[2]; int result; const char *progname; void *defp; (void) pam_get_item(pamh, PAM_SERVICE, (const void **)&progname); /* Module defaults */ p->minlength = MINLENGTH; p->do_namecheck = B_TRUE; p->do_dictcheck = B_FALSE; p->dicts = NULL; p->mindiff = MINDIFF; p->minalpha = MINALPHA; p->minnonalpha = MINNONALPHA; p->minupper = 0; /* not configured by default */ p->minlower = 0; /* not configured by default */ p->maxrepeat = 0; /* not configured by default */ p->minspecial = 0; p->mindigit = 0; p->whitespace = B_TRUE; /* * Determine the number of significant characters in a password * * we find out where the user information came from (which repository), * and which password-crypt-algorithm is to be used (based on the * old password, or the system default). * * If the user comes from a repository other than FILES/NIS * the module-flag "server_policy" means that we don't perform * any checks on the user, but let the repository decide instead. */ (void) pam_get_item(pamh, PAM_REPOSITORY, (const void **)&pam_rep); if (pam_rep != NULL) { if ((pwu_rep = calloc(1, sizeof (*pwu_rep))) == NULL) return (PAM_BUF_ERR); pwu_rep->type = pam_rep->type; pwu_rep->scope = pam_rep->scope; pwu_rep->scope_len = pam_rep->scope_len; } else { pwu_rep = PWU_DEFAULT_REP; } attr[0].type = ATTR_PASSWD; attr[0].next = &attr[1]; attr[1].type = ATTR_REP_NAME; attr[1].next = NULL; result = __get_authtoken_attr(user, pwu_rep, attr); if (pwu_rep != PWU_DEFAULT_REP) free(pwu_rep); if (result != PWU_SUCCESS) { /* * In the unlikely event that we can't obtain any info about * the users password, we assume the most strict scenario. */ p->maxlength = _PASS_MAX_XPG; } else { char *oldpw = attr[0].data.val_s; char *repository = attr[1].data.val_s; if ((strcmp(repository, "files") == 0 || strcmp(repository, "nis") == 0) || p->server_policy == B_FALSE) { char *salt; /* * We currently need to supply this dummy to * crypt_gensalt(). This will change RSN. */ struct passwd dummy; dummy.pw_name = strdup(user); if (dummy.pw_name == NULL) { free(attr[0].data.val_s); free(attr[1].data.val_s); return (PAM_BUF_ERR); } salt = crypt_gensalt(oldpw, &dummy); free(dummy.pw_name); if (salt && *salt == '$') p->maxlength = _PASS_MAX; else p->maxlength = _PASS_MAX_XPG; free(salt); p->server_policy = B_FALSE; /* we perform checks */ } else { /* not files or nis AND server_policy is set */ p->maxlength = _PASS_MAX; } free(attr[0].data.val_s); free(attr[1].data.val_s); } if ((defp = defopen_r(PWADMIN)) == NULL) return (PAM_SUCCESS); (void) defread_int("PASSLENGTH=", &p->minlength, defp); if ((q = defread_r("NAMECHECK=", defp)) != NULL && strcasecmp(q, "NO") == 0) p->do_namecheck = B_FALSE; if ((q = defread_r("DICTIONLIST=", defp)) != NULL) { if ((p->dicts = strdup(q)) == NULL) { syslog(LOG_ERR, "pam_authtok_check: out of memory"); defclose_r(defp); return (PAM_BUF_ERR); } p->do_dictcheck = B_TRUE; } else { p->dicts = NULL; } if ((q = defread_r("DICTIONDBDIR=", defp)) != NULL) { if (strlcpy(p->db_location, q, sizeof (p->db_location)) >= sizeof (p->db_location)) { syslog(LOG_ERR, "pam_authtok_check: value for " "DICTIONDBDIR too large."); defclose_r(defp); return (PAM_SYSTEM_ERR); } p->do_dictcheck = B_TRUE; } else { (void) strlcpy(p->db_location, CRACK_DIR, sizeof (p->db_location)); } (void) defread_int("MINDIFF=", &p->mindiff, defp); (void) defread_int("MINALPHA=", &p->minalpha, defp); (void) defread_int("MINUPPER=", &p->minupper, defp); (void) defread_int("MINLOWER=", &p->minlower, defp); if (defread_int("MINNONALPHA=", &p->minnonalpha, defp)) minnonalpha_defined = B_TRUE; (void) defread_int("MAXREPEATS=", &p->maxrepeat, defp); if (defread_int("MINSPECIAL=", &p->minspecial, defp)) { if (minnonalpha_defined) { syslog(LOG_ERR, "pam_authtok_check: %s contains " "definition for MINNONALPHA and for MINSPECIAL. " "These options are mutually exclusive.", PWADMIN); defclose_r(defp); return (PAM_SYSTEM_ERR); } p->minnonalpha = 0; } if (defread_int("MINDIGIT=", &p->mindigit, defp)) { if (minnonalpha_defined) { syslog(LOG_ERR, "pam_authtok_check: %s contains " "definition for MINNONALPHA and for MINDIGIT. " "These options are mutually exclusive.", PWADMIN); defclose_r(defp); return (PAM_SYSTEM_ERR); } p->minnonalpha = 0; } if ((q = defread_r("WHITESPACE=", defp)) != NULL) p->whitespace = (strcasecmp(q, "no") == 0 || strcmp(q, "0") == 0) ? B_FALSE : B_TRUE; defclose_r(defp); /* sanity check of the configured parameters */ if (p->minlength < p->mindigit + p->minspecial + p->minnonalpha + p->minalpha) { syslog(LOG_ERR, "%s: pam_authtok_check: Defined minimum " "password length (PASSLENGTH=%d) is less then minimum " "characters in the various classes (%d)", progname, p->minlength, p->mindigit + p->minspecial + p->minnonalpha + p->minalpha); p->minlength = p->mindigit + p->minspecial + p->minnonalpha + p->minalpha; syslog(LOG_ERR, "%s: pam_authtok_check: effective " "PASSLENGTH set to %d.", progname, p->minlength); /* this won't lead to failure */ } if (p->maxlength < p->minlength) { syslog(LOG_ERR, "%s: pam_authtok_check: The configured " "minimum password length (PASSLENGTH=%d) is larger than " "the number of significant characters the current " "encryption algorithm uses (%d). See policy.conf(5) for " "alternative password encryption algorithms.", progname); /* this won't lead to failure */ } return (PAM_SUCCESS); } /* * free_passwd_defaults(struct pwdefaults *p) * * free space occupied by the defaults read from PWADMIN */ void free_passwd_defaults(struct pwdefaults *p) { if (p && p->dicts) free(p->dicts); } /* * check_circular(): * This function return 1 if string "t" is a circular shift of * string "s", else it returns 0. -1 is returned on failure. * We also check to see if string "t" is a reversed-circular shift * of string "s", i.e. "ABCDE" vs. "DCBAE". */ static int check_circular(const char *s, const char *t) { const char *p; char c, *u, *o, *r, *buff, *ubuff, *pubuff; unsigned int i, j, k, l, m; size_t len; int ret = 0; i = strlen(s); l = strlen(t); if (i != l) return (0); len = i + 1; buff = malloc(len); ubuff = malloc(len); pubuff = malloc(len); if (buff == NULL || ubuff == NULL || pubuff == NULL) { syslog(LOG_ERR, "pam_authtok_check: out of memory."); free(buff); free(ubuff); free(pubuff); return (-1); } m = 2; o = &ubuff[0]; for (p = s; c = *p++; *o++ = c) { if (islower(c)) c = toupper(c); } *o = '\0'; o = &pubuff[0]; for (p = t; c = *p++; *o++ = c) { if (islower(c)) c = toupper(c); } *o = '\0'; u = &ubuff[0]; while (m--) { for (k = 0; k < i; k++) { c = *u++; o = u; l = i; r = &buff[0]; while (--l) *r++ = *o++; *r++ = c; *r = '\0'; u = &buff[0]; if (strcmp(u, pubuff) == 0) { ret = 1; goto out; } } u = u + i; r = &ubuff[0]; j = i; while (j--) *--u = *r++; /* reverse test-string for m==0 pass */ } out: (void) memset(buff, 0, len); (void) memset(ubuff, 0, len); (void) memset(pubuff, 0, len); free(buff); free(ubuff); free(pubuff); return (ret); } /* * count the different character classes present in the password. */ int check_composition(const char *pw, struct pwdefaults *pwdef, pam_handle_t *pamh, int flags) { uint_t alpha_cnt = 0; uint_t upper_cnt = 0; uint_t lower_cnt = 0; uint_t special_cnt = 0; uint_t whitespace_cnt = 0; uint_t digit_cnt = 0; uint_t maxrepeat = 0; uint_t repeat = 1; int ret = 0; const char *progname; char errmsg[256]; char lastc = '\0'; uint_t significant = pwdef->maxlength; const char *w; (void) pam_get_item(pamh, PAM_SERVICE, (const void **)&progname); /* go over the password gathering statistics */ for (w = pw; significant != 0 && *w != '\0'; w++, significant--) { if (isalpha(*w)) { alpha_cnt++; if (isupper(*w)) { upper_cnt++; } else { lower_cnt++; } } else if (isspace(*w)) whitespace_cnt++; else if (isdigit(*w)) digit_cnt++; else special_cnt++; if (*w == lastc) { if (++repeat > maxrepeat) maxrepeat = repeat; } else { repeat = 1; } lastc = *w; } /* * If we only consider part of the password (the first maxlength * characters) we give a modified error message. Otherwise, a * user entering FooBar1234 with PASSLENGTH=6, MINDIGIT=4, while * we're using the default UNIX crypt (8 chars significant), * would not understand what's going on when they're told that * "The password should contain at least 4 digits"... * Instead, we now tell them * "The first 8 characters of the password should contain at least * 4 digits." */ if (pwdef->maxlength < strlen(pw)) /* * TRANSLATION_NOTE * - Make sure the % and %% come over intact * - The last %%s will be replaced by strings like * "alphabetic character(s)" * "numeric or special character(s)" * "special character(s)" * "digit(s)" * "uppercase alpha character(s)" * "lowercase alpha character(s)" * So the final string written to the user might become * "passwd: The first 8 characters of the password must contain * at least 4 uppercase alpha characters(s)" */ (void) snprintf(errmsg, sizeof (errmsg), dgettext(TEXT_DOMAIN, "%s: The first %d characters of the password must " "contain at least %%d %%s."), progname, pwdef->maxlength); else /* * TRANSLATION_NOTE * - Make sure the % and %% come over intact * - The last %%s will be replaced by strings like * "alphabetic character(s)" * "numeric or special character(s)" * "special character(s)" * "digit(s)" * "uppercase alpha character(s)" * "lowercase alpha character(s)" * So the final string written to the user might become * "passwd: The password must contain at least 4 uppercase * alpha characters(s)" */ (void) snprintf(errmsg, sizeof (errmsg), dgettext(TEXT_DOMAIN, "%s: The password must contain at least %%d %%s."), progname); /* Check for whitespace first since it influences special counts */ if (whitespace_cnt > 0 && pwdef->whitespace == B_FALSE) { error(pamh, flags, dgettext(TEXT_DOMAIN, "%s: Whitespace characters are not allowed."), progname); ret = 1; goto out; } /* * Once we get here, whitespace_cnt is either 0, or whitespaces are * to be treated a special characters. */ if (alpha_cnt < pwdef->minalpha) { error(pamh, flags, errmsg, pwdef->minalpha, dgettext(TEXT_DOMAIN, "alphabetic character(s)")); ret = 1; goto out; } if (pwdef->minnonalpha > 0) { /* specials are defined by MINNONALPHA */ /* nonalpha = special+whitespace+digit */ if ((special_cnt + whitespace_cnt + digit_cnt) < pwdef->minnonalpha) { error(pamh, flags, errmsg, pwdef->minnonalpha, dgettext(TEXT_DOMAIN, "numeric or special character(s)")); ret = 1; goto out; } } else { /* specials are defined by MINSPECIAL and/or MINDIGIT */ if ((special_cnt + whitespace_cnt) < pwdef->minspecial) { error(pamh, flags, errmsg, pwdef->minspecial, dgettext(TEXT_DOMAIN, "special character(s)")); ret = 1; goto out; } if (digit_cnt < pwdef->mindigit) { error(pamh, flags, errmsg, pwdef->mindigit, dgettext(TEXT_DOMAIN, "digit(s)")); ret = 1; goto out; } } if (upper_cnt < pwdef->minupper) { error(pamh, flags, errmsg, pwdef->minupper, dgettext(TEXT_DOMAIN, "uppercase alpha character(s)")); ret = 1; goto out; } if (lower_cnt < pwdef->minlower) { error(pamh, flags, errmsg, pwdef->minlower, dgettext(TEXT_DOMAIN, "lowercase alpha character(s)")); ret = 1; goto out; } if (pwdef->maxrepeat > 0 && maxrepeat > pwdef->maxrepeat) { error(pamh, flags, dgettext(TEXT_DOMAIN, "%s: Too many consecutively repeating characters. " "Maximum allowed is %d."), progname, pwdef->maxrepeat); ret = 1; } out: return (ret); } /* * make sure that old and new password differ by at least 'mindiff' * positions. Return 0 if OK, 1 otherwise */ int check_diff(const char *pw, const char *opw, struct pwdefaults *pwdef, pam_handle_t *pamh, int flags) { size_t pwlen, opwlen, max; unsigned int diff; /* difference between old and new */ if (opw == NULL) opw = ""; max = pwdef->maxlength; pwlen = MIN(strlen(pw), max); opwlen = MIN(strlen(opw), max); if (pwlen > opwlen) diff = pwlen - opwlen; else diff = opwlen - pwlen; while (*opw != '\0' && *pw != '\0' && max-- != 0) { if (*opw != *pw) diff++; opw++; pw++; } if (diff < pwdef->mindiff) { const char *progname; (void) pam_get_item(pamh, PAM_SERVICE, (const void **)&progname); error(pamh, flags, dgettext(TEXT_DOMAIN, "%s: The first %d characters of the old and new passwords " "must differ by at least %d positions."), progname, pwdef->maxlength, pwdef->mindiff); return (1); } return (0); } /* * check to see if password is in one way or another based on a * dictionary word. Returns 0 if password is OK, 1 if it is based * on a dictionary word and hence should be rejected. */ int check_dictionary(const char *pw, struct pwdefaults *pwdef, pam_handle_t *pamh, int flags) { int crack_ret; int ret; const char *progname; (void) pam_get_item(pamh, PAM_SERVICE, (const void **)&progname); /* dictionary check isn't MT-safe */ (void) mutex_lock(&dictlock); if (pwdef->dicts && make_dict_database(pwdef->dicts, pwdef->db_location) != 0) { (void) mutex_unlock(&dictlock); syslog(LOG_ERR, "pam_authtok_check:pam_sm_chauthtok: " "Dictionary database not present."); error(pamh, flags, dgettext(TEXT_DOMAIN, "%s: password dictionary missing."), progname); return (PAM_SYSTEM_ERR); } crack_ret = DictCheck(pw, pwdef->db_location); (void) mutex_unlock(&dictlock); switch (crack_ret) { case DATABASE_OPEN_FAIL: syslog(LOG_ERR, "pam_authtok_check:pam_sm_chauthtok: " "dictionary database open failure: %s", strerror(errno)); error(pamh, flags, dgettext(TEXT_DOMAIN, "%s: failed to open dictionary database."), progname); ret = PAM_SYSTEM_ERR; break; case DICTIONARY_WORD: error(pamh, flags, dgettext(TEXT_DOMAIN, "%s: password is based on a dictionary word."), progname); ret = PAM_AUTHTOK_ERR; break; case REVERSE_DICTIONARY_WORD: error(pamh, flags, dgettext(TEXT_DOMAIN, "%s: password is based on a reversed dictionary word."), progname); ret = PAM_AUTHTOK_ERR; break; default: ret = PAM_SUCCESS; break; } return (ret); } int pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, const char **argv) { int debug = 0; int retcode = 0; int force_check = 0; int i; size_t pwlen; const char *usrname; const char *pwbuf, *opwbuf; pwu_repository_t *pwu_rep = PWU_DEFAULT_REP; const pam_repository_t *pwd_rep = NULL; struct pwdefaults pwdef; const char *progname; /* needs to be set before option processing */ pwdef.server_policy = B_FALSE; for (i = 0; i < argc; i++) { if (strcmp(argv[i], "debug") == 0) debug = 1; if (strcmp(argv[i], "force_check") == 0) force_check = 1; if (strcmp(argv[i], "server_policy") == 0) pwdef.server_policy = B_TRUE; } if (debug) syslog(LOG_AUTH | LOG_DEBUG, "pam_authtok_check: pam_sm_chauthok called(%x) " "force_check = %d", flags, force_check); if ((flags & PAM_PRELIM_CHECK) == 0) return (PAM_IGNORE); (void) pam_get_item(pamh, PAM_SERVICE, (const void **)&progname); (void) pam_get_item(pamh, PAM_USER, (const void **)&usrname); if (usrname == NULL || *usrname == '\0') { syslog(LOG_ERR, "pam_authtok_check: username name is empty"); return (PAM_USER_UNKNOWN); } (void) pam_get_item(pamh, PAM_AUTHTOK, (const void **)&pwbuf); (void) pam_get_item(pamh, PAM_OLDAUTHTOK, (const void **)&opwbuf); if (pwbuf == NULL) return (PAM_AUTHTOK_ERR); /* none of these checks holds if caller say so */ if ((flags & PAM_NO_AUTHTOK_CHECK) != 0 && force_check == 0) return (PAM_SUCCESS); /* read system-defaults */ retcode = get_passwd_defaults(pamh, usrname, &pwdef); if (retcode != PAM_SUCCESS) return (retcode); if (debug) { syslog(LOG_AUTH | LOG_DEBUG, "pam_authtok_check: MAXLENGTH= %d, server_policy = %s", pwdef.maxlength, pwdef.server_policy ? "true" : "false"); syslog(LOG_AUTH | LOG_DEBUG, "pam_authtok_check: PASSLENGTH= %d", pwdef.minlength); syslog(LOG_AUTH | LOG_DEBUG, "pam_authtok_check: NAMECHECK=%s", pwdef.do_namecheck == B_TRUE ? "Yes" : "No"); syslog(LOG_AUTH | LOG_DEBUG, "pam_authtok_check: do_dictcheck = %s\n", pwdef.do_dictcheck ? "true" : "false"); if (pwdef.do_dictcheck) { syslog(LOG_AUTH | LOG_DEBUG, "pam_authtok_check: DICTIONLIST=%s", (pwdef.dicts != NULL) ? pwdef.dicts : ""); syslog(LOG_AUTH | LOG_DEBUG, "pam_authtok_check: DICTIONDBDIR=%s", pwdef.db_location); } syslog(LOG_AUTH | LOG_DEBUG, "pam_authtok_check: MINDIFF=%d", pwdef.mindiff); syslog(LOG_AUTH | LOG_DEBUG, "pam_authtok_check: MINALPHA=%d, MINNONALPHA=%d", pwdef.minalpha, pwdef.minnonalpha); syslog(LOG_AUTH | LOG_DEBUG, "pam_authtok_check: MINSPECIAL=%d, MINDIGIT=%d", pwdef.minspecial, pwdef.mindigit); syslog(LOG_AUTH | LOG_DEBUG, "pam_authtok_check: WHITESPACE=%s", pwdef.whitespace ? "YES" : "NO"); syslog(LOG_AUTH | LOG_DEBUG, "pam_authtok_check: MINUPPER=%d, MINLOWER=%d", pwdef.minupper, pwdef.minlower); syslog(LOG_AUTH | LOG_DEBUG, "pam_authtok_check: MAXREPEATS=%d", pwdef.maxrepeat); } /* * If server policy is still true (might be changed from the * value specified in /etc/pam.conf by get_passwd_defaults()), * we return ignore and let the server do all the checks. */ if (pwdef.server_policy == B_TRUE) { free_passwd_defaults(&pwdef); return (PAM_IGNORE); } /* * XXX: JV: we can't really make any assumption on the length of * the password that will be used by the crypto algorithm. * for UNIX-style encryption, minalpha=5,minnonalpha=5 might * be impossible, but not for MD5 style hashes... what to do? * * since we don't know what alg. will be used, we operate on * the password as entered, so we don't sanity check anything * for now. */ /* * Make sure new password is long enough */ pwlen = strlen(pwbuf); if (pwlen < pwdef.minlength) { error(pamh, flags, dgettext(TEXT_DOMAIN, "%s: Password too short - must be at least %d " "characters."), progname, pwdef.minlength); free_passwd_defaults(&pwdef); return (PAM_AUTHTOK_ERR); } /* Make sure the password doesn't equal--a shift of--the username */ if (pwdef.do_namecheck) { switch (check_circular(usrname, pwbuf)) { case 1: error(pamh, flags, dgettext(TEXT_DOMAIN, "%s: Password cannot be circular shift of " "logonid."), progname); free_passwd_defaults(&pwdef); return (PAM_AUTHTOK_ERR); case -1: free_passwd_defaults(&pwdef); return (PAM_BUF_ERR); default: break; } } /* Check if new password is in history list. */ (void) pam_get_item(pamh, PAM_REPOSITORY, (const void **)&pwd_rep); if (pwd_rep != NULL) { if ((pwu_rep = calloc(1, sizeof (*pwu_rep))) == NULL) return (PAM_BUF_ERR); pwu_rep->type = pwd_rep->type; pwu_rep->scope = pwd_rep->scope; pwu_rep->scope_len = pwd_rep->scope_len; } if (__check_history(usrname, pwbuf, pwu_rep) == PWU_SUCCESS) { /* password found in history */ error(pamh, flags, dgettext(TEXT_DOMAIN, "%s: Password in history list."), progname); if (pwu_rep != PWU_DEFAULT_REP) free(pwu_rep); free_passwd_defaults(&pwdef); return (PAM_AUTHTOK_ERR); } if (pwu_rep != PWU_DEFAULT_REP) free(pwu_rep); /* check MINALPHA, MINLOWER, etc. */ if (check_composition(pwbuf, &pwdef, pamh, flags) != 0) { free_passwd_defaults(&pwdef); return (PAM_AUTHTOK_ERR); } /* make sure the old and new password are not too much alike */ if (check_diff(pwbuf, opwbuf, &pwdef, pamh, flags) != 0) { free_passwd_defaults(&pwdef); return (PAM_AUTHTOK_ERR); } /* dictionary check */ if (pwdef.do_dictcheck) { retcode = check_dictionary(pwbuf, &pwdef, pamh, flags); if (retcode != PAM_SUCCESS) { free_passwd_defaults(&pwdef); return (retcode); } } free_passwd_defaults(&pwdef); /* password has passed all tests: it's strong enough */ return (PAM_SUCCESS); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include "packer.h" static int lockfd = -1; static struct flock flock = { 0, 0, 0, 0, 0, 0 }; char dblock[PATH_MAX]; #define LOCK_WAIT 1000000 #define LOCK_RETRIES 60 /* * lock_db() * * Create a lockfile to prevent simultaneous access to the database * creation routines. We set a timeout to LOCK_WAIT seconds. If we * haven't obtained a lock after LOCK_RETIRES attempts, we bail out. * * returns 0 on succes, -1 on (lock) failure. * side effect: the directory "path" will be created if it didn't exist. */ int lock_db(char *path) { int retval; struct stat st; int retries = 0; /* create directory "path" if it doesn't exist */ if (stat(path, &st) == -1) { if (errno != ENOENT || (mkdir(path, 0755) == -1 || chmod(path, 0755) == -1)) return (-1); } (void) snprintf(dblock, sizeof (dblock), "%s/authtok_check.lock", path); if ((lockfd = open(dblock, O_WRONLY|O_CREAT|O_EXCL, 0400)) == -1) { if (errno == EEXIST) lockfd = open(dblock, O_WRONLY); if (lockfd == -1) { int olderrno = errno; syslog(LOG_ERR, "pam_authtok_check::pam_sm_chauthtok: " "can't open lockfile: %s", strerror(errno)); errno = olderrno; return (-1); } } do { flock.l_type = F_WRLCK; retval = fcntl(lockfd, F_SETLK, &flock); if (retval == -1) (void) usleep(LOCK_WAIT); } while (retval == -1 && ++retries < LOCK_RETRIES); if (retval == -1) { int errno_saved = errno; syslog(LOG_ERR, "pam_authtok_check::pam_sm_chauthtok: timeout " "waiting for dictionary lock."); errno = errno_saved; } return (retval); } /* * unlock_db() * * Release the database lock */ void unlock_db(void) { if (lockfd != -1) { flock.l_type = F_UNLCK; (void) fcntl(lockfd, F_SETLK, &flock); (void) close(lockfd); lockfd = -1; } } /* * database_present() * * returns 0 if the database files are found, and the database size is * greater than 0 and the database version matches the current version. */ int database_present(char *path) { struct stat st; char dict_hwm[PATH_MAX]; char dict_pwd[PATH_MAX]; char dict_pwi[PATH_MAX]; PWDICT *dict; (void) snprintf(dict_hwm, sizeof (dict_hwm), "%s/%s", path, DICT_DATABASE_HWM); (void) snprintf(dict_pwd, sizeof (dict_pwd), "%s/%s", path, DICT_DATABASE_PWD); (void) snprintf(dict_pwi, sizeof (dict_pwi), "%s/%s", path, DICT_DATABASE_PWI); if (stat(dict_hwm, &st) == -1 || (stat(dict_pwd, &st) == -1 || st.st_size == 0) || stat(dict_pwi, &st) == -1) return (NO_DICTDATABASE); /* verify database version number by trying to open it */ if ((dict = PWOpen(path, "r")) == NULL) { /* the files are there, but an outdated version */ PWRemove(path); return (NO_DICTDATABASE); } (void) PWClose(dict); return (0); } /* * build_dict_database(list, char *path) * * Create the Crack Dictionary Database based on the list of sources * dictionaries specified in "list". Store the database in "path". */ int build_dict_database(char *list, char *path) { return (packer(list, path) == -1 ? DICTDATABASE_BUILD_ERR : 0); } /* * Rebuild the database in "path" if the database is older than one of the * files listed in "list", or older than the config-file PWADMIN. */ int update_dict_database(char *list, char *path) { struct stat st_db; struct stat st_file; char *buf; char *listcopy; boolean_t update_needed = B_FALSE; char dbase_pwd[PATH_MAX]; (void) snprintf(dbase_pwd, sizeof (dbase_pwd), "%s/%s", path, DICT_DATABASE_PWD); if (stat(dbase_pwd, &st_db) == -1) return (DICTFILE_ERR); if ((listcopy = strdup(list)) == NULL) return (DICTFILE_ERR); buf = strtok(listcopy, "\t ,"); /* Compare mtime of each listed dictionary against DB mtime */ while (update_needed == B_FALSE && buf != NULL) { if (stat(buf, &st_file) == -1) { if (errno == ENOENT) { syslog(LOG_ERR, "pam_authtok_check:update_dict_database: " "dictionary \"%s\" not present.", buf); } else { syslog(LOG_ERR, "pam_authtok_check:update_dict_database: " "stat(%s) failed: %s", buf, strerror(errno)); } free(listcopy); return (DICTFILE_ERR); } if (st_db.st_mtime < st_file.st_mtime) update_needed = B_TRUE; /* database out of date */ buf = strtok(NULL, "\t ,"); } free(listcopy); /* * If /etc/default/passwd is updated, generate the database. * Because this is the only way we can check if files have been * added/deleted from DICTIONLIST. * Drawback: the database will also be generated when other * tunables are changed. */ if (stat(PWADMIN, &st_file) != -1 && st_db.st_mtime < st_file.st_mtime) update_needed = B_TRUE; if (update_needed) { /* * Since we actually rebuild the database, we need to remove * the old database first. */ PWRemove(path); return (build_dict_database(list, path)); } return (0); } /* * Build or update database, while holding the global lock. */ int make_dict_database(char *list, char *path) { int r = -1; if (lock_db(path) == 0) { if (database_present(path) == NO_DICTDATABASE) r = build_dict_database(list, path); else r = update_dict_database(list, path); unlock_db(); } return (r); } /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * Copyright 2024 OmniOS Community Edition (OmniOSce) Association. */ /* * This program is copyright Alec Muffett 1993. The author disclaims all * responsibility or liability with respect to it's usage or its effect * upon hardware or computer systems, and maintains copyright as set out * in the "LICENCE" document which accompanies distributions of Crack v4.0 * and upwards. */ #include "packer.h" static char *r_destructors[] = { ":", /* noop - must do this to test raw word. */ "[", /* trimming leading/trailing junk */ "]", "[[", "]]", "[[[", "]]]", "/?p@?p", /* purging out punctuation/symbols/junk */ "/?s@?s", "/?X@?X", /* attempt reverse engineering of password strings */ "/$s$s", "/$s$s/0s0o", "/$s$s/0s0o/2s2a", "/$s$s/0s0o/2s2a/3s3e", "/$s$s/0s0o/2s2a/3s3e/5s5s", "/$s$s/0s0o/2s2a/3s3e/5s5s/1s1i", "/$s$s/0s0o/2s2a/3s3e/5s5s/1s1l", "/$s$s/0s0o/2s2a/3s3e/5s5s/1s1i/4s4a", "/$s$s/0s0o/2s2a/3s3e/5s5s/1s1i/4s4h", "/$s$s/0s0o/2s2a/3s3e/5s5s/1s1l/4s4a", "/$s$s/0s0o/2s2a/3s3e/5s5s/1s1l/4s4h", "/$s$s/0s0o/2s2a/3s3e/5s5s/4s4a", "/$s$s/0s0o/2s2a/3s3e/5s5s/4s4h", "/$s$s/0s0o/2s2a/3s3e/5s5s/4s4a", "/$s$s/0s0o/2s2a/3s3e/5s5s/4s4h", "/$s$s/0s0o/2s2a/3s3e/1s1i", "/$s$s/0s0o/2s2a/3s3e/1s1l", "/$s$s/0s0o/2s2a/3s3e/1s1i/4s4a", "/$s$s/0s0o/2s2a/3s3e/1s1i/4s4h", "/$s$s/0s0o/2s2a/3s3e/1s1l/4s4a", "/$s$s/0s0o/2s2a/3s3e/1s1l/4s4h", "/$s$s/0s0o/2s2a/3s3e/4s4a", "/$s$s/0s0o/2s2a/3s3e/4s4h", "/$s$s/0s0o/2s2a/3s3e/4s4a", "/$s$s/0s0o/2s2a/3s3e/4s4h", "/$s$s/0s0o/2s2a/5s5s", "/$s$s/0s0o/2s2a/5s5s/1s1i", "/$s$s/0s0o/2s2a/5s5s/1s1l", "/$s$s/0s0o/2s2a/5s5s/1s1i/4s4a", "/$s$s/0s0o/2s2a/5s5s/1s1i/4s4h", "/$s$s/0s0o/2s2a/5s5s/1s1l/4s4a", "/$s$s/0s0o/2s2a/5s5s/1s1l/4s4h", "/$s$s/0s0o/2s2a/5s5s/4s4a", "/$s$s/0s0o/2s2a/5s5s/4s4h", "/$s$s/0s0o/2s2a/5s5s/4s4a", "/$s$s/0s0o/2s2a/5s5s/4s4h", "/$s$s/0s0o/2s2a/1s1i", "/$s$s/0s0o/2s2a/1s1l", "/$s$s/0s0o/2s2a/1s1i/4s4a", "/$s$s/0s0o/2s2a/1s1i/4s4h", "/$s$s/0s0o/2s2a/1s1l/4s4a", "/$s$s/0s0o/2s2a/1s1l/4s4h", "/$s$s/0s0o/2s2a/4s4a", "/$s$s/0s0o/2s2a/4s4h", "/$s$s/0s0o/2s2a/4s4a", "/$s$s/0s0o/2s2a/4s4h", "/$s$s/0s0o/3s3e", "/$s$s/0s0o/3s3e/5s5s", "/$s$s/0s0o/3s3e/5s5s/1s1i", "/$s$s/0s0o/3s3e/5s5s/1s1l", "/$s$s/0s0o/3s3e/5s5s/1s1i/4s4a", "/$s$s/0s0o/3s3e/5s5s/1s1i/4s4h", "/$s$s/0s0o/3s3e/5s5s/1s1l/4s4a", "/$s$s/0s0o/3s3e/5s5s/1s1l/4s4h", "/$s$s/0s0o/3s3e/5s5s/4s4a", "/$s$s/0s0o/3s3e/5s5s/4s4h", "/$s$s/0s0o/3s3e/5s5s/4s4a", "/$s$s/0s0o/3s3e/5s5s/4s4h", "/$s$s/0s0o/3s3e/1s1i", "/$s$s/0s0o/3s3e/1s1l", "/$s$s/0s0o/3s3e/1s1i/4s4a", "/$s$s/0s0o/3s3e/1s1i/4s4h", "/$s$s/0s0o/3s3e/1s1l/4s4a", "/$s$s/0s0o/3s3e/1s1l/4s4h", "/$s$s/0s0o/3s3e/4s4a", "/$s$s/0s0o/3s3e/4s4h", "/$s$s/0s0o/3s3e/4s4a", "/$s$s/0s0o/3s3e/4s4h", "/$s$s/0s0o/5s5s", "/$s$s/0s0o/5s5s/1s1i", "/$s$s/0s0o/5s5s/1s1l", "/$s$s/0s0o/5s5s/1s1i/4s4a", "/$s$s/0s0o/5s5s/1s1i/4s4h", "/$s$s/0s0o/5s5s/1s1l/4s4a", "/$s$s/0s0o/5s5s/1s1l/4s4h", "/$s$s/0s0o/5s5s/4s4a", "/$s$s/0s0o/5s5s/4s4h", "/$s$s/0s0o/5s5s/4s4a", "/$s$s/0s0o/5s5s/4s4h", "/$s$s/0s0o/1s1i", "/$s$s/0s0o/1s1l", "/$s$s/0s0o/1s1i/4s4a", "/$s$s/0s0o/1s1i/4s4h", "/$s$s/0s0o/1s1l/4s4a", "/$s$s/0s0o/1s1l/4s4h", "/$s$s/0s0o/4s4a", "/$s$s/0s0o/4s4h", "/$s$s/0s0o/4s4a", "/$s$s/0s0o/4s4h", "/$s$s/2s2a", "/$s$s/2s2a/3s3e", "/$s$s/2s2a/3s3e/5s5s", "/$s$s/2s2a/3s3e/5s5s/1s1i", "/$s$s/2s2a/3s3e/5s5s/1s1l", "/$s$s/2s2a/3s3e/5s5s/1s1i/4s4a", "/$s$s/2s2a/3s3e/5s5s/1s1i/4s4h", "/$s$s/2s2a/3s3e/5s5s/1s1l/4s4a", "/$s$s/2s2a/3s3e/5s5s/1s1l/4s4h", "/$s$s/2s2a/3s3e/5s5s/4s4a", "/$s$s/2s2a/3s3e/5s5s/4s4h", "/$s$s/2s2a/3s3e/5s5s/4s4a", "/$s$s/2s2a/3s3e/5s5s/4s4h", "/$s$s/2s2a/3s3e/1s1i", "/$s$s/2s2a/3s3e/1s1l", "/$s$s/2s2a/3s3e/1s1i/4s4a", "/$s$s/2s2a/3s3e/1s1i/4s4h", "/$s$s/2s2a/3s3e/1s1l/4s4a", "/$s$s/2s2a/3s3e/1s1l/4s4h", "/$s$s/2s2a/3s3e/4s4a", "/$s$s/2s2a/3s3e/4s4h", "/$s$s/2s2a/3s3e/4s4a", "/$s$s/2s2a/3s3e/4s4h", "/$s$s/2s2a/5s5s", "/$s$s/2s2a/5s5s/1s1i", "/$s$s/2s2a/5s5s/1s1l", "/$s$s/2s2a/5s5s/1s1i/4s4a", "/$s$s/2s2a/5s5s/1s1i/4s4h", "/$s$s/2s2a/5s5s/1s1l/4s4a", "/$s$s/2s2a/5s5s/1s1l/4s4h", "/$s$s/2s2a/5s5s/4s4a", "/$s$s/2s2a/5s5s/4s4h", "/$s$s/2s2a/5s5s/4s4a", "/$s$s/2s2a/5s5s/4s4h", "/$s$s/2s2a/1s1i", "/$s$s/2s2a/1s1l", "/$s$s/2s2a/1s1i/4s4a", "/$s$s/2s2a/1s1i/4s4h", "/$s$s/2s2a/1s1l/4s4a", "/$s$s/2s2a/1s1l/4s4h", "/$s$s/2s2a/4s4a", "/$s$s/2s2a/4s4h", "/$s$s/2s2a/4s4a", "/$s$s/2s2a/4s4h", "/$s$s/3s3e", "/$s$s/3s3e/5s5s", "/$s$s/3s3e/5s5s/1s1i", "/$s$s/3s3e/5s5s/1s1l", "/$s$s/3s3e/5s5s/1s1i/4s4a", "/$s$s/3s3e/5s5s/1s1i/4s4h", "/$s$s/3s3e/5s5s/1s1l/4s4a", "/$s$s/3s3e/5s5s/1s1l/4s4h", "/$s$s/3s3e/5s5s/4s4a", "/$s$s/3s3e/5s5s/4s4h", "/$s$s/3s3e/5s5s/4s4a", "/$s$s/3s3e/5s5s/4s4h", "/$s$s/3s3e/1s1i", "/$s$s/3s3e/1s1l", "/$s$s/3s3e/1s1i/4s4a", "/$s$s/3s3e/1s1i/4s4h", "/$s$s/3s3e/1s1l/4s4a", "/$s$s/3s3e/1s1l/4s4h", "/$s$s/3s3e/4s4a", "/$s$s/3s3e/4s4h", "/$s$s/3s3e/4s4a", "/$s$s/3s3e/4s4h", "/$s$s/5s5s", "/$s$s/5s5s/1s1i", "/$s$s/5s5s/1s1l", "/$s$s/5s5s/1s1i/4s4a", "/$s$s/5s5s/1s1i/4s4h", "/$s$s/5s5s/1s1l/4s4a", "/$s$s/5s5s/1s1l/4s4h", "/$s$s/5s5s/4s4a", "/$s$s/5s5s/4s4h", "/$s$s/5s5s/4s4a", "/$s$s/5s5s/4s4h", "/$s$s/1s1i", "/$s$s/1s1l", "/$s$s/1s1i/4s4a", "/$s$s/1s1i/4s4h", "/$s$s/1s1l/4s4a", "/$s$s/1s1l/4s4h", "/$s$s/4s4a", "/$s$s/4s4h", "/$s$s/4s4a", "/$s$s/4s4h", "/0s0o", "/0s0o/2s2a", "/0s0o/2s2a/3s3e", "/0s0o/2s2a/3s3e/5s5s", "/0s0o/2s2a/3s3e/5s5s/1s1i", "/0s0o/2s2a/3s3e/5s5s/1s1l", "/0s0o/2s2a/3s3e/5s5s/1s1i/4s4a", "/0s0o/2s2a/3s3e/5s5s/1s1i/4s4h", "/0s0o/2s2a/3s3e/5s5s/1s1l/4s4a", "/0s0o/2s2a/3s3e/5s5s/1s1l/4s4h", "/0s0o/2s2a/3s3e/5s5s/4s4a", "/0s0o/2s2a/3s3e/5s5s/4s4h", "/0s0o/2s2a/3s3e/5s5s/4s4a", "/0s0o/2s2a/3s3e/5s5s/4s4h", "/0s0o/2s2a/3s3e/1s1i", "/0s0o/2s2a/3s3e/1s1l", "/0s0o/2s2a/3s3e/1s1i/4s4a", "/0s0o/2s2a/3s3e/1s1i/4s4h", "/0s0o/2s2a/3s3e/1s1l/4s4a", "/0s0o/2s2a/3s3e/1s1l/4s4h", "/0s0o/2s2a/3s3e/4s4a", "/0s0o/2s2a/3s3e/4s4h", "/0s0o/2s2a/3s3e/4s4a", "/0s0o/2s2a/3s3e/4s4h", "/0s0o/2s2a/5s5s", "/0s0o/2s2a/5s5s/1s1i", "/0s0o/2s2a/5s5s/1s1l", "/0s0o/2s2a/5s5s/1s1i/4s4a", "/0s0o/2s2a/5s5s/1s1i/4s4h", "/0s0o/2s2a/5s5s/1s1l/4s4a", "/0s0o/2s2a/5s5s/1s1l/4s4h", "/0s0o/2s2a/5s5s/4s4a", "/0s0o/2s2a/5s5s/4s4h", "/0s0o/2s2a/5s5s/4s4a", "/0s0o/2s2a/5s5s/4s4h", "/0s0o/2s2a/1s1i", "/0s0o/2s2a/1s1l", "/0s0o/2s2a/1s1i/4s4a", "/0s0o/2s2a/1s1i/4s4h", "/0s0o/2s2a/1s1l/4s4a", "/0s0o/2s2a/1s1l/4s4h", "/0s0o/2s2a/4s4a", "/0s0o/2s2a/4s4h", "/0s0o/2s2a/4s4a", "/0s0o/2s2a/4s4h", "/0s0o/3s3e", "/0s0o/3s3e/5s5s", "/0s0o/3s3e/5s5s/1s1i", "/0s0o/3s3e/5s5s/1s1l", "/0s0o/3s3e/5s5s/1s1i/4s4a", "/0s0o/3s3e/5s5s/1s1i/4s4h", "/0s0o/3s3e/5s5s/1s1l/4s4a", "/0s0o/3s3e/5s5s/1s1l/4s4h", "/0s0o/3s3e/5s5s/4s4a", "/0s0o/3s3e/5s5s/4s4h", "/0s0o/3s3e/5s5s/4s4a", "/0s0o/3s3e/5s5s/4s4h", "/0s0o/3s3e/1s1i", "/0s0o/3s3e/1s1l", "/0s0o/3s3e/1s1i/4s4a", "/0s0o/3s3e/1s1i/4s4h", "/0s0o/3s3e/1s1l/4s4a", "/0s0o/3s3e/1s1l/4s4h", "/0s0o/3s3e/4s4a", "/0s0o/3s3e/4s4h", "/0s0o/3s3e/4s4a", "/0s0o/3s3e/4s4h", "/0s0o/5s5s", "/0s0o/5s5s/1s1i", "/0s0o/5s5s/1s1l", "/0s0o/5s5s/1s1i/4s4a", "/0s0o/5s5s/1s1i/4s4h", "/0s0o/5s5s/1s1l/4s4a", "/0s0o/5s5s/1s1l/4s4h", "/0s0o/5s5s/4s4a", "/0s0o/5s5s/4s4h", "/0s0o/5s5s/4s4a", "/0s0o/5s5s/4s4h", "/0s0o/1s1i", "/0s0o/1s1l", "/0s0o/1s1i/4s4a", "/0s0o/1s1i/4s4h", "/0s0o/1s1l/4s4a", "/0s0o/1s1l/4s4h", "/0s0o/4s4a", "/0s0o/4s4h", "/0s0o/4s4a", "/0s0o/4s4h", "/2s2a", "/2s2a/3s3e", "/2s2a/3s3e/5s5s", "/2s2a/3s3e/5s5s/1s1i", "/2s2a/3s3e/5s5s/1s1l", "/2s2a/3s3e/5s5s/1s1i/4s4a", "/2s2a/3s3e/5s5s/1s1i/4s4h", "/2s2a/3s3e/5s5s/1s1l/4s4a", "/2s2a/3s3e/5s5s/1s1l/4s4h", "/2s2a/3s3e/5s5s/4s4a", "/2s2a/3s3e/5s5s/4s4h", "/2s2a/3s3e/5s5s/4s4a", "/2s2a/3s3e/5s5s/4s4h", "/2s2a/3s3e/1s1i", "/2s2a/3s3e/1s1l", "/2s2a/3s3e/1s1i/4s4a", "/2s2a/3s3e/1s1i/4s4h", "/2s2a/3s3e/1s1l/4s4a", "/2s2a/3s3e/1s1l/4s4h", "/2s2a/3s3e/4s4a", "/2s2a/3s3e/4s4h", "/2s2a/3s3e/4s4a", "/2s2a/3s3e/4s4h", "/2s2a/5s5s", "/2s2a/5s5s/1s1i", "/2s2a/5s5s/1s1l", "/2s2a/5s5s/1s1i/4s4a", "/2s2a/5s5s/1s1i/4s4h", "/2s2a/5s5s/1s1l/4s4a", "/2s2a/5s5s/1s1l/4s4h", "/2s2a/5s5s/4s4a", "/2s2a/5s5s/4s4h", "/2s2a/5s5s/4s4a", "/2s2a/5s5s/4s4h", "/2s2a/1s1i", "/2s2a/1s1l", "/2s2a/1s1i/4s4a", "/2s2a/1s1i/4s4h", "/2s2a/1s1l/4s4a", "/2s2a/1s1l/4s4h", "/2s2a/4s4a", "/2s2a/4s4h", "/2s2a/4s4a", "/2s2a/4s4h", "/3s3e", "/3s3e/5s5s", "/3s3e/5s5s/1s1i", "/3s3e/5s5s/1s1l", "/3s3e/5s5s/1s1i/4s4a", "/3s3e/5s5s/1s1i/4s4h", "/3s3e/5s5s/1s1l/4s4a", "/3s3e/5s5s/1s1l/4s4h", "/3s3e/5s5s/4s4a", "/3s3e/5s5s/4s4h", "/3s3e/5s5s/4s4a", "/3s3e/5s5s/4s4h", "/3s3e/1s1i", "/3s3e/1s1l", "/3s3e/1s1i/4s4a", "/3s3e/1s1i/4s4h", "/3s3e/1s1l/4s4a", "/3s3e/1s1l/4s4h", "/3s3e/4s4a", "/3s3e/4s4h", "/3s3e/4s4a", "/3s3e/4s4h", "/5s5s", "/5s5s/1s1i", "/5s5s/1s1l", "/5s5s/1s1i/4s4a", "/5s5s/1s1i/4s4h", "/5s5s/1s1l/4s4a", "/5s5s/1s1l/4s4h", "/5s5s/4s4a", "/5s5s/4s4h", "/5s5s/4s4a", "/5s5s/4s4h", "/1s1i", "/1s1l", "/1s1i/4s4a", "/1s1i/4s4h", "/1s1l/4s4a", "/1s1l/4s4h", "/4s4a", "/4s4h", "/4s4a", "/4s4h", /* done */ (char *)0 }; int FascistLook(PWDICT *pwp, const char *instring) { int i; char *password; uint32_t notfound; char rpassword[PATH_MAX]; notfound = PW_WORDS(pwp); (void) strlcpy(rpassword, instring, TRUNCSTRINGSIZE); password = rpassword; (void) strcpy(password, Lowercase(password)); (void) Trim(password); /* * it should be safe to use Mangle with its reliance on PATH_SIZE * since password cannot be longer than TRUNCSTRINGSIZE; * nonetheless this is not an elegant solution */ for (i = 0; r_destructors[i]; i++) { char *a; if (!(a = Mangle(password, r_destructors[i]))) { continue; } if (FindPW(pwp, a) != notfound) { return (DICTIONARY_WORD); } } (void) strlcpy(password, Reverse(password), PATH_MAX); for (i = 0; r_destructors[i]; i++) { char *a; if (!(a = Mangle(password, r_destructors[i]))) { continue; } if (FindPW(pwp, a) != notfound) { return (REVERSE_DICTIONARY_WORD); } } return (0); } int DictCheck(const char *password, char *path) { PWDICT *pwp; int r; if ((pwp = PWOpen(path, "rF")) == NULL) return (DATABASE_OPEN_FAIL); r = FascistLook(pwp, password); (void) PWClose(pwp); return (r); } # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. # # # MAPFILE HEADER START # # WARNING: STOP NOW. DO NOT MODIFY THIS FILE. # Object versioning must comply with the rules detailed in # # usr/src/lib/README.mapfiles # # You should not be making modifications here until you've read the most current # copy of that file. If you need help, contact a gatekeeper for guidance. # # MAPFILE HEADER END # $mapfile_version 2 SYMBOL_VERSION SUNW_1.1 { global: pam_sm_chauthtok; local: *; }; /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include "packer.h" /* * This file steers the creation of the Crack Dictionary Database. * Based on a list of source dictionaries specified by the administrator, * we create the Database by sorting each dictionary (in memory, one at * a time), writing the sorted result to a temporary file, and merging * all the temporary files into the Database. * * The current implementation has a number of limitations * - each single source dictionary has to fit in memory * - each single source dictionary has to be smaller than 2GByte * - each single source dictionary can only hold up to 4GB words * None of these seem real, practical, problems to me. * * All of this is meant to be run by one thread per host. The caller is * responsible for locking things appropriately (as make_dict_database * in dict.c does). */ #include #include #include #include #include #include #include #include /* Stuff used for sorting the dictionary */ static char *buf; /* used to hold the source dictionary */ static uint_t *offsets; /* array of word-offsets into "buf" */ static uint_t off_idx = 0; /* first free index in offsets array */ static size_t off_size = 0; /* offsets array size */ /* stuff to keep track of the temporary files */ #define FNAME_TEMPLATE "/var/tmp/authtok_check.XXXXXX" #define MAXTMP 64 static FILE *tmpfp[MAXTMP]; /* FILE *'s to (unlinked) temporary files */ static int tmpfp_idx = 0; /* points to first free entry in tmpfp */ #define MODNAME "pam_authtok_check::packer" /* * int writeout(void) * * Write the sorted wordlist to disk. We create a temporary file * (in /var/tmp), and immediately unlink() it. We keep an open * FILE pointer to it in tmpfp[] for later use. * * returns 0 on success, -1 on failure (can't create file/output failure). */ int writeout(void) { int i = 0; char tmpname[sizeof (FNAME_TEMPLATE)]; int fd; if (tmpfp_idx == MAXTMP) { syslog(LOG_ERR, MODNAME ": too many temporary " "files (maximum %d exceeded)", MAXTMP); return (-1); } (void) strcpy(tmpname, FNAME_TEMPLATE); if ((fd = mkstemp(tmpname)) == -1) { syslog(LOG_ERR, MODNAME ": mkstemp() failed: %s\n", strerror(errno)); return (-1); } (void) unlink(tmpname); if ((tmpfp[tmpfp_idx] = fdopen(fd, "w+F")) == NULL) { syslog(LOG_ERR, MODNAME ": fdopen failed: %s", strerror(errno)); (void) close(fd); return (-1); } /* write words to file */ while (i < off_idx) { if (fprintf(tmpfp[tmpfp_idx], "%s\n", &buf[offsets[i++]]) < 0) { syslog(LOG_ERR, MODNAME ": write to file failed: %s", strerror(errno)); (void) close(fd); return (-1); } } /* we have one extra tmpfp */ tmpfp_idx++; return (0); } /* * int insert_word(int off) * * insert an offset into the offsets-array. If the offsets-array is out of * space, we allocate additional space (in CHUNKs) * * returns 0 on success, -1 on failure (out of memory) */ int insert_word(int off) { #define CHUNK 10000 if (off_idx == off_size) { uint_t *tmp; off_size += CHUNK; tmp = realloc(offsets, sizeof (uint_t) * off_size); if (tmp == NULL) { syslog(LOG_ERR, MODNAME ": out of memory"); free(offsets); off_idx = off_size = 0; offsets = NULL; return (-1); } offsets = tmp; } offsets[off_idx++] = off; return (0); } /* * translate(buf, size) * * perform "tr '[A-Z]' '[a-z]' | tr -cd '\012[a-z][0-9]'" on the * words in "buf" and insert each of them into the offsets-array. * We refrain from using 'isupper' and 'islower' to keep this strictly * ASCII-only, as is the original Cracklib code. * * returns 0 on success, -1 on failure (failure of insert_word) */ int translate(char *buf, size_t size) { char *p, *q, *e; char c; int wordstart; e = &buf[size]; wordstart = 0; for (p = buf, q = buf; q < e; q++) { c = *q; if (c >= 'A' && c <= 'Z') { *(p++) = tolower(c); } else if (c == '\n') { *(p++) = '\0'; /* * make sure we only insert words consisting of * MAXWORDLEN-1 bytes or less */ if (p-&buf[wordstart] > MAXWORDLEN) buf[wordstart+MAXWORDLEN-1] = '\0'; if (insert_word(wordstart) != 0) return (-1); wordstart = p-buf; } else if ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9')) { *(p++) = c; } } return (0); } /* * int compare(a, b) * * helper-routine used for quicksort. we compate two words in the * buffer, one start starts at index "a", and the other one that starts * at index "b" */ int compare(const void *a, const void *b) { int idx_a = *(uint_t *)a, idx_b = *(uint_t *)b; return (strcmp(&buf[idx_a], &buf[idx_b])); } /* * * int sort_file(fname) * * We sort the file in memory: we read the dictionary file, translate all * newlines to '\0's, all uppercase ASCII characters to lowercase characters * and removing all characters but '[a-z][0-9]'. * We maintain an array of offsets into the buffer where each word starts * and sort this array using qsort(). * * This implements the original cracklib code that did an execl of * sh -c "/bin/cat | * /bin/tr '[A-Z]' '[a-z]' | /bin/tr -cd '\012[a-z][0-9]' | * sort -o tmfpfile * * returns 0 on success, -1 on failure. */ int sort_file(char *fname) { int fd; struct stat statbuf; ssize_t n; int ret = -1; if ((fd = open(fname, O_RDONLY)) == -1) { syslog(LOG_ERR, MODNAME ": failed to open %s: %s", fname, strerror(errno)); return (-1); } if (fstat(fd, &statbuf) == -1) { syslog(LOG_ERR, MODNAME ": fstat() failed (%s)", strerror(errno)); (void) close(fd); return (-1); } if ((buf = malloc(statbuf.st_size + 1)) == NULL) { syslog(LOG_ERR, MODNAME ": out of memory"); goto error; } n = read(fd, buf, statbuf.st_size); if (n == -1) { if (errno == EINVAL) syslog(LOG_ERR, MODNAME ": %s is too big. " "Split the file into smaller files.", fname); else syslog(LOG_ERR, MODNAME ": read failed: %s", strerror(errno)); goto error; } if (translate(buf, n) == 0) { qsort((void *)offsets, off_idx, sizeof (int), compare); if (writeout() == 0) ret = 0; } error: (void) close(fd); if (buf != NULL) free(buf); if (offsets != NULL) free(offsets); offsets = NULL; off_size = 0; off_idx = 0; return (ret); } /* * We merge the temporary files created by previous calls to sort_file() * and insert the thus sorted words into the cracklib database * * returns 0 on success, -1 on failure. */ int merge_files(PWDICT *pwp) { int ti; char *words[MAXTMP]; char lastword[MAXWORDLEN]; int choice; lastword[0] = '\0'; for (ti = 0; ti < tmpfp_idx; ti++) if ((words[ti] = malloc(MAXWORDLEN)) == NULL) { while (--ti >= 0) free(words[ti]); return (-1); } /* * we read the first word of each of the temp-files into words[]. */ for (ti = 0; ti < tmpfp_idx; ti++) { (void) fseek(tmpfp[ti], 0, SEEK_SET); (void) fgets(words[ti], MAXWORDLEN, tmpfp[ti]); words[ti][MAXWORDLEN-1] = '\0'; } /* * next, we emit the word that comes first (lexicographically), * and replace that word with a new word from the file it * came from. If the file is exhausted, we close the fp and * swap the fp with the last fp in tmpfp[]. * we then decrease tmpfp_idx and continue with what's left until * we run out of open FILE pointers. */ while (tmpfp_idx != 0) { choice = 0; for (ti = 1; ti < tmpfp_idx; ti++) if (strcmp(words[choice], words[ti]) > 0) choice = ti; /* Insert word in Cracklib database */ (void) Chomp(words[choice]); if (words[choice][0] != '\0' && strcmp(lastword, words[choice]) != 0) { (void) PutPW(pwp, words[choice]); (void) strncpy(lastword, words[choice], MAXWORDLEN); } if (fgets(words[choice], MAXWORDLEN, tmpfp[choice]) == NULL) { (void) fclose(tmpfp[choice]); tmpfp[choice] = tmpfp[tmpfp_idx - 1]; tmpfp_idx--; } else words[choice][MAXWORDLEN-1] = '\0'; } return (0); } /* * int packer(list) * * sort all dictionaries in "list", and feed the words into the Crack * Password Database. * * returns 0 on sucess, -1 on failure. */ int packer(char *list, char *path) { PWDICT *pwp; char *listcopy, *fname; int ret = 0; if ((listcopy = strdup(list)) == NULL) { syslog(LOG_ERR, MODNAME ": out of memory"); return (-1); } if (!(pwp = PWOpen(path, "wF"))) return (-1); fname = strtok(listcopy, " \t,"); while (ret == 0 && fname != NULL) { if ((ret = sort_file(fname)) == 0) fname = strtok(NULL, " \t,"); } free(listcopy); if (ret == 0) ret = merge_files(pwp); (void) PWClose(pwp); return (ret); } /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * Copyright 2024 OmniOS Community Edition (OmniOSce) Association. */ #ifndef _PACKER_H #define _PACKER_H #ifdef __cplusplus extern "C" { #endif /* * This program is copyright Alec Muffett 1993. The author disclaims all * responsibility or liability with respect to it's usage or its effect * upon hardware or computer systems, and maintains copyright as set out * in the "LICENCE" document which accompanies distributions of Crack v4.0 * and upwards. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #define PWADMIN "/etc/default/passwd" #define TRUNCSTRINGSIZE (PATH_MAX/4) #define STRINGSIZE PATH_MAX #ifndef NUMWORDS #define NUMWORDS 16 #endif #define MAXWORDLEN 32 #define MAXBLOCKLEN (MAXWORDLEN * NUMWORDS) struct pi_header { uint32_t pih_magic; uint32_t pih_numwords; uint16_t pih_blocklen; uint16_t pih_pad; }; typedef struct { FILE *ifp; FILE *dfp; FILE *wfp; uint32_t flags; #define PFOR_WRITE 0x0001 #define PFOR_FLUSH 0x0002 #define PFOR_USEHWMS 0x0004 uint32_t hwms[256]; struct pi_header header; uint32_t count; char data[NUMWORDS][MAXWORDLEN]; } PWDICT; #define PW_WORDS(x) ((x)->header.pih_numwords) #define PIH_MAGIC 0x70775632 void PWRemove(char *); PWDICT *PWOpen(char *, char *); char *Mangle(char *, char *); #define CRACK_TOLOWER(a) (isupper(a)?tolower(a):(a)) #define CRACK_TOUPPER(a) (islower(a)?toupper(a):(a)) #define STRCMP(a, b) strcmp((a), (b)) char *Trim(register char *); uint32_t FindPW(PWDICT *, char *); int PWClose(PWDICT *); int PutPW(PWDICT *, char *); char Chop(register char *); char Chomp(register char *); char *GetPW(PWDICT *, uint32_t); #define DATABASE_OPEN_FAIL -1 #define DICTIONARY_WORD 2 #define REVERSE_DICTIONARY_WORD 3 /* Dictionary database dir and prefix */ #define CRACK_DIR "/var/passwd" #define CRACK_DICTPATH "/var/passwd/pw_dict" #define DICT_DATABASE_HWM "pw_dict.hwm" #define DICT_DATABASE_PWD "pw_dict.pwd" #define DICT_DATABASE_PWI "pw_dict.pwi" int packer(char *, char *); char *Reverse(char *); char *Lowercase(char *); int DictCheck(const char *, char *); int make_dict_database(char *, char *); int build_dict_database(char *, char *); int lock_db(char *); void unlock_db(); /* Return values for dictionary database checks */ #define NO_DICTDATABASE 1 #define UPDATE_DICTDATABASE 2 #define DICTFILE_ERR -1 #define DICTPATH_ERR -2 #define DICTDATABASE_BUILD_ERR -3 #ifdef __cplusplus } #endif #endif /* _PACKER_H */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Copyright (c) 2018, Joyent, Inc. */ /* * This program is copyright Alec Muffett 1993. The author disclaims all * responsibility or liability with respect to it's usage or its effect * upon hardware or computer systems, and maintains copyright as set out * in the "LICENCE" document which accompanies distributions of Crack v4.0 * and upwards. */ #include "packer.h" void PWRemove(char *path) { char fname[PATH_MAX]; (void) snprintf(fname, sizeof (fname), "%s/%s", path, DICT_DATABASE_PWI); (void) unlink(fname); (void) snprintf(fname, sizeof (fname), "%s/%s", path, DICT_DATABASE_PWD); (void) unlink(fname); (void) snprintf(fname, sizeof (fname), "%s/%s", path, DICT_DATABASE_HWM); (void) unlink(fname); } PWDICT * PWOpen(char *path, char *mode) { PWDICT *pdesc; char iname[PATH_MAX]; char dname[PATH_MAX]; char wname[PATH_MAX]; int fd_d; int fd_i; int fd_w; FILE *dfp; FILE *ifp; FILE *wfp; if ((pdesc = calloc(1, sizeof (PWDICT))) == NULL) return ((PWDICT *) 0); if (pdesc->header.pih_magic == PIH_MAGIC) { return ((PWDICT *) 0); } (void) memset(pdesc, '\0', sizeof (pdesc)); (void) snprintf(iname, sizeof (iname), "%s/%s", path, DICT_DATABASE_PWI); (void) snprintf(dname, sizeof (dname), "%s/%s", path, DICT_DATABASE_PWD); (void) snprintf(wname, sizeof (wname), "%s/%s", path, DICT_DATABASE_HWM); if ((fd_d = open(dname, O_RDWR|O_CREAT, 0600)) == -1) syslog(LOG_ERR, "PWopen: can't open %s: %s", dname, strerror(errno)); if ((fd_i = open(iname, O_RDWR|O_CREAT, 0600)) == -1) syslog(LOG_ERR, "PWopen: can't open %s: %s", iname, strerror(errno)); if ((fd_w = open(wname, O_RDWR|O_CREAT, 0600)) == -1) syslog(LOG_ERR, "PWopen: can't open %s: %s", wname, strerror(errno)); if (!(pdesc->dfp = fdopen(fd_d, mode))) { return ((PWDICT *) 0); } if (!(pdesc->ifp = fdopen(fd_i, mode))) { (void) fclose(pdesc->dfp); return ((PWDICT *) 0); } if (pdesc->wfp = fdopen(fd_w, mode)) { pdesc->flags |= PFOR_USEHWMS; } ifp = pdesc->ifp; dfp = pdesc->dfp; wfp = pdesc->wfp; if (mode[0] == 'w') { pdesc->flags |= PFOR_WRITE; pdesc->header.pih_magic = PIH_MAGIC; pdesc->header.pih_blocklen = NUMWORDS; pdesc->header.pih_numwords = 0; (void) fwrite((char *)&(pdesc->header), sizeof (pdesc->header), 1, ifp); } else { pdesc->flags &= ~PFOR_WRITE; if (!fread((char *)&(pdesc->header), sizeof (pdesc->header), 1, ifp)) { pdesc->header.pih_magic = 0; (void) fclose(ifp); (void) fclose(dfp); return ((PWDICT *) 0); } if (pdesc->header.pih_magic != PIH_MAGIC) { pdesc->header.pih_magic = 0; (void) fclose(ifp); (void) fclose(dfp); return ((PWDICT *) 0); } if (pdesc->header.pih_blocklen != NUMWORDS) { pdesc->header.pih_magic = 0; (void) fclose(ifp); (void) fclose(dfp); return ((PWDICT *) 0); } if (pdesc->flags & PFOR_USEHWMS) { if (fread(pdesc->hwms, 1, sizeof (pdesc->hwms), wfp) != sizeof (pdesc->hwms)) { pdesc->flags &= ~PFOR_USEHWMS; } } } return (pdesc); } int PWClose(PWDICT *pwp) { if (pwp->header.pih_magic != PIH_MAGIC) { return (-1); } if (pwp->flags & PFOR_WRITE) { pwp->flags |= PFOR_FLUSH; (void) PutPW(pwp, (char *)0); /* flush last index if necess */ if (fseek(pwp->ifp, 0L, 0)) { return (-1); } if (!fwrite((char *)&pwp->header, sizeof (pwp->header), 1, pwp->ifp)) { return (-1); } if (pwp->flags & PFOR_USEHWMS) { int i; for (i = 1; i <= 0xff; i++) { if (!pwp->hwms[i]) { pwp->hwms[i] = pwp->hwms[i-1]; } } (void) fwrite(pwp->hwms, 1, sizeof (pwp->hwms), pwp->wfp); } } (void) fclose(pwp->ifp); (void) fclose(pwp->dfp); (void) fclose(pwp->wfp); pwp->header.pih_magic = 0; free(pwp); return (0); } int PutPW(PWDICT *pwp, char *string) { if (!(pwp->flags & PFOR_WRITE)) { return (-1); } if (string) { (void) strncpy(pwp->data[pwp->count], string, MAXWORDLEN); pwp->data[pwp->count][MAXWORDLEN - 1] = '\0'; pwp->hwms[string[0] & 0xff] = pwp->header.pih_numwords; ++(pwp->count); ++(pwp->header.pih_numwords); } else if (!(pwp->flags & PFOR_FLUSH)) { return (-1); } if ((pwp->flags & PFOR_FLUSH) || !(pwp->count % NUMWORDS)) { int i; uint32_t datum; register char *ostr; datum = (uint32_t)ftell(pwp->dfp); (void) fwrite((char *)&datum, sizeof (datum), 1, pwp->ifp); (void) fputs(pwp->data[0], pwp->dfp); (void) putc(0, pwp->dfp); ostr = pwp->data[0]; for (i = 1; i < NUMWORDS; i++) { register int j; register char *nstr; nstr = pwp->data[i]; if (nstr[0]) { for (j = 0; ostr[j] && nstr[j] && (ostr[j] == nstr[j]); j++) ; (void) putc(j & 0xff, pwp->dfp); (void) fputs(nstr + j, pwp->dfp); } (void) putc(0, pwp->dfp); ostr = nstr; } (void) memset(pwp->data, '\0', sizeof (pwp->data)); pwp->count = 0; } return (0); } char * GetPW(PWDICT *pwp, uint32_t number) { uint32_t datum; register int i; register char *ostr; register char *nstr; register char *bptr; char buffer[NUMWORDS * MAXWORDLEN]; static char data[NUMWORDS][MAXWORDLEN]; static uint32_t prevblock = 0xffffffff; uint32_t thisblock; thisblock = number / NUMWORDS; if (prevblock == thisblock) { return (data[number % NUMWORDS]); } if (fseek(pwp->ifp, sizeof (struct pi_header) + (thisblock * sizeof (uint32_t)), 0)) { return (NULL); } if (!fread((char *)&datum, sizeof (datum), 1, pwp->ifp)) { return (NULL); } if (fseek(pwp->dfp, datum, 0)) { return (NULL); } if (!fread(buffer, 1, sizeof (buffer), pwp->dfp)) { return (NULL); } prevblock = thisblock; bptr = buffer; for (ostr = data[0]; *(ostr++) = *(bptr++); /* nothing */) ; ostr = data[0]; for (i = 1; i < NUMWORDS; i++) { nstr = data[i]; (void) strcpy(nstr, ostr); ostr = nstr + *(bptr++); while (*(ostr++) = *(bptr++)) ; ostr = nstr; } return (data[number % NUMWORDS]); } uint32_t FindPW(PWDICT *pwp, char *string) { int lwm; int hwm; int idx; if (string == NULL) return (PW_WORDS(pwp)); if (pwp->flags & PFOR_USEHWMS) { idx = string[0] & 0xff; lwm = idx ? pwp->hwms[idx - 1] : 0; hwm = pwp->hwms[idx]; } else { lwm = 0; hwm = PW_WORDS(pwp) - 1; } for (;;) { int cmp; int pivot; char *this; pivot = lwm + ((hwm+1)-lwm)/2; if (feof(pwp->ifp) && feof(pwp->dfp) && feof(pwp->wfp)) break; if ((this = GetPW(pwp, pivot)) == NULL) break; cmp = strcmp(string, this); /* INLINE ? */ if (cmp == 0) return (pivot); else if (cmp < 0) hwm = pivot-1; else lwm = pivot+1; if (lwm > hwm) /* searched all; not found */ break; } /* not found */ return (PW_WORDS(pwp)); } /* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * This program is copyright Alec Muffett 1993. The author disclaims all * responsibility or liability with respect to it's usage or its effect * upon hardware or computer systems, and maintains copyright as set out * in the "LICENCE" document which accompanies distributions of Crack v4.0 * and upwards. */ #include "packer.h" #define RULE_NOOP ':' #define RULE_PREPEND '^' #define RULE_APPEND '$' #define RULE_REVERSE 'r' #define RULE_UPPERCASE 'u' #define RULE_LOWERCASE 'l' #define RULE_PLURALISE 'p' #define RULE_CAPITALISE 'c' #define RULE_DUPLICATE 'd' #define RULE_REFLECT 'f' #define RULE_SUBSTITUTE 's' #define RULE_MATCH '/' #define RULE_NOT '!' #define RULE_LT '<' #define RULE_GT '>' #define RULE_EXTRACT 'x' #define RULE_OVERSTRIKE 'o' #define RULE_INSERT 'i' #define RULE_EQUALS '=' #define RULE_PURGE '@' #define RULE_CLASS '?' /* class rule? socialist ethic in cracker? */ #define RULE_DFIRST '[' #define RULE_DLAST ']' #define RULE_MFIRST '(' #define RULE_MLAST ')' int Suffix(char *myword, char *suffix) { register int i; register int j; i = strlen(myword); j = strlen(suffix); if (i > j) { return (STRCMP((myword + i - j), suffix)); } else { return (-1); } } char * Reverse(register char *str) /* return a pointer to a reversal */ { register int i; register int j; static char area[PATH_MAX]; j = i = strlen(str); while (*str) { area[--i] = *str++; } area[j] = '\0'; return (area); } char * Uppercase(register char *str) /* return a pointer to an uppercase */ { register char *ptr; static char area[PATH_MAX]; ptr = area; while (*str) { *(ptr++) = CRACK_TOUPPER(*str); str++; } *ptr = '\0'; return (area); } char * Lowercase(register char *str) /* return a pointer to an lowercase */ { register char *ptr; static char area[PATH_MAX]; ptr = area; while (*str) { *(ptr++) = CRACK_TOLOWER(*str); str++; } *ptr = '\0'; return (area); } char * Capitalise(register char *str) /* return a pointer to an capitalised */ { register char *ptr; static char area[PATH_MAX]; ptr = area; while (*str) { *(ptr++) = CRACK_TOLOWER(*str); str++; } *ptr = '\0'; area[0] = CRACK_TOUPPER(area[0]); return (area); } char * Pluralise(register char *string) /* returns a pointer to a plural */ { register int length; static char area[PATH_MAX]; length = strlen(string); (void) strlcpy(area, string, PATH_MAX); if (!Suffix(string, "ch") || !Suffix(string, "ex") || !Suffix(string, "ix") || !Suffix(string, "sh") || !Suffix(string, "ss")) { /* bench -> benches */ (void) strcat(area, "es"); } else if (length > 2 && string[length - 1] == 'y') { if (strchr("aeiou", string[length - 2])) { /* alloy -> alloys */ (void) strcat(area, "s"); } else { /* gully -> gullies */ (void) strcpy(area + length - 1, "ies"); } } else if (string[length - 1] == 's') { /* bias -> biases */ (void) strcat(area, "es"); } else { /* catchall */ (void) strcat(area, "s"); } return (area); } char * Substitute(register char *string, register char old, register char new) /* returns pointer to a swapped about copy */ { register char *ptr; static char area[PATH_MAX]; ptr = area; while (*string) { *(ptr++) = (*string == old ? new : *string); string++; } *ptr = '\0'; return (area); } /* returns pointer to a purged copy */ char * Purge(register char *string, register char target) { register char *ptr; static char area[PATH_MAX]; ptr = area; while (*string) { if (*string != target) { *(ptr++) = *string; } string++; } *ptr = '\0'; return (area); } /* -------- CHARACTER CLASSES START HERE -------- */ /* * this function takes two inputs, a class identifier and a character, and * returns non-null if the given character is a member of the class, based * upon restrictions set out below */ int MatchClass(register char class, register char input) { register char c; register int retval; retval = 0; switch (class) { /* ESCAPE */ case '?': /* ?? -> ? */ if (input == '?') { retval = 1; } break; /* ILLOGICAL GROUPINGS (ie: not in ctype.h) */ case 'V': case 'v': /* vowels */ c = CRACK_TOLOWER(input); if (strchr("aeiou", c)) { retval = 1; } break; case 'C': case 'c': /* consonants */ c = CRACK_TOLOWER(input); if (strchr("bcdfghjklmnpqrstvwxyz", c)) { retval = 1; } break; case 'W': case 'w': /* whitespace */ if (strchr("\t ", input)) { retval = 1; } break; case 'P': case 'p': /* punctuation */ if (strchr(".`,:;'!?\"", input)) { retval = 1; } break; case 'S': case 's': /* symbols */ if (strchr("$%%^&*()-_+=|\\[]{}#@/~", input)) { retval = 1; } break; /* LOGICAL GROUPINGS */ case 'L': case 'l': /* lowercase */ if (islower(input)) { retval = 1; } break; case 'U': case 'u': /* uppercase */ if (isupper(input)) { retval = 1; } break; case 'A': case 'a': /* alphabetic */ if (isalpha(input)) { retval = 1; } break; case 'X': case 'x': /* alphanumeric */ if (isalnum(input)) { retval = 1; } break; case 'D': case 'd': /* digits */ if (isdigit(input)) { retval = 1; } break; } if (isupper(class)) { return (!retval); } return (retval); } char * PolyStrchr(register char *string, register char class) { while (*string) { if (MatchClass(class, *string)) { return (string); } string++; } return ((char *)0); } /* returns pointer to a swapped about copy */ char * PolySubst(register char *string, register char class, register char new) { register char *ptr; static char area[PATH_MAX]; ptr = area; while (*string) { *(ptr++) = (MatchClass(class, *string) ? new : *string); string++; } *ptr = '\0'; return (area); } /* returns pointer to a purged copy */ char * PolyPurge(register char *string, register char class) { register char *ptr; static char area[PATH_MAX]; ptr = area; while (*string) { if (!MatchClass(class, *string)) { *(ptr++) = *string; } string++; } *ptr = '\0'; return (area); } /* -------- BACK TO NORMALITY -------- */ int Char2Int(char character) { if (isdigit(character)) { return (character - '0'); } else if (islower(character)) { return (character - 'a' + 10); } else if (isupper(character)) { return (character - 'A' + 10); } return (-1); } /* returns a pointer to a controlled Mangle */ char * Mangle(char *input, char *control) { int limit; register char *ptr; static char area[PATH_MAX]; char area2[PATH_MAX]; area[0] = '\0'; (void) strlcpy(area, input, PATH_MAX); for (ptr = control; *ptr; ptr++) { switch (*ptr) { case RULE_NOOP: break; case RULE_REVERSE: (void) strlcpy(area, Reverse(area), PATH_MAX); break; case RULE_UPPERCASE: (void) strlcpy(area, Uppercase(area), PATH_MAX); break; case RULE_LOWERCASE: (void) strlcpy(area, Lowercase(area), PATH_MAX); break; case RULE_CAPITALISE: (void) strlcpy(area, Capitalise(area), PATH_MAX); break; case RULE_PLURALISE: (void) strlcpy(area, Pluralise(area), PATH_MAX); break; case RULE_REFLECT: (void) strlcat(area, Reverse(area), PATH_MAX); break; case RULE_DUPLICATE: (void) strlcpy(area2, area, PATH_MAX); (void) strlcat(area, area2, PATH_MAX); break; case RULE_GT: if (!ptr[1]) { return ((char *)0); } else { limit = Char2Int(*(++ptr)); if (limit < 0) { return ((char *)0); } if (strlen(area) <= limit) { return ((char *)0); } } break; case RULE_LT: if (!ptr[1]) { return ((char *)0); } else { limit = Char2Int(*(++ptr)); if (limit < 0) { return ((char *)0); } if (strlen(area) >= limit) { return ((char *)0); } } break; case RULE_PREPEND: if (!ptr[1]) { return ((char *)0); } else { area2[0] = *(++ptr); (void) strlcpy(area2 + 1, area, PATH_MAX); (void) strlcpy(area, area2, PATH_MAX); } break; case RULE_APPEND: if (!ptr[1]) { return ((char *)0); } else { register char *string; string = area; while (*(string++)); string[-1] = *(++ptr); *string = '\0'; } break; case RULE_EXTRACT: if (!ptr[1] || !ptr[2]) { return ((char *)0); } else { register int i; int start; int length; start = Char2Int(*(++ptr)); length = Char2Int(*(++ptr)); if (start < 0 || length < 0) { return ((char *)0); } (void) strlcpy(area2, area, PATH_MAX); for (i = 0; length-- && area2[start + i]; i++) { area[i] = area2[start + i]; } /* cant use strncpy()-no trailing NUL */ area[i] = '\0'; } break; case RULE_OVERSTRIKE: if (!ptr[1] || !ptr[2]) { return ((char *)0); } else { register int i; i = Char2Int(*(++ptr)); if (i < 0) { return ((char *)0); } else { ++ptr; if (area[i]) { area[i] = *ptr; } } } break; case RULE_INSERT: if (!ptr[1] || !ptr[2]) { return ((char *)0); } else { register int i; register char *p1; register char *p2; i = Char2Int(*(++ptr)); if (i < 0) { return ((char *)0); } p1 = area; p2 = area2; while (i && *p1) { i--; *(p2++) = *(p1++); } *(p2++) = *(++ptr); (void) strlcpy(p2, p1, PATH_MAX); (void) strlcpy(area, area2, PATH_MAX); } break; /* THE FOLLOWING RULES REQUIRE CLASS MATCHING */ case RULE_PURGE: /* @x or @?c */ if (!ptr[1] || (ptr[1] == RULE_CLASS && !ptr[2])) { return ((char *)0); } else if (ptr[1] != RULE_CLASS) { (void) strlcpy(area, Purge(area, *(++ptr)), PATH_MAX); } else { (void) strlcpy(area, PolyPurge(area, ptr[2]), PATH_MAX); ptr += 2; } break; case RULE_SUBSTITUTE: /* sxy || s?cy */ if (!ptr[1] || !ptr[2] || (ptr[1] == RULE_CLASS && !ptr[3])) { return ((char *)0); } else if (ptr[1] != RULE_CLASS) { ptr += 2; } else { (void) strlcpy(area, PolySubst(area, ptr[2], ptr[3]), PATH_MAX); ptr += 3; } break; case RULE_MATCH: /* /x || /?c */ if (!ptr[1] || (ptr[1] == RULE_CLASS && !ptr[2])) { return ((char *)0); } else if (ptr[1] != RULE_CLASS) { if (!strchr(area, *(++ptr))) { return ((char *)0); } } else { if (!PolyStrchr(area, ptr[2])) { return ((char *)0); } ptr += 2; } break; case RULE_NOT: /* !x || !?c */ if (!ptr[1] || (ptr[1] == RULE_CLASS && !ptr[2])) { return ((char *)0); } else if (ptr[1] != RULE_CLASS) { if (strchr(area, *(++ptr))) { return ((char *)0); } } else { if (PolyStrchr(area, ptr[2])) { return ((char *)0); } ptr += 2; } break; /* * alternative use for a boomerang, number 1: a standard throwing * boomerang is an ideal thing to use to tuck the sheets under * the mattress when making your bed. The streamlined shape of * the boomerang allows it to slip easily 'twixt mattress and * bedframe, and it's curve makes it very easy to hook sheets * into the gap. */ case RULE_EQUALS: /* =nx || =n?c */ if (!ptr[1] || !ptr[2] || (ptr[2] == RULE_CLASS && !ptr[3])) { return ((char *)0); } else { register int i; if ((i = Char2Int(ptr[1])) < 0) { return ((char *)0); } if (ptr[2] != RULE_CLASS) { ptr += 2; if (area[i] != *ptr) { return ((char *)0); } } else { ptr += 3; if (!MatchClass(*ptr, area[i])) { return ((char *)0); } } } break; case RULE_DFIRST: if (area[0]) { register int i; for (i = 1; area[i]; i++) { area[i - 1] = area[i]; } area[i - 1] = '\0'; } break; case RULE_DLAST: if (area[0]) { register int i; for (i = 1; area[i]; i++); area[i - 1] = '\0'; } break; case RULE_MFIRST: if (!ptr[1] || (ptr[1] == RULE_CLASS && !ptr[2])) { return ((char *)0); } else { if (ptr[1] != RULE_CLASS) { ptr++; if (area[0] != *ptr) { return ((char *)0); } } else { ptr += 2; if (!MatchClass(*ptr, area[0])) { return ((char *)0); } } } break; case RULE_MLAST: if (!ptr[1] || (ptr[1] == RULE_CLASS && !ptr[2])) { return ((char *)0); } else { register int i; for (i = 0; area[i]; i++); if (i > 0) { i--; } else { return ((char *)0); } if (ptr[1] != RULE_CLASS) { ptr++; if (area[i] != *ptr) { return ((char *)0); } } else { ptr += 2; if (!MatchClass(*ptr, area[i])) { return ((char *)0); } } } break; } } if (!area[0]) { /* have we deweted de poor widdle fing away? */ return ((char *)0); } return (area); } /* * int * PMatch(register char *control, register char *string) * { * while (*string && *control) { * if (!MatchClass(*control, *string)) { * return (0); * } * * string++; * control++; * } * * if (*string || *control) { * return (0); * } * * return (1); * } */ /* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * This program is copyright Alec Muffett 1993. The author disclaims all * responsibility or liability with respect to it's usage or its effect * upon hardware or computer systems, and maintains copyright as set out * in the "LICENCE" document which accompanies distributions of Crack v4.0 * and upwards. */ #include "packer.h" char Chop(register char *string) { register char c; register char *ptr; c = '\0'; for (ptr = string; *ptr; ptr++); if (ptr != string) { c = *(--ptr); *ptr = '\0'; } return (c); } char Chomp(register char *string) { register char c; register char *ptr; c = '\0'; for (ptr = string; *ptr; ptr++) ; if (ptr != string && isspace(*(--ptr))) { c = *ptr; *ptr = '\0'; } return (c); } char * Trim(register char *string) { register char *ptr; for (ptr = string; *ptr; ptr++); while ((--ptr >= string) && isspace(*ptr)); *(++ptr) = '\0'; return (ptr); } # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # include ../../Makefile.lib TEXT_DOMAIN= SUNW_OST_SYSOSPAM POFILE= authtok_get.po MSGFILES= authtok_get.c # Hammerhead: amd64-only SUBDIRS= $(MACH64) all : TARGET= all clean : TARGET= clean clobber : TARGET= clobber install : TARGET= install .KEEP_STATE: all clean clobber install: $(SUBDIRS) _msg: $(MSGDOMAINPOFILE) $(SUBDIRS): FRC @cd $@; pwd; $(MAKE) $(TARGET) FRC: include $(SRC)/Makefile.msg.targ include ../../Makefile.targ # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License, Version 1.0 only # (the "License"). You may not use this file except in compliance # with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2004 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # LIBRARY= pam_authtok_get.a VERS= .1 OBJECTS= authtok_get.o include ../../Makefile.pam_modules LDLIBS += -lpam -lc all: $(LIBS) include ../../../Makefile.targ # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License, Version 1.0 only # (the "License"). You may not use this file except in compliance # with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2004 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" # include ../Makefile.com include ../../../Makefile.lib.64 # Hammerhead: 64-bit only - flatten passwdutil path DYNFLAGS += $(ROOT)/usr/lib/passwdutil.so.1 install: all $(ROOTLIBS64) $(ROOTLINKS64) /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * Copyright 2023 OmniOS Community Edition (OmniOSce) Association. */ #include #include #include #include #include #include #include #include #include #include /*PRINTFLIKE2*/ void error(pam_handle_t *pamh, char *fmt, ...) { va_list ap; char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE]; va_start(ap, fmt); (void) vsnprintf(messages[0], sizeof (messages[0]), fmt, ap); (void) __pam_display_msg(pamh, PAM_ERROR_MSG, 1, messages, NULL); va_end(ap); } int read_authtok(pam_handle_t *pamh, int debug) { int res; const char *authtok; char *pwd; /* * We are about to read the new AUTHTOK. Store the AUTHTOK that * the user used to authenticate in OLDAUTHTOK, so it is available * to future modules. If OLDAUTHTOK is already set, we leave it alone */ res = pam_get_item(pamh, PAM_OLDAUTHTOK, (const void **)&authtok); if (res != PAM_SUCCESS) return (res); if (authtok == NULL) { res = pam_get_item(pamh, PAM_AUTHTOK, (const void **)&authtok); if (res != PAM_SUCCESS) return (res); if (authtok != NULL) { res = pam_set_item(pamh, PAM_OLDAUTHTOK, (void *)authtok); if (res == PAM_SUCCESS) res = pam_set_item(pamh, PAM_AUTHTOK, NULL); if (debug) __pam_log(LOG_AUTH | LOG_DEBUG, "read_authtok: Copied AUTHTOK to " "OLDAUTHTOK"); if (res != PAM_SUCCESS) goto out; } } else { /* * OLDAUTHTOK was filled in. If AUTHTOK is also filled * in, we either succeed a module that has done our * work, or we're here because one of the modules * that are stacked beyond us has returned PAM_TRY_AGAIN. * In either case, we should *not* prompt for another * password. */ res = pam_get_item(pamh, PAM_AUTHTOK, (const void **)&pwd); if (res != PAM_SUCCESS) goto out; if (pwd != NULL) { goto out; } } /* * Make sure PAM_AUTHTOK is empty, or the framework will not * put the value read by __pam_get_authtok into it */ (void) pam_set_item(pamh, PAM_AUTHTOK, NULL); res = __pam_get_authtok(pamh, PAM_PROMPT, PAM_AUTHTOK, dgettext(TEXT_DOMAIN, "New Password: "), &pwd); if (res != PAM_SUCCESS) goto out; if (pwd == NULL) { const char *service; if ((pam_get_item(pamh, PAM_SERVICE, (const void **)&service) == PAM_SUCCESS) && service != NULL) { error(pamh, dgettext(TEXT_DOMAIN, "%s: Sorry."), service); } res = PAM_PERM_DENIED; } else { (void) memset(pwd, 0, strlen(pwd)); free(pwd); } out: if (res != PAM_SUCCESS) { (void) pam_set_item(pamh, PAM_AUTHTOK, NULL); (void) pam_set_item(pamh, PAM_OLDAUTHTOK, NULL); } else { /* * Since we don't actually check the password, we should * not return PAM_SUCCESS if everything went OK. * We should return PAM_IGNORE instead. */ res = PAM_IGNORE; } return (res); } int verify_authtok(pam_handle_t *pamh, int debug) { int res; const char *authtok; char *pwd; if (debug) __pam_log(LOG_AUTH | LOG_DEBUG, "pam_authtok_get: verifying authtok"); /* * All we need to do, is make sure that the user re-enters * the password correctly. */ res = pam_get_item(pamh, PAM_AUTHTOK, (const void **)&authtok); if (res != PAM_SUCCESS || authtok == NULL) return (PAM_AUTHTOK_ERR); res = __pam_get_authtok(pamh, PAM_PROMPT, 0, dgettext(TEXT_DOMAIN, "Re-enter new Password: "), &pwd); if (res != PAM_SUCCESS) return (res); if (strcmp(authtok, pwd) != 0) { const char *service; if ((pam_get_item(pamh, PAM_SERVICE, (const void **)&service) == PAM_SUCCESS) && service != NULL) { error(pamh, dgettext(TEXT_DOMAIN, "%s: They don't match."), service); } (void) pam_set_item(pamh, PAM_AUTHTOK, NULL); (void) memset(pwd, 0, strlen(pwd)); free(pwd); return (PAM_AUTHTOK_ERR); } if (debug) __pam_log(LOG_AUTH | LOG_DEBUG, "pam_authtok_get: new password verified"); (void) memset(pwd, 0, strlen(pwd)); free(pwd); return (PAM_IGNORE); } int pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, const char **argv) { int i; int debug = 0; int res; for (i = 0; i < argc; i++) if (strcmp(argv[i], "debug") == 0) debug = 1; if ((flags & PAM_PRELIM_CHECK) == PAM_PRELIM_CHECK) res = read_authtok(pamh, debug); else res = verify_authtok(pamh, debug); return (res); } /* * int pam_sm_authenticate(pamh, flags, argc, argv) * * Read authentication token from user. */ int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) { const char *user; char *password; int i; int debug = 0; int res; int fail = 0; attrlist al[1]; const pam_repository_t *auth_rep = NULL; pwu_repository_t *pwu_rep = NULL; for (i = 0; i < argc; i++) if (strcmp(argv[i], "debug") == 0) debug = 1; if (debug) __pam_log(LOG_AUTH | LOG_DEBUG, "pam_authtok_get:pam_sm_authenticate: flags = %d", flags); if ((res = pam_get_user(pamh, &user, NULL)) != PAM_SUCCESS) { if (debug) __pam_log(LOG_AUTH | LOG_DEBUG, "pam_authtok_get: get user failed: %s", pam_strerror(pamh, res)); return (res); } if (user == NULL || *user == '\0') { __pam_log(LOG_AUTH | LOG_ERR, "pam_authtok_get: pam_sm_authenticate: PAM_USER NULL or " "empty"); return (PAM_SYSTEM_ERR); } res = pam_get_item(pamh, PAM_AUTHTOK, (const void **)&password); if (res != PAM_SUCCESS) return (res); if (password != NULL) return (PAM_IGNORE); /* * No password has been entered yet. Check to see if we need * to obtain a password */ res = pam_get_item(pamh, PAM_REPOSITORY, (const void **)&auth_rep); if (res != PAM_SUCCESS) { __pam_log(LOG_AUTH | LOG_ERR, "pam_authtok_get: error getting repository"); return (PAM_SYSTEM_ERR); } if (auth_rep == NULL) { pwu_rep = PWU_DEFAULT_REP; } else { if ((pwu_rep = calloc(1, sizeof (*pwu_rep))) == NULL) return (PAM_BUF_ERR); pwu_rep->type = auth_rep->type; pwu_rep->scope = auth_rep->scope; pwu_rep->scope_len = auth_rep->scope_len; } (void) memset(&al, 0, sizeof (al)); al[0].type = ATTR_PASSWD; al[0].next = NULL; res = __get_authtoken_attr(user, pwu_rep, al); if (pwu_rep != PWU_DEFAULT_REP) free(pwu_rep); if (res == PWU_SUCCESS && (al[0].data.val_s == NULL || al[0].data.val_s[0] == '\0')) { const char *service = NULL; const char *rhost = NULL; /* * if PAM_DIASALLOW_NULL_AUTHTOK has not been set, we * simply return IGNORE */ if ((flags & PAM_DISALLOW_NULL_AUTHTOK) == 0) return (PAM_IGNORE); /* * NULL authtoks are not allowed, so we need to fail. * We will ask for a password to mask the failure however. */ (void) pam_get_item(pamh, PAM_RHOST, (const void **)&rhost); (void) pam_get_item(pamh, PAM_SERVICE, (const void **)&service); if (service == NULL) service = "unknown"; if (rhost == NULL || *rhost == '\0') rhost = "localhost"; __pam_log(LOG_AUTH | LOG_NOTICE, "pam_authtok_get: %s: empty password not allowed for " "%s from %s.", service, user, rhost); fail = 1; } if (al[0].data.val_s != NULL) { (void) memset(al[0].data.val_s, 0, strlen(al[0].data.val_s)); free(al[0].data.val_s); } res = __pam_get_authtok(pamh, PAM_PROMPT, PAM_AUTHTOK, dgettext(TEXT_DOMAIN, "Password: "), &password); if (res != PAM_SUCCESS) return (res); if (password != NULL) { (void) pam_set_item(pamh, PAM_AUTHTOK, (const void *)password); (void) memset(password, 0, strlen(password)); free(password); } else if (debug) { __pam_log(LOG_AUTH | LOG_DEBUG, "pam_authtok_get: pam_sm_authenticate: " "got NULL password from get_authtok()"); } if (fail) { __pam_log(LOG_AUTH | LOG_DEBUG, "pam_authtok_get:pam_sm_authenticate: " "failing because NULL authtok not allowed"); return (PAM_AUTH_ERR); } else return (PAM_IGNORE); } /*ARGSUSED*/ int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv) { return (PAM_IGNORE); } # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. # # # MAPFILE HEADER START # # WARNING: STOP NOW. DO NOT MODIFY THIS FILE. # Object versioning must comply with the rules detailed in # # usr/src/lib/README.mapfiles # # You should not be making modifications here until you've read the most current # copy of that file. If you need help, contact a gatekeeper for guidance. # # MAPFILE HEADER END # $mapfile_version 2 SYMBOL_VERSION SUNW_1.1 { global: pam_sm_authenticate; pam_sm_chauthtok; pam_sm_setcred; local: *; }; # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # include ../../Makefile.lib TEXT_DOMAIN= SUNW_OST_SYSOSPAM POFILE= authtok_store.po MSGFILES= authtok_store.c # Hammerhead: amd64-only SUBDIRS= $(MACH64) all : TARGET= all clean : TARGET= clean clobber : TARGET= clobber install : TARGET= install .KEEP_STATE: all clean clobber install: $(SUBDIRS) _msg: $(MSGDOMAINPOFILE) $(SUBDIRS): FRC @cd $@; pwd; $(MAKE) $(TARGET) FRC: include $(SRC)/Makefile.msg.targ include ../../Makefile.targ # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License, Version 1.0 only # (the "License"). You may not use this file except in compliance # with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2004 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # LIBRARY= pam_authtok_store.a VERS= .1 OBJECTS= authtok_store.o include ../../Makefile.pam_modules LDLIBS += -lpam -lc all: $(LIBS) include $(SRC)/lib/Makefile.targ # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License, Version 1.0 only # (the "License"). You may not use this file except in compliance # with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2004 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" # include ../Makefile.com include ../../../Makefile.lib.64 # Hammerhead: 64-bit only - flatten passwdutil path DYNFLAGS += $(ROOT)/usr/lib/passwdutil.so.1 install: all $(ROOTLIBS64) $(ROOTLINKS64) /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * Copyright 2023 OmniOS Community Edition (OmniOSce) Association. */ #include #include #include #include #include #include #include #include #include #include #include /*PRINTFLIKE3*/ static void error(int nowarn, pam_handle_t *pamh, char *fmt, ...) { va_list ap; char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE]; va_start(ap, fmt); (void) vsnprintf(messages[0], sizeof (messages[0]), fmt, ap); if (nowarn == 0) (void) __pam_display_msg(pamh, PAM_ERROR_MSG, 1, messages, NULL); va_end(ap); } /*PRINTFLIKE3*/ static void info(int nowarn, pam_handle_t *pamh, char *fmt, ...) { va_list ap; char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE]; va_start(ap, fmt); (void) vsnprintf(messages[0], sizeof (messages[0]), fmt, ap); if (nowarn == 0) (void) __pam_display_msg(pamh, PAM_TEXT_INFO, 1, messages, NULL); va_end(ap); } #if defined(ENABLE_AGING) /* * test if authtok is aged. * returns 1 if it is, 0 otherwise */ static int authtok_is_aged(pam_handle_t *pamh) { unix_authtok_data *status; if (pam_get_data(pamh, UNIX_AUTHTOK_DATA, (const void **)status) != PAM_SUCCESS) return (0); return (status->age_status == PAM_NEW_AUTHTOK_REQD) } #endif int pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, const char **argv) { int i; int debug = 0; int nowarn = 0; attrlist l; pwu_repository_t *pwu_rep; const char *user; const char *oldpw; const char *newpw; const char *service; const struct pam_repository *auth_rep; int res; char msg[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE]; int updated_reps = 0; int server_policy = 0; for (i = 0; i < argc; i++) { if (strcmp(argv[i], "debug") == 0) debug = 1; else if (strcmp(argv[i], "nowarn") == 0) nowarn = 1; else if (strcmp(argv[i], "server_policy") == 0) server_policy = 1; } if ((flags & PAM_PRELIM_CHECK) != 0) return (PAM_IGNORE); if ((flags & PAM_UPDATE_AUTHTOK) == 0) return (PAM_SYSTEM_ERR); if ((flags & PAM_SILENT) != 0) nowarn = 1; if (debug) syslog(LOG_DEBUG, "pam_authtok_store: storing authtok"); #if defined(ENABLE_AGING) if ((flags & PAM_CHANGE_EXPIRED_AUTHTOK) && !authtok_is_aged(pamh)) { syslog(LOG_DEBUG, "pam_authtok_store: System password young"); return (PAM_IGNORE); } #endif res = pam_get_item(pamh, PAM_SERVICE, (const void **)&service); if (res != PAM_SUCCESS) { syslog(LOG_ERR, "pam_authtok_store: error getting SERVICE"); return (PAM_SYSTEM_ERR); } res = pam_get_item(pamh, PAM_USER, (const void **)&user); if (res != PAM_SUCCESS) { syslog(LOG_ERR, "pam_authtok_store: error getting USER"); return (PAM_SYSTEM_ERR); } if (user == NULL || *user == '\0') { syslog(LOG_ERR, "pam_authtok_store: username is empty"); return (PAM_USER_UNKNOWN); } res = pam_get_item(pamh, PAM_OLDAUTHTOK, (const void **)&oldpw); if (res != PAM_SUCCESS) { syslog(LOG_ERR, "pam_authtok_store: error getting OLDAUTHTOK"); return (PAM_SYSTEM_ERR); } res = pam_get_item(pamh, PAM_AUTHTOK, (const void **)&newpw); if (res != PAM_SUCCESS || newpw == NULL) { /* * A module on the stack has removed PAM_AUTHTOK. We fail */ return (PAM_SYSTEM_ERR); } l.data.val_s = strdup(newpw); if (l.data.val_s == NULL) return (PAM_BUF_ERR); /* * If the server_policy option is specified, * use the special attribute, ATTR_PASSWD_SERVER_POLICY, * to tell the update routine for each repository * to perform the necessary special operations. * For now, only the LDAP routine treats this attribute * differently that ATTR_PASSWD. It will skip the * crypting of the password before storing it in the LDAP * server. NIS, and FILES will handle ATTR_PASSWD_SERVER_POLICY * the same as ATTR_PASSWD. */ if (server_policy) l.type = ATTR_PASSWD_SERVER_POLICY; else l.type = ATTR_PASSWD; l.next = NULL; res = pam_get_item(pamh, PAM_REPOSITORY, (const void **)&auth_rep); if (res != PAM_SUCCESS) { free(l.data.val_s); syslog(LOG_ERR, "pam_authtok_store: error getting repository"); return (PAM_SYSTEM_ERR); } if (auth_rep == NULL) { pwu_rep = PWU_DEFAULT_REP; } else { if ((pwu_rep = calloc(1, sizeof (*pwu_rep))) == NULL) { free(l.data.val_s); return (PAM_BUF_ERR); } pwu_rep->type = auth_rep->type; pwu_rep->scope = auth_rep->scope; pwu_rep->scope_len = auth_rep->scope_len; } res = __set_authtoken_attr(user, oldpw, pwu_rep, &l, &updated_reps); free(l.data.val_s); if (pwu_rep != PWU_DEFAULT_REP) free(pwu_rep); /* * now map the various passwdutil return states to user messages * and PAM return codes. */ switch (res) { case PWU_SUCCESS: for (i = 1; i <= REP_LAST; i <<= 1) { if ((updated_reps & i) == 0) continue; info(nowarn, pamh, dgettext(TEXT_DOMAIN, "%s: password successfully changed for %s"), service, user); } res = PAM_SUCCESS; break; case PWU_BUSY: error(nowarn, pamh, dgettext(TEXT_DOMAIN, "%s: Password database busy. Try again later."), service); res = PAM_AUTHTOK_LOCK_BUSY; break; case PWU_STAT_FAILED: syslog(LOG_ERR, "%s: stat of password file failed", service); res = PAM_AUTHTOK_ERR; break; case PWU_OPEN_FAILED: case PWU_WRITE_FAILED: case PWU_CLOSE_FAILED: case PWU_UPDATE_FAILED: error(nowarn, pamh, dgettext(TEXT_DOMAIN, "%s: Unexpected failure. Password database unchanged."), service); res = PAM_SYSTEM_ERR; break; case PWU_NOT_FOUND: /* Different error if repository was explicitly specified */ if (auth_rep != NULL) { error(nowarn, pamh, dgettext(TEXT_DOMAIN, "%s: System error: no %s password for %s."), service, auth_rep->type, user); } else { error(nowarn, pamh, dgettext(TEXT_DOMAIN, "%s: %s does not exist."), service, user); } res = PAM_USER_UNKNOWN; break; case PWU_NOMEM: error(nowarn, pamh, dgettext(TEXT_DOMAIN, "%s: Internal memory allocation failure."), service); res = PAM_BUF_ERR; break; case PWU_SERVER_ERROR: res = PAM_SYSTEM_ERR; break; case PWU_SYSTEM_ERROR: res = PAM_SYSTEM_ERR; break; case PWU_DENIED: res = PAM_PERM_DENIED; break; case PWU_NO_CHANGE: /* * yppasswdd detected that we're not changing anything. */ info(nowarn, pamh, dgettext(TEXT_DOMAIN, "%s: Password information unchanged."), service); res = PAM_SUCCESS; break; case PWU_REPOSITORY_ERROR: syslog(LOG_NOTICE, "pam_authtok_store: detected " "unsupported configuration in /etc/nsswitch.conf."); error(nowarn, pamh, dgettext(TEXT_DOMAIN, "%s: System error: repository out of range."), service); res = PAM_SYSTEM_ERR; break; case PWU_PWD_TOO_SHORT: (void) snprintf(msg[0], sizeof (msg[0]), dgettext(TEXT_DOMAIN, "%s: Password too short."), service); (void) __pam_display_msg(pamh, PAM_ERROR_MSG, 1, msg, NULL); res = PAM_AUTHTOK_ERR; break; case PWU_PWD_INVALID: (void) snprintf(msg[0], sizeof (msg[0]), dgettext(TEXT_DOMAIN, "%s: Invalid password syntax."), service); (void) __pam_display_msg(pamh, PAM_ERROR_MSG, 1, msg, NULL); res = PAM_AUTHTOK_ERR; break; case PWU_PWD_IN_HISTORY: (void) snprintf(msg[0], sizeof (msg[0]), dgettext(TEXT_DOMAIN, "%s: Reuse of old passwords not " "allowed, the new password is in the history list."), service); (void) __pam_display_msg(pamh, PAM_ERROR_MSG, 1, msg, NULL); res = PAM_AUTHTOK_ERR; break; case PWU_CHANGE_NOT_ALLOWED: (void) snprintf(msg[0], sizeof (msg[0]), dgettext(TEXT_DOMAIN, "%s: You may not change " "this password."), service); (void) __pam_display_msg(pamh, PAM_ERROR_MSG, 1, msg, NULL); res = PAM_PERM_DENIED; break; case PWU_WITHIN_MIN_AGE: (void) snprintf(msg[0], sizeof (msg[0]), dgettext(TEXT_DOMAIN, "%s: Password can not be changed yet, " "not enough time has passed."), service); (void) __pam_display_msg(pamh, PAM_ERROR_MSG, 1, msg, NULL); res = PAM_PERM_DENIED; break; default: res = PAM_SYSTEM_ERR; break; } return (res); } # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. # # # MAPFILE HEADER START # # WARNING: STOP NOW. DO NOT MODIFY THIS FILE. # Object versioning must comply with the rules detailed in # # usr/src/lib/README.mapfiles # # You should not be making modifications here until you've read the most current # copy of that file. If you need help, contact a gatekeeper for guidance. # # MAPFILE HEADER END # $mapfile_version 2 SYMBOL_VERSION SUNW_1.1 { global: pam_sm_chauthtok; local: *; }; # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # include ../../Makefile.lib TEXT_DOMAIN= SUNW_OST_SYSOSPAM POFILE= deny.po MSGFILES= deny.c # Hammerhead: amd64-only SUBDIRS= $(MACH64) all : TARGET= all clean : TARGET= clean clobber : TARGET= clobber install : TARGET= install .KEEP_STATE: all clean clobber install: $(SUBDIRS) _msg: $(MSGDOMAINPOFILE) $(SUBDIRS): FRC @cd $@; pwd; $(MAKE) $(TARGET) FRC: include $(SRC)/Makefile.msg.targ include ../../Makefile.targ # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License, Version 1.0 only # (the "License"). You may not use this file except in compliance # with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2004 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # LIBRARY= pam_deny.a VERS= .1 OBJECTS= deny.o include ../../Makefile.pam_modules LDLIBS += -lpam -lc all: $(LIBS) include $(SRC)/lib/Makefile.targ # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License, Version 1.0 only # (the "License"). You may not use this file except in compliance # with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2004 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" # # pam_modules/deny/amd64/Makefile include ../Makefile.com include ../../../Makefile.lib.64 install: all $(ROOTLIBS64) $(ROOTLINKS64) /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * Copyright 2023 OmniOS Community Edition (OmniOSce) Association. */ #include #include #include #include /* * pam_deny - PAM service module that returns the default error code for * all service module types. * * Entry argv = debug, syslog call LOG_AUTH | LOG_DEBUG. * * Exit PAM_* appropriate for service module type. * * Uses PAM_USER, PAM_SERVICE */ static void debug(pam_handle_t *pamh, int flags, int argc, const char **argv, char *mod) { const char *user; const char *service; if (argc < 1 || strcmp(argv[0], "debug") != 0) return; (void) pam_get_item(pamh, PAM_SERVICE, (const void **)&service); (void) pam_get_item(pamh, PAM_USER, (const void **)&user); syslog(LOG_AUTH | LOG_DEBUG, "%s pam_deny:%s(%x) for %s", service ? service : "No Service Specified", mod, flags, user ? user : "No User Specified"); } int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) { debug(pamh, flags, argc, argv, "pam_sm_authenticate"); return (PAM_AUTH_ERR); } int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv) { debug(pamh, flags, argc, argv, "pam_sm_setcred"); return (PAM_CRED_ERR); } int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, const char **argv) { debug(pamh, flags, argc, argv, "pam_sm_acct_mgmt"); return (PAM_ACCT_EXPIRED); } int pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, const char **argv) { debug(pamh, flags, argc, argv, "pam_sm_open_session"); return (PAM_SESSION_ERR); } int pam_sm_close_session(pam_handle_t *pamh, int flags, int argc, const char **argv) { debug(pamh, flags, argc, argv, "pam_sm_close_session"); return (PAM_SESSION_ERR); } int pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, const char **argv) { debug(pamh, flags, argc, argv, "pam_sm_chauthtok"); return (PAM_AUTHTOK_ERR); } # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. # # # MAPFILE HEADER START # # WARNING: STOP NOW. DO NOT MODIFY THIS FILE. # Object versioning must comply with the rules detailed in # # usr/src/lib/README.mapfiles # # You should not be making modifications here until you've read the most current # copy of that file. If you need help, contact a gatekeeper for guidance. # # MAPFILE HEADER END # $mapfile_version 2 SYMBOL_VERSION SUNW_1.1 { global: pam_sm_acct_mgmt; pam_sm_authenticate; pam_sm_chauthtok; pam_sm_close_session; pam_sm_open_session; pam_sm_setcred; local: *; }; # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # include ../../Makefile.lib TEXT_DOMAIN= SUNW_OST_SYSOSPAM POFILE= list.po MSGFILES= list.c # Hammerhead: amd64-only SUBDIRS= $(MACH64) all : TARGET= all clean : TARGET= clean clobber : TARGET= clobber install : TARGET= install .KEEP_STATE: all clean clobber install: $(SUBDIRS) _msg: $(MSGDOMAINPOFILE) $(SUBDIRS): FRC @cd $@; pwd; $(MAKE) $(TARGET) FRC: include $(SRC)/Makefile.msg.targ include ../../Makefile.targ # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # LIBRARY= pam_list.a VERS= .1 OBJECTS= list.o include ../../Makefile.pam_modules LDLIBS += -lpam -lc all: $(LIBS) include $(SRC)/lib/Makefile.targ # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" # include ../Makefile.com include ../../../Makefile.lib.64 install: all $(ROOTLIBS64) $(ROOTLINKS64) /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * Copyright 2023 OmniOS Community Edition (OmniOSce) Association. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #define ILLEGAL_COMBINATION "pam_list: illegal combination of options" typedef enum { LIST_EXTERNAL_FILE, LIST_PLUS_CHECK, LIST_COMPAT_MODE } pam_list_mode_t; static const char * string_mode_type(pam_list_mode_t op_mode, boolean_t allow) { return ((op_mode == LIST_COMPAT_MODE) ? "compat" : (allow ? "allow" : "deny")); } static void log_illegal_combination(const char *s1, const char *s2) { __pam_log(LOG_AUTH | LOG_ERR, ILLEGAL_COMBINATION " %s and %s", s1, s2); } int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, const char **argv) { FILE *fd; const char *allowdeny_filename = PF_PATH; char buf[BUFSIZ]; char hostname[MAXHOSTNAMELEN]; const char *username = NULL; char *grbuf = NULL; char *bufp; const char *rhost; char *limit; int userok = 0; int hostok = 0; int i; int allow_deny_test = 0; long grbuflen = 0; boolean_t debug = B_FALSE; boolean_t allow = B_FALSE; boolean_t matched = B_FALSE; boolean_t check_user = B_TRUE; boolean_t check_group = B_FALSE; boolean_t check_host = B_FALSE; boolean_t check_exact = B_FALSE; pam_list_mode_t op_mode = LIST_PLUS_CHECK; // group reentrant interfaces limits if ((grbuflen = sysconf(_SC_GETGR_R_SIZE_MAX)) <= 0) return (PAM_BUF_ERR); for (i = 0; i < argc; ++i) { if (strncasecmp(argv[i], "debug", sizeof ("debug")) == 0) { debug = B_TRUE; } else if (strncasecmp(argv[i], "group", sizeof ("group")) == 0) { check_group = B_TRUE; } else if (strncasecmp(argv[i], "user", sizeof ("user")) == 0) { check_user = B_TRUE; } else if (strncasecmp(argv[i], "nouser", sizeof ("nouser")) == 0) { check_user = B_FALSE; } else if (strncasecmp(argv[i], "host", sizeof ("host")) == 0) { check_host = B_TRUE; } else if (strncasecmp(argv[i], "nohost", sizeof ("nohost")) == 0) { check_host = B_FALSE; } else if (strncasecmp(argv[i], "user_host_exact", sizeof ("user_host_exact")) == 0) { check_exact = B_TRUE; } else if (strcasecmp(argv[i], "compat") == 0) { if (op_mode == LIST_PLUS_CHECK) { op_mode = LIST_COMPAT_MODE; } else { log_illegal_combination("compat", string_mode_type(op_mode, allow)); return (PAM_SERVICE_ERR); } } else if (strncasecmp(argv[i], "allow=", sizeof ("allow=") - 1) == 0) { if (op_mode == LIST_PLUS_CHECK) { allowdeny_filename = argv[i] + sizeof ("allow=") - 1; allow = B_TRUE; op_mode = LIST_EXTERNAL_FILE; allow_deny_test++; } else { log_illegal_combination("allow", string_mode_type(op_mode, allow)); return (PAM_SERVICE_ERR); } } else if (strncasecmp(argv[i], "deny=", sizeof ("deny=") - 1) == 0) { if (op_mode == LIST_PLUS_CHECK) { allowdeny_filename = argv[i] + sizeof ("deny=") - 1; allow = B_FALSE; op_mode = LIST_EXTERNAL_FILE; allow_deny_test++; } else { log_illegal_combination("deny", string_mode_type(op_mode, allow)); return (PAM_SERVICE_ERR); } } else { __pam_log(LOG_AUTH | LOG_ERR, "pam_list: illegal option %s", argv[i]); return (PAM_SERVICE_ERR); } } if (((check_user || check_group || check_host || check_exact) == B_FALSE) || (allow_deny_test > 1)) { __pam_log(LOG_AUTH | LOG_ERR, ILLEGAL_COMBINATION); return (PAM_SERVICE_ERR); } if ((op_mode == LIST_COMPAT_MODE) && (check_user == B_FALSE)) { log_illegal_combination("compat", "nouser"); return (PAM_SERVICE_ERR); } if ((op_mode == LIST_COMPAT_MODE) && (check_group == B_TRUE)) { log_illegal_combination("compat", "group"); return (PAM_SERVICE_ERR); } if (debug) { __pam_log(LOG_AUTH | LOG_DEBUG, "pam_list: check_user = %d, check_host = %d," "check_exact = %d\n", check_user, check_host, check_exact); __pam_log(LOG_AUTH | LOG_DEBUG, "pam_list: auth_file: %s, %s\n", allowdeny_filename, (op_mode == LIST_COMPAT_MODE) ? "compat mode" : (allow ? "allow file" : "deny file")); } (void) pam_get_item(pamh, PAM_USER, (const void **)&username); if ((check_user || check_group || check_exact) && ((username == NULL) || (*username == '\0'))) { __pam_log(LOG_AUTH | LOG_ERR, "pam_list: username not supplied, critical error"); return (PAM_USER_UNKNOWN); } (void) pam_get_item(pamh, PAM_RHOST, (const void **)&rhost); if ((check_host || check_exact) && ((rhost == NULL) || (*rhost == '\0'))) { if (gethostname(hostname, MAXHOSTNAMELEN) == 0) { rhost = hostname; } else { __pam_log(LOG_AUTH | LOG_ERR, "pam_list: error by gethostname - %m"); return (PAM_SERVICE_ERR); } } if (debug) { __pam_log(LOG_AUTH | LOG_DEBUG, "pam_list: pam_sm_acct_mgmt for (%s,%s,)", (rhost != NULL) ? rhost : "", username); } if (strlen(allowdeny_filename) == 0) { __pam_log(LOG_AUTH | LOG_ERR, "pam_list: file name not specified"); return (PAM_SERVICE_ERR); } if ((fd = fopen(allowdeny_filename, "rF")) == NULL) { __pam_log(LOG_AUTH | LOG_ERR, "pam_list: fopen of %s: %s", allowdeny_filename, strerror(errno)); return (PAM_SERVICE_ERR); } if (check_group && ((grbuf = calloc(1, grbuflen)) == NULL)) { __pam_log(LOG_AUTH | LOG_ERR, "pam_list: could not allocate memory for group"); return (PAM_BUF_ERR); } while (fgets(buf, BUFSIZ, fd) != NULL) { /* lines longer than BUFSIZ-1 */ if ((strlen(buf) == (BUFSIZ - 1)) && (buf[BUFSIZ - 2] != '\n')) { while ((fgetc(fd) != '\n') && (!feof(fd))) { continue; } __pam_log(LOG_AUTH | LOG_DEBUG, "pam_list: long line in file," "more than %d chars, the rest ignored", BUFSIZ - 1); } /* remove unneeded colons if necessary */ if ((limit = strpbrk(buf, ":\n")) != NULL) { *limit = '\0'; } /* ignore free values */ if (buf[0] == '\0') { continue; } bufp = buf; /* test for interesting lines = +/- in /etc/passwd */ if (op_mode == LIST_COMPAT_MODE) { /* simple + matches all */ if ((buf[0] == '+') && (buf[1] == '\0')) { matched = B_TRUE; allow = B_TRUE; break; } /* simple - is not defined */ if ((buf[0] == '-') && (buf[1] == '\0')) { __pam_log(LOG_AUTH | LOG_ERR, "pam_list: simple minus unknown, " "illegal line in " PF_PATH); (void) fclose(fd); free(grbuf); return (PAM_SERVICE_ERR); } /* @ is not allowed on the first position */ if (buf[0] == '@') { __pam_log(LOG_AUTH | LOG_ERR, "pam_list: @ is not allowed on the first " "position in " PF_PATH); (void) fclose(fd); free(grbuf); return (PAM_SERVICE_ERR); } /* -user or -@netgroup */ if (buf[0] == '-') { allow = B_FALSE; bufp++; /* +user or +@netgroup */ } else if (buf[0] == '+') { allow = B_TRUE; bufp++; /* user */ } else { allow = B_TRUE; } } else if (op_mode == LIST_PLUS_CHECK) { if (((buf[0] != '+') && (buf[0] != '-')) || (buf[1] == '\0')) { continue; } if (buf[0] == '+') { allow = B_TRUE; } else { allow = B_FALSE; } bufp++; } /* * if -> netgroup line * else if -> group line * else -> user line */ if ((bufp[0] == '@') && (bufp[1] != '\0')) { bufp++; if (check_exact) { if (innetgr(bufp, rhost, username, NULL) == 1) { matched = B_TRUE; break; } } else { if (check_user) { userok = innetgr(bufp, NULL, username, NULL); } else { userok = 1; } if (check_host) { hostok = innetgr(bufp, rhost, NULL, NULL); } else { hostok = 1; } if (userok && hostok) { matched = B_TRUE; break; } } } else if ((bufp[0] == '%') && (bufp[1] != '\0')) { char **member; struct group grp; if (check_group == B_FALSE) continue; bufp++; if (getgrnam_r(bufp, &grp, grbuf, grbuflen) != NULL) { for (member = grp.gr_mem; *member != NULL; member++) { if (strcmp(*member, username) == 0) { matched = B_TRUE; break; } } } else { __pam_log(LOG_AUTH | LOG_ERR, "pam_list: %s is not a known group", bufp); } } else { if (check_user) { if (strcmp(bufp, username) == 0) { matched = B_TRUE; break; } } } /* * No match found in /etc/passwd yet. For compat mode * a failure to match should result in a return of * PAM_PERM_DENIED which is achieved below if 'matched' * is false and 'allow' is true. */ if (op_mode == LIST_COMPAT_MODE) { allow = B_TRUE; } } (void) fclose(fd); free(grbuf); if (debug) { __pam_log(LOG_AUTH | LOG_DEBUG, "pam_list: %s for %s", matched ? "matched" : "no match", allow ? "allow" : "deny"); } if (matched) { return (allow ? PAM_SUCCESS : PAM_PERM_DENIED); } /* * For compatibility with passwd_compat mode to prevent root access * denied. */ if (op_mode == LIST_PLUS_CHECK) { return (PAM_IGNORE); } return (allow ? PAM_PERM_DENIED : PAM_SUCCESS); } # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. # # # MAPFILE HEADER START # # WARNING: STOP NOW. DO NOT MODIFY THIS FILE. # Object versioning must comply with the rules detailed in # # usr/src/lib/README.mapfiles # # You should not be making modifications here until you've read the most current # copy of that file. If you need help, contact a gatekeeper for guidance. # # MAPFILE HEADER END # $mapfile_version 2 SYMBOL_VERSION SUNW_1.1 { global: pam_sm_acct_mgmt; local: *; }; # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # include ../../Makefile.lib TEXT_DOMAIN= SUNW_OST_SYSOSPAM POFILE= passwd_auth.po MSGFILES= passwd_auth.c # Hammerhead: amd64-only SUBDIRS= $(MACH64) all : TARGET= all clean : TARGET= clean clobber : TARGET= clobber install : TARGET= install .KEEP_STATE: all clean clobber install: $(SUBDIRS) _msg: $(MSGDOMAINPOFILE) $(SUBDIRS): FRC @cd $@; pwd; $(MAKE) $(TARGET) FRC: include $(SRC)/Makefile.msg.targ include ../../Makefile.targ # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License, Version 1.0 only # (the "License"). You may not use this file except in compliance # with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2004 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # usr/src/lib/pam_modules/passwd_auth/Makefile.com # LIBRARY= pam_passwd_auth.a VERS= .1 OBJECTS= passwd_auth.o include ../../Makefile.pam_modules LDLIBS += -lpam -lc all: $(LIBS) include ../../../Makefile.targ # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License, Version 1.0 only # (the "License"). You may not use this file except in compliance # with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2004 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" # include ../Makefile.com include ../../../Makefile.lib.64 # Hammerhead: 64-bit only - flatten passwdutil path DYNFLAGS += $(ROOT)/usr/lib/passwdutil.so.1 install: all $(ROOTLIBS64) $(ROOTLINKS64) # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. # # # MAPFILE HEADER START # # WARNING: STOP NOW. DO NOT MODIFY THIS FILE. # Object versioning must comply with the rules detailed in # # usr/src/lib/README.mapfiles # # You should not be making modifications here until you've read the most current # copy of that file. If you need help, contact a gatekeeper for guidance. # # MAPFILE HEADER END # $mapfile_version 2 SYMBOL_VERSION SUNW_1.1 { global: pam_sm_authenticate; pam_sm_setcred; local: *; }; /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * Copyright 2023 OmniOS Community Edition (OmniOSce) Association. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include /*PRINTFLIKE3*/ void error(int nowarn, pam_handle_t *pamh, char *fmt, ...) { va_list ap; char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE]; va_start(ap, fmt); (void) vsnprintf(messages[0], sizeof (messages[0]), fmt, ap); if (nowarn == 0) (void) __pam_display_msg(pamh, PAM_ERROR_MSG, 1, messages, NULL); va_end(ap); } /* * int pam_sm_authenticate(pamh, flags, argc, argv) * * Read authentication token from user. */ int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) { const char *user; char *password; const char *service; int i; int debug = 0; int nowarn = 0; int res; char prompt[PAM_MAX_MSG_SIZE]; char *auth_user = NULL; int retval; int privileged; char *rep_passwd = NULL; char *repository_name = NULL; attrlist al[8]; int min; int max; int lstchg; int server_policy = 0; const pam_repository_t *auth_rep = NULL; pwu_repository_t *pwu_rep = NULL; for (i = 0; i < argc; i++) { if (strcmp(argv[i], "debug") == 0) debug = 1; if (strcmp(argv[i], "nowarn") == 0) nowarn = 1; if (strcmp(argv[i], "server_policy") == 0) server_policy = 1; } if (flags & PAM_SILENT) nowarn = 1; if ((res = pam_get_user(pamh, (const char **)&user, NULL)) != PAM_SUCCESS) { if (debug) syslog(LOG_DEBUG, "pam_passwd_auth: " "get user failed: %s", pam_strerror(pamh, res)); return (res); } if (user == NULL || *user == '\0') { syslog(LOG_ERR, "pam_passwd_auth: pam_sm_authenticate: " "PAM_USER NULL or empty"); return (PAM_SYSTEM_ERR); } res = pam_get_item(pamh, PAM_AUTHTOK, (const void **)&password); if (res != PAM_SUCCESS) return (res); if (password != NULL) return (PAM_IGNORE); res = pam_get_item(pamh, PAM_SERVICE, (const void **)&service); if (res != PAM_SUCCESS) return (res); res = pam_get_item(pamh, PAM_REPOSITORY, (const void **)&auth_rep); if (res != PAM_SUCCESS) { syslog(LOG_ERR, "pam_passwd_auth: pam_sm_authenticate: " "error getting repository"); return (PAM_SYSTEM_ERR); } if (auth_rep == NULL) { pwu_rep = PWU_DEFAULT_REP; } else { if ((pwu_rep = calloc(1, sizeof (*pwu_rep))) == NULL) return (PAM_BUF_ERR); pwu_rep->type = auth_rep->type; pwu_rep->scope = auth_rep->scope; pwu_rep->scope_len = auth_rep->scope_len; } res = __user_to_authenticate(user, pwu_rep, &auth_user, &privileged); if (res != PWU_SUCCESS) { if (res == PWU_NOT_FOUND) retval = PAM_USER_UNKNOWN; else if (res == PWU_DENIED) retval = PAM_PERM_DENIED; else if (res == PWU_REPOSITORY_ERROR) { syslog(LOG_NOTICE, "pam_passwd_auth: detected unsupported " "configuration in /etc/nsswitch.conf."); error(nowarn, pamh, dgettext(TEXT_DOMAIN, "%s: " "Unsupported nsswitch entry for \"passwd:\"." " Use \"-r repository \"."), service); retval = PAM_SYSTEM_ERR; } else retval = PAM_SYSTEM_ERR; if (debug) syslog(LOG_DEBUG, "passwd_auth: __user_to_authenticate " "returned %d", retval); goto out; } if (auth_user == NULL) { /* No authentication needed */ if (debug) syslog(LOG_DEBUG, "passwd_auth: no authentication needed."); retval = PAM_SUCCESS; goto out; } /* * The password prompt differs between users updating their * own password, and users updating other an user's password */ if (privileged) { /* * TRANSLATION_NOTE * The following string has a single space at the end */ (void) snprintf(prompt, sizeof (prompt), dgettext(TEXT_DOMAIN, "Enter %s's password: "), auth_user); } else { /* * TRANSLATION_NOTE * The following string has a single space at the end */ (void) snprintf(prompt, sizeof (prompt), dgettext(TEXT_DOMAIN, "Enter existing login password: ")); } retval = __pam_get_authtok(pamh, PAM_PROMPT, PAM_AUTHTOK, prompt, &password); if (retval != PAM_SUCCESS) goto out; if (password == NULL) { syslog(LOG_ERR, "pam_passwd_auth: pam_sm_authenticate: " "got NULL password from get_authtok()"); retval = PAM_AUTH_ERR; goto out; } /* Privileged users can skip the tests that follow */ if (privileged) goto setitem; /* * Non privileged user: so we need to check the old password * and possible restrictions on password changes. */ /* Get password and it's age from the repository specified */ al[0].type = ATTR_PASSWD; al[0].next = &al[1]; al[1].type = ATTR_MIN; al[1].next = &al[2]; al[2].type = ATTR_MAX; al[2].next = &al[3]; al[3].type = ATTR_LSTCHG; al[3].next = &al[4]; al[4].type = ATTR_WARN; al[4].next = &al[5]; al[5].type = ATTR_INACT; al[5].next = &al[6]; al[6].type = ATTR_EXPIRE; al[6].next = &al[7]; al[7].type = ATTR_REP_NAME; al[7].next = NULL; res = __get_authtoken_attr(auth_user, pwu_rep, al); if (res != PWU_SUCCESS) { retval = PAM_SYSTEM_ERR; goto out; } repository_name = al[7].data.val_s; /* * if repository isn't files|nis, and user wants to follow server * policy, return PAM_IGNORE */ if (server_policy && strcmp(repository_name, "files") != 0 && strcmp(repository_name, "nis") != 0) { retval = PAM_IGNORE; goto out; } rep_passwd = al[0].data.val_s; /* * Chop off old SunOS-style password aging information. * * Note: old style password aging is only defined for UNIX-style * crypt strings, hence the comma will always be at position 14. * Note: This code is here because some other vendors might still * support this style of password aging. If we don't remove * the age field, users won't be able to change their password. * XXX yank this code when we're certain this "compatibility" * isn't needed anymore. */ if (rep_passwd != NULL && rep_passwd[0] != '$' && strlen(rep_passwd) > 13 && rep_passwd[13] == ',') rep_passwd[13] = '\0'; if (strcmp(crypt(password, rep_passwd), rep_passwd) != 0) { retval = PAM_AUTH_ERR; goto out; } /* * Now check to see if the user is allowed to change * the password. */ min = al[1].data.val_i; max = al[2].data.val_i; lstchg = al[3].data.val_i; if (max != -1 && lstchg != 0) { /* aging is turned on, and a change is not forced */ time_t daynow = DAY_NOW_32; if ((time_t)lstchg <= daynow) { /* Aged enough? */ if (daynow < (time_t)(lstchg + min)) { error(nowarn, pamh, dgettext(TEXT_DOMAIN, "%s: Sorry: less than %d days " "since the last change."), service, min); retval = PAM_PERM_DENIED; goto out; } /* * users with min>max are not allowed to * change their password. */ if (min > max) { error(nowarn, pamh, dgettext(TEXT_DOMAIN, "%s: You may not change " "this password."), service); retval = PAM_PERM_DENIED; goto out; } } } setitem: retval = pam_set_item(pamh, PAM_AUTHTOK, (void *)password); out: if (password) { (void) memset(password, 0, strlen(password)); free(password); } if (rep_passwd) { (void) memset(rep_passwd, 0, strlen(rep_passwd)); free(rep_passwd); } if (pwu_rep) free(pwu_rep); if (auth_user) free(auth_user); if (repository_name) free(repository_name); return (retval); } /*ARGSUSED*/ int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv) { return (PAM_IGNORE); } # # Copyright 2005 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License, Version 1.0 only # (the "License"). You may not use this file except in compliance # with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # #ident "%Z%%M% %I% %E% SMI" echo_file usr/src/lib/pam_modules/Makefile.pam_modules # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # include ../../Makefile.lib TEXT_DOMAIN= SUNW_OST_SYSOSPAM POFILE= roles.po MSGFILES= roles.c # Hammerhead: amd64-only SUBDIRS= $(MACH64) all : TARGET= all clean : TARGET= clean clobber : TARGET= clobber install : TARGET= install .KEEP_STATE: all clean clobber install: $(SUBDIRS) _msg: $(MSGDOMAINPOFILE) $(SUBDIRS): FRC @cd $@; pwd; $(MAKE) $(TARGET) FRC: include $(SRC)/Makefile.msg.targ include ../../Makefile.targ # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License, Version 1.0 only # (the "License"). You may not use this file except in compliance # with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2004 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # LIBRARY= pam_roles.a VERS= .1 OBJECTS= roles.o include ../../Makefile.pam_modules LDLIBS += -lpam -lsecdb -lc all: $(LIBS) include $(SRC)/lib/Makefile.targ # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License, Version 1.0 only # (the "License"). You may not use this file except in compliance # with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2004 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" # include ../Makefile.com include ../../../Makefile.lib.64 install: all $(ROOTLIBS64) $(ROOTLINKS64) # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. # # # MAPFILE HEADER START # # WARNING: STOP NOW. DO NOT MODIFY THIS FILE. # Object versioning must comply with the rules detailed in # # usr/src/lib/README.mapfiles # # You should not be making modifications here until you've read the most current # copy of that file. If you need help, contact a gatekeeper for guidance. # # MAPFILE HEADER END # $mapfile_version 2 SYMBOL_VERSION SUNW_1.1 { global: pam_sm_acct_mgmt; local: *; }; /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * Copyright 2023 OmniOS Community Edition (OmniOSce) Association. */ #include #include #include #include #include #include #include #include #include #include #include #include static int roleinlist(); /* * pam_sm_acct_mgmt(): * Account management module * This module disallows roles for primary logins and adds special * checks to allow roles for secondary logins. */ int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, const char **argv) { uid_t uid; userattr_t *user_entry; char *kva_value; const char *username; const char *auser; const char *rhost; char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE]; struct passwd *pw_entry, pwd; char buf[NSS_BUFLEN_PASSWD]; int i; int debug = 0; int allow_remote = 0; (void) pam_get_item(pamh, PAM_USER, (const void **)&username); (void) pam_get_item(pamh, PAM_AUSER, (const void **)&auser); (void) pam_get_item(pamh, PAM_RHOST, (const void **)&rhost); for (i = 0; i < argc; i++) { if (strcmp(argv[i], "allow_remote") == 0) { allow_remote = 1; } else if (strcmp(argv[i], "debug") == 0) { debug = 1; } else { __pam_log(LOG_AUTH | LOG_ERR, "pam_roles:pam_sm_acct_mgmt: illegal module " "option %s", argv[i]); } } if (debug) { const char *ruser; const char *service; (void) pam_get_item(pamh, PAM_RUSER, (const void **)&ruser); (void) pam_get_item(pamh, PAM_SERVICE, (const void **)&service); __pam_log(LOG_AUTH | LOG_DEBUG, "pam_roles:pam_sm_acct_mgmt: " "service = %s, allow_remote = %d, user = %s auser = %s " "ruser = %s rhost = %s\n", (service) ? service : "not set", allow_remote, (username) ? username : "not set", (auser) ? auser: "not set", (ruser) ? ruser: "not set", (rhost) ? rhost: "not set"); } if (username == NULL) return (PAM_USER_UNKNOWN); /* stop masquerades by mapping username to uid to username */ if ((pw_entry = getpwnam_r(username, &pwd, buf, sizeof (buf))) == NULL) return (PAM_USER_UNKNOWN); if ((pw_entry = getpwuid_r(pw_entry->pw_uid, &pwd, buf, sizeof (buf))) == NULL) return (PAM_USER_UNKNOWN); /* * If there's no user_attr entry for the primary user or it's not a * role, no further checks are needed. */ if (((user_entry = getusernam(pw_entry->pw_name)) == NULL) || ((kva_value = kva_match((kva_t *)user_entry->attr, USERATTR_TYPE_KW)) == NULL) || ((strcmp(kva_value, USERATTR_TYPE_NONADMIN_KW) != 0) && (strcmp(kva_value, USERATTR_TYPE_ADMIN_KW) != 0))) { free_userattr(user_entry); return (PAM_IGNORE); } free_userattr(user_entry); /* username is a role */ if (strcmp(username, pw_entry->pw_name) != 0) { __pam_log(LOG_AUTH | LOG_ALERT, "pam_roles:pam_sm_acct_mgmt: user name %s " "maps to user id %d which is user name %s", username, pw_entry->pw_uid, pw_entry->pw_name); } /* Who's the user requesting the role? */ if (auser != NULL && *auser != '\0') { /* authenticated requesting user */ user_entry = getusernam(auser); } else { /* user is implied by real UID */ if ((uid = getuid()) == 0) { /* * Root user_attr entry cannot have roles. * Force error and deny access. */ user_entry = NULL; } else { if ((pw_entry = getpwuid_r(uid, &pwd, buf, sizeof (buf))) == NULL) { return (PAM_USER_UNKNOWN); } user_entry = getusernam(pw_entry->pw_name); } } if ((rhost != NULL && *rhost != '\0') && allow_remote == 0) { /* don't allow remote roles for this service */ free_userattr(user_entry); return (PAM_PERM_DENIED); } /* * If the original user does not have a user_attr entry or isn't * assigned the role being assumed, fail. */ if ((user_entry == NULL) || ((kva_value = kva_match((kva_t *)user_entry->attr, USERATTR_ROLES_KW)) == NULL) || (roleinlist(kva_value, username) == 0)) { free_userattr(user_entry); (void) strlcpy(messages[0], dgettext(TEXT_DOMAIN, "Roles can only be assumed by authorized users"), sizeof (messages[0])); (void) __pam_display_msg(pamh, PAM_ERROR_MSG, 1, messages, NULL); return (PAM_PERM_DENIED); } free_userattr(user_entry); return (PAM_IGNORE); } int roleinlist(char *list, char *role) { char *lasts = (char *)NULL; char *rolename = (char *)strtok_r(list, ",", &lasts); while (rolename) { if (strcmp(rolename, role) == 0) return (1); else rolename = (char *)strtok_r(NULL, ",", &lasts); } return (0); } # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # include ../../Makefile.lib TEXT_DOMAIN= SUNW_OST_SYSOSPAM POFILE= smb_passwd.po MSGFILES= smb_passwd.c # Hammerhead: amd64-only SUBDIRS= $(MACH64) all : TARGET= all clean : TARGET= clean clobber : TARGET= clobber install : TARGET= install .KEEP_STATE: all clean clobber install: $(SUBDIRS) _msg: $(MSGDOMAINPOFILE) $(SUBDIRS): FRC @cd $@; pwd; $(MAKE) $(TARGET) FRC: include $(SRC)/Makefile.msg.targ include ../../Makefile.targ # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # Copyright 2016 RackTop Systems. # LIBRARY= pam_smb_passwd.a VERS= .1 OBJECTS= smb_passwd.o include ../../Makefile.pam_modules # These are in LDLIBS32/64 so they come before -lsmb LDLIBS32 += -L$(ROOT)/usr/lib/smbsrv # Hammerhead: 64-bit only - flatten smbsrv library path LDLIBS64 += -L$(ROOT)/usr/lib/smbsrv LDLIBS += -lsmb -lpam -lc all: $(LIBS) include $(SRC)/lib/Makefile.targ # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # Copyright 2016 RackTop Systems. # include ../Makefile.com include ../../../Makefile.lib.64 # Hammerhead: 64-bit only - flatten smbsrv and passwdutil paths DYNFLAGS += -R/usr/lib/smbsrv DYNFLAGS += $(ROOT)/usr/lib/passwdutil.so.1 install: all $(ROOTLIBS64) $(ROOTLINKS64) # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. # # # MAPFILE HEADER START # # WARNING: STOP NOW. DO NOT MODIFY THIS FILE. # Object versioning must comply with the rules detailed in # # usr/src/lib/README.mapfiles # # You should not be making modifications here until you've read the most current # copy of that file. If you need help, contact a gatekeeper for guidance. # # MAPFILE HEADER END # $mapfile_version 2 SYMBOL_VERSION SUNW_1.1 { global: pam_sm_chauthtok; local: *; }; /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * Copyright 2023 OmniOS Community Edition (OmniOSce) Association. */ #include #include #include #include #include #include #include #include #include #include #include /*PRINTFLIKE3*/ static void error(boolean_t nowarn, pam_handle_t *pamh, char *fmt, ...) { va_list ap; char message[PAM_MAX_MSG_SIZE]; if (nowarn) return; va_start(ap, fmt); (void) vsnprintf(message, sizeof (message), fmt, ap); (void) __pam_display_msg(pamh, PAM_ERROR_MSG, 1, &message, NULL); va_end(ap); } /*PRINTFLIKE3*/ static void info(boolean_t nowarn, pam_handle_t *pamh, char *fmt, ...) { va_list ap; char message[PAM_MAX_MSG_SIZE]; if (nowarn) return; va_start(ap, fmt); (void) vsnprintf(message, sizeof (message), fmt, ap); (void) __pam_display_msg(pamh, PAM_TEXT_INFO, 1, &message, NULL); va_end(ap); } int pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, const char **argv) { boolean_t debug = B_FALSE; boolean_t nowarn = B_FALSE; pwu_repository_t files_rep; const char *user; char *local_user; const char *newpw; const char *service; int privileged; int res; int i; for (i = 0; i < argc; i++) { if (strcmp(argv[i], "debug") == 0) debug = B_TRUE; else if (strcmp(argv[i], "nowarn") == 0) nowarn = B_TRUE; } if ((flags & PAM_PRELIM_CHECK) != 0) return (PAM_IGNORE); if ((flags & PAM_UPDATE_AUTHTOK) == 0) return (PAM_SYSTEM_ERR); if ((flags & PAM_SILENT) != 0) nowarn = B_TRUE; if (debug) __pam_log(LOG_AUTH | LOG_DEBUG, "pam_smb_passwd: storing authtok"); (void) pam_get_item(pamh, PAM_SERVICE, (const void **)&service); (void) pam_get_item(pamh, PAM_USER, (const void **)&user); if (user == NULL || *user == '\0') { __pam_log(LOG_AUTH | LOG_ERR, "pam_smb_passwd: username is empty"); return (PAM_USER_UNKNOWN); } (void) pam_get_item(pamh, PAM_AUTHTOK, (const void **)&newpw); if (newpw == NULL) { /* * A module on the stack has removed PAM_AUTHTOK. We fail */ return (PAM_AUTHTOK_ERR); } /* Check to see if this is a local user */ files_rep.type = "files"; files_rep.scope = NULL; files_rep.scope_len = 0; res = __user_to_authenticate(user, &files_rep, &local_user, &privileged); if (res != PWU_SUCCESS) { switch (res) { case PWU_NOT_FOUND: /* if not a local user, ignore */ if (debug) { __pam_log(LOG_AUTH | LOG_DEBUG, "pam_smb_passwd: %s is not local", user); } return (PAM_IGNORE); case PWU_DENIED: return (PAM_PERM_DENIED); } return (PAM_SYSTEM_ERR); } smb_pwd_init(B_FALSE); res = smb_pwd_setpasswd(user, newpw); smb_pwd_fini(); /* * now map the various return states to user messages * and PAM return codes. */ switch (res) { case SMB_PWE_SUCCESS: info(nowarn, pamh, dgettext(TEXT_DOMAIN, "%s: SMB password successfully changed for %s"), service, user); return (PAM_SUCCESS); case SMB_PWE_STAT_FAILED: __pam_log(LOG_AUTH | LOG_ERR, "%s: stat of SMB password file failed", service); return (PAM_SYSTEM_ERR); case SMB_PWE_OPEN_FAILED: case SMB_PWE_WRITE_FAILED: case SMB_PWE_CLOSE_FAILED: case SMB_PWE_UPDATE_FAILED: error(nowarn, pamh, dgettext(TEXT_DOMAIN, "%s: Unexpected failure. SMB password database unchanged."), service); return (PAM_SYSTEM_ERR); case SMB_PWE_BUSY: error(nowarn, pamh, dgettext(TEXT_DOMAIN, "%s: SMB password database busy. Try again later."), service); return (PAM_AUTHTOK_LOCK_BUSY); case SMB_PWE_USER_UNKNOWN: error(nowarn, pamh, dgettext(TEXT_DOMAIN, "%s: %s does not exist."), service, user); return (PAM_USER_UNKNOWN); case SMB_PWE_USER_DISABLE: error(nowarn, pamh, dgettext(TEXT_DOMAIN, "%s: %s is disable. SMB password database unchanged."), service, user); return (PAM_IGNORE); case SMB_PWE_DENIED: return (PAM_PERM_DENIED); default: res = PAM_SYSTEM_ERR; break; } return (res); } # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # include ../../Makefile.lib TEXT_DOMAIN= SUNW_OST_SYSOSPAM POFILE= smbfs_login.po MSGFILES= smbfs_login.c # BUILDPO runs the sourcefile through the pre-processor # make sure it can find what it needs. $(POFILE) : CPPFLAGS += -I$(SRC)/lib/libsmbfs # Hammerhead: amd64-only SUBDIRS= $(MACH64) all : TARGET= all clean : TARGET= clean clobber : TARGET= clobber install : TARGET= install .KEEP_STATE: all clean clobber install: $(SUBDIRS) _msg: $(MSGDOMAINPOFILE) $(SUBDIRS): FRC @cd $@; pwd; $(MAKE) $(TARGET) FRC: include $(SRC)/Makefile.msg.targ include ../../Makefile.targ # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # LIBRARY= pam_smbfs_login.a VERS= .1 OBJECTS= smbfs_login.o include ../../Makefile.pam_modules LDLIBS += -lpam -lc -lsmbfs CFLAGS += -I../../../libsmbfs CFLAGS64 += -I../../../libsmbfs all: $(LIBS) include $(SRC)/lib/Makefile.targ # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" # include ../Makefile.com include ../../../Makefile.lib.64 # Hammerhead: GNU ld needs rpath-link for mech_krb5.so.1 (transitive dep via libsmbfs) DYNFLAGS += -Wl,-rpath-link,$(ROOT)/usr/lib/gss install: all $(ROOTLIBS64) $(ROOTLINKS64) # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. # # # MAPFILE HEADER START # # WARNING: STOP NOW. DO NOT MODIFY THIS FILE. # Object versioning must comply with the rules detailed in # # usr/src/lib/README.mapfiles # # You should not be making modifications here until you've read the most current # copy of that file. If you need help, contact a gatekeeper for guidance. # # MAPFILE HEADER END # $mapfile_version 2 SYMBOL_VERSION SUNW_1.1 { global: pam_sm_authenticate; pam_sm_setcred; local: *; }; /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * Copyright 2023 OmniOS Community Edition (OmniOSce) Association. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /*ARGSUSED*/ int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) { return (PAM_IGNORE); } int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv) { boolean_t debug = B_FALSE; char dom[20]; const char *user; const char *pw; const char *service; struct passwd pwbuf; char buf[NSS_BUFLEN_PASSWD]; char *home; uid_t uid; int res = PAM_SUCCESS; int i, mask; for (i = 0; i < argc; i++) { if (strcmp(argv[i], "debug") == 0) debug = B_TRUE; } /* Since our creds don't time out, ignore a refresh. */ if ((flags & PAM_REFRESH_CRED) != 0) return (PAM_IGNORE); /* Check for unknown options */ mask = PAM_ESTABLISH_CRED | PAM_REINITIALIZE_CRED | PAM_DELETE_CRED; if ((flags & ~mask) != 0) return (PAM_IGNORE); (void) pam_get_item(pamh, PAM_SERVICE, (const void **)&service); (void) pam_get_item(pamh, PAM_USER, (const void **)&user); if (user == NULL || *user == '\0') { __pam_log(LOG_AUTH | LOG_ERR, "pam_smbfs_login: username is empty"); return (PAM_IGNORE); } if (getpwnam_r(user, &pwbuf, buf, sizeof (buf)) == NULL) { __pam_log(LOG_AUTH | LOG_ERR, "pam_smbfs_login: username %s can't be found", user); return (PAM_IGNORE); } uid = pwbuf.pw_uid; home = pwbuf.pw_dir; (void) pam_get_item(pamh, PAM_AUTHTOK, (const void **)&pw); if (pw == NULL) { /* * A module on the stack has removed PAM_AUTHTOK. */ return (PAM_IGNORE); } res = smbfs_default_dom_usr(home, NULL, dom, sizeof (dom), NULL, 0); if (res != 0) (void) strcpy(dom, "WORKGROUP"); if (debug) __pam_log(LOG_AUTH | LOG_DEBUG, "pam_smbfs_login: service %s, dom %s, user %s", service, dom, user); if ((flags & (PAM_ESTABLISH_CRED | PAM_REINITIALIZE_CRED)) != 0) res = smbfs_keychain_add(uid, dom, user, pw); if ((flags & PAM_DELETE_CRED) != 0) res = smbfs_keychain_del(uid, dom, user); /* * map errors to user messages and PAM return codes. */ switch (res) { case SMB_KEYCHAIN_SUCCESS: if (debug) __pam_log(LOG_AUTH | LOG_DEBUG, "smbfs password successfully stored for %s", user); break; case SMB_KEYCHAIN_BADPASSWD: __pam_log(LOG_AUTH | LOG_ERR, "smbfs password is invalid"); break; case SMB_KEYCHAIN_BADDOMAIN: __pam_log(LOG_AUTH | LOG_ERR, "%s: smbfs domain %s is invalid", service, dom); break; case SMB_KEYCHAIN_BADUSER: __pam_log(LOG_AUTH | LOG_ERR, "smbfs user %s is invalid", user); break; case SMB_KEYCHAIN_NODRIVER: __pam_log(LOG_AUTH | LOG_ERR, "driver open failed (%s), smbfs password not stored", strerror(errno)); break; case SMB_KEYCHAIN_UNKNOWN: __pam_log(LOG_AUTH | LOG_ERR, "Unexpected failure, smbfs password not stored"); break; default: __pam_log(LOG_AUTH | LOG_ERR, "driver ioctl failed (%s), smbfs password not stored", strerror(errno)); break; } return (PAM_IGNORE); } # # This file and its contents are supplied under the terms of the # Common Development and Distribution License ("CDDL"), version 1.0. # You may only use this file in accordance with the terms of version # 1.0 of the CDDL. # # A full copy of the text of the CDDL should have accompanied this # source. A copy of the CDDL is also available via the Internet at # http://www.illumos.org/license/CDDL. # # Copyright 2014 Nexenta Systems, Inc. # include ../../Makefile.lib TEXT_DOMAIN= SUNW_OST_SYSOSPAM POFILE= pam_timestamp.po MSGFILES= pam_timestamp.c # Hammerhead: amd64-only SUBDIRS= $(MACH64) all : TARGET= all clean : TARGET= clean clobber : TARGET= clobber install : TARGET= install .KEEP_STATE: all clean clobber install: $(SUBDIRS) _msg: $(MSGDOMAINPOFILE) $(SUBDIRS): FRC @cd $@; pwd; $(MAKE) $(TARGET) FRC: include $(SRC)/Makefile.msg.targ include ../../Makefile.targ # # This file and its contents are supplied under the terms of the # Common Development and Distribution License ("CDDL"), version 1.0. # You may only use this file in accordance with the terms of version # 1.0 of the CDDL. # # A full copy of the text of the CDDL should have accompanied this # source. A copy of the CDDL is also available via the Internet at # http://www.illumos.org/license/CDDL. # # Copyright 2014 Nexenta Systems, Inc. # # # usr/src/lib/pam_modules/pam_timestamp/Makefile.com # LIBRARY= pam_timestamp.a VERS= .1 OBJECTS= pam_timestamp.o include ../../Makefile.pam_modules LDLIBS += -lpam -lc all: $(LIBS) include $(SRC)/lib/Makefile.targ # # This file and its contents are supplied under the terms of the # Common Development and Distribution License ("CDDL"), version 1.0. # You may only use this file in accordance with the terms of version # 1.0 of the CDDL. # # A full copy of the text of the CDDL should have accompanied this # source. A copy of the CDDL is also available via the Internet at # http://www.illumos.org/license/CDDL. # # Copyright 2014 Nexenta Systems, Inc. # include ../Makefile.com include ../../../Makefile.lib.64 install: all $(ROOTLIBS64) $(ROOTLINKS64) # # This file and its contents are supplied under the terms of the # Common Development and Distribution License ("CDDL"), version 1.0. # You may only use this file in accordance with the terms of version # 1.0 of the CDDL. # # A full copy of the text of the CDDL should have accompanied this # source. A copy of the CDDL is also available via the Internet at # http://www.illumos.org/license/CDDL. # # Copyright 2014 Nexenta Systems, Inc. # # # MAPFILE HEADER START # # WARNING: STOP NOW. DO NOT MODIFY THIS FILE. # Object versioning must comply with the rules detailed in # # usr/src/lib/README.mapfiles # # You should not be making modifications here until you've read the most current # copy of that file. If you need help, contact a gatekeeper for guidance. # # MAPFILE HEADER END # $mapfile_version 2 SYMBOL_VERSION ILLUMOS_0.1 { global: pam_sm_authenticate; pam_sm_setcred; local: *; }; /* * This file and its contents are supplied under the terms of the * Common Development and Distribution License ("CDDL"), version 1.0. * You may only use this file in accordance with the terms of version * 1.0 of the CDDL. * * A full copy of the text of the CDDL should have accompanied this * source. A copy of the CDDL is also available via the Internet at * http://www.illumos.org/license/CDDL. */ /* * Copyright 2014 Nexenta Systems, Inc. * Copyright 2023 OmniOS Community Edition (OmniOSce) Association. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define TIMESTAMP_DIR "/var/run/tty_timestamps" #define TIMESTAMP_TIMEOUT 5 /* default timeout */ #define ROOT_UID 0 /* root uid */ #define ROOT_GID 0 /* root gid */ struct user_info { dev_t dev; /* ID of device tty resides on */ dev_t rdev; /* tty device ID */ ino_t ino; /* tty inode number */ uid_t uid; /* user's uid */ pid_t ppid; /* parent pid */ pid_t sid; /* session ID associated with tty/ppid */ timestruc_t ts; /* time of tty last status change */ }; int debug = 0; int validate_basic(pam_handle_t *pamh, char *user_tty, char *timestampfile) { const char *user; const char *auser; const char *ttyn; /* get user, auser and users's tty */ (void) pam_get_item(pamh, PAM_USER, (const void **)&user); (void) pam_get_item(pamh, PAM_AUSER, (const void **)&auser); (void) pam_get_item(pamh, PAM_TTY, (const void **)&ttyn); if (user == NULL || *user == '\0') { syslog(LOG_AUTH | LOG_ERR, "pam_timestamp: " "PAM_USER NULL or empty"); return (PAM_IGNORE); } if (auser == NULL || *auser == '\0') { syslog(LOG_AUTH | LOG_ERR, "pam_timestamp: " "PAM_AUSER NULL or empty"); return (PAM_IGNORE); } if (ttyn == NULL || *ttyn == '\0') { syslog(LOG_AUTH | LOG_ERR, "pam_timestamp: " "PAM_TTY NULL or empty"); return (PAM_IGNORE); } if (debug) syslog(LOG_AUTH | LOG_DEBUG, "pam_timestamp: " "user = %s, auser = %s, tty = %s", user, auser, ttyn); (void) strlcpy(user_tty, ttyn, MAXPATHLEN); if (strchr(ttyn, '/') == NULL || strncmp(ttyn, "/dev/", 5) == 0) { ttyn = strrchr(ttyn, '/') + 1; } else { syslog(LOG_AUTH | LOG_ERR, "pam_timestamp: " "invalid tty: %s", ttyn); return (PAM_IGNORE); } /* format timestamp file name */ (void) snprintf(timestampfile, MAXPATHLEN, "%s/%s/%s:%s", TIMESTAMP_DIR, auser, ttyn, user); return (PAM_SUCCESS); } int validate_dir(const char *dir) { struct stat sb; /* * check that the directory exist and has * right owner and permissions. */ if (lstat(dir, &sb) < 0) { syslog(LOG_AUTH | LOG_ERR, "pam_timestamp: " "directory %s does not exist", dir); return (PAM_IGNORE); } if (!S_ISDIR(sb.st_mode)) { syslog(LOG_AUTH | LOG_ERR, "pam_timestamp: " "%s is not a directory", dir); return (PAM_IGNORE); } if (S_ISLNK(sb.st_mode)) { syslog(LOG_AUTH | LOG_ERR, "pam_timestamp: " "%s is a symbolic link", dir); return (PAM_IGNORE); } if (sb.st_uid != 0 || sb.st_gid != 0) { syslog(LOG_AUTH | LOG_ERR, "pam_timestamp: " "%s is not owned by root", dir); return (PAM_IGNORE); } if (sb.st_mode & (S_IWGRP | S_IWOTH | S_IROTH)) { syslog(LOG_AUTH | LOG_ERR, "pam_timestamp: " "%s has wrong permissions", dir); return (PAM_IGNORE); } return (PAM_SUCCESS); } int create_dir(char *dir) { /* * create directory if it doesn't exist and attempt to set * the owner to root. */ if (mkdir(dir, S_IRWXU) < 0) { if (errno != EEXIST) { syslog(LOG_AUTH | LOG_ERR, "pam_timestamp: " "can't create directory %s", dir); return (PAM_IGNORE); } } else if (lchown(dir, ROOT_UID, ROOT_GID) < 0) { syslog(LOG_AUTH | LOG_ERR, "pam_timestamp: " "can't set permissions on directory %s", dir); return (PAM_IGNORE); } return (PAM_SUCCESS); } /* * pam_sm_authenticate * * Read authentication from user, using cached successful authentication * attempts. * * returns PAM_SUCCESS on success, otherwise always returns PAM_IGNORE: * while this module has "sufficient" control value, in case of any failure * user will be authenticated with the pam_unix_auth module. * options - * debug * timeout= timeout in min, default is 5 */ int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) { struct user_info info; struct stat sb, tty; time_t timeout = 0; long tmp = 0; int result = PAM_IGNORE; int i; int fd = -1; char *p; char user_tty[MAXPATHLEN]; char timestampdir[MAXPATHLEN]; char timestampfile[MAXPATHLEN]; char *sudir; timeout = TIMESTAMP_TIMEOUT; /* check options passed to this module */ for (i = 0; i < argc; i++) { if (strcmp(argv[i], "debug") == 0) { debug = 1; } else if (strncmp(argv[i], "timeout=", 8) == 0) { tmp = strtol(argv[i] + 8, &p, 0); if ((p != NULL) && (*p == '\0') && tmp > 0) { timeout = tmp; } } } if (validate_basic(pamh, user_tty, timestampfile) != PAM_SUCCESS) return (result); sudir = TIMESTAMP_DIR; if (validate_dir(sudir) != PAM_SUCCESS) return (result); (void) strlcpy(timestampdir, timestampfile, MAXPATHLEN); if (validate_dir(dirname(timestampdir)) != PAM_SUCCESS) return (result); /* * check that timestamp file is exist and has right owner * and permissions. */ if (lstat(timestampfile, &sb) == 0 && sb.st_size != 0) { if (!S_ISREG(sb.st_mode)) { (void) unlink(timestampfile); syslog(LOG_AUTH | LOG_ERR, "pam_timestamp: " "timestamp file %s is not a regular file", timestampfile); return (result); } if (sb.st_uid != 0 || sb.st_gid != 0) { (void) unlink(timestampfile); syslog(LOG_AUTH | LOG_ERR, "pam_timestamp: " "timestamp file %s is not owned by root", timestampfile); return (result); } if (sb.st_nlink != 1 || S_ISLNK(sb.st_mode)) { (void) unlink(timestampfile); syslog(LOG_AUTH | LOG_ERR, "pam_timestamp: " "timestamp file %s is a symbolic link", timestampfile); return (result); } if (sb.st_mode & (S_IRWXG | S_IRWXO)) { (void) unlink(timestampfile); syslog(LOG_AUTH | LOG_ERR, "pam_timestamp: " "timestamp file %s has wrong permissions", timestampfile); return (result); } } else { if (debug) syslog(LOG_AUTH | LOG_DEBUG, "pam_timestamp: " "timestamp file %s does not exist: %m", timestampfile); return (result); } if (stat(user_tty, &tty) < 0) { syslog(LOG_AUTH | LOG_ERR, "pam_timestamp: " "can't stat tty: %m"); return (result); } if ((fd = open(timestampfile, O_RDONLY)) < 0) { syslog(LOG_AUTH | LOG_ERR, "pam_timestamp: " "can't open timestamp file %s for reading: %m", timestampfile); return (result); } if (read(fd, &info, sizeof (info)) != sizeof (info)) { (void) close(fd); (void) unlink(timestampfile); syslog(LOG_AUTH | LOG_ERR, "pam_timestamp: " "timestamp file '%s' is corrupt: %m", timestampfile); return (result); } if (info.dev != tty.st_dev || info.ino != tty.st_ino || info.rdev != tty.st_rdev || info.sid != getsid(getpid()) || info.uid != getuid() || info.ts.tv_sec != tty.st_ctim.tv_sec || info.ts.tv_nsec != tty.st_ctim.tv_nsec) { (void) close(fd); (void) unlink(timestampfile); syslog(LOG_AUTH | LOG_ERR, "pam_timestamp: " "the content of the timestamp file '%s' is not valid", timestampfile); return (result); } if (time((time_t *)0) - sb.st_mtime > 60 * timeout) { (void) unlink(timestampfile); syslog(LOG_AUTH | LOG_ERR, "pam_timestamp: " "timestamp file '%s' has expired, disallowing access", timestampfile); return (result); } else { if (debug) syslog(LOG_AUTH | LOG_DEBUG, "pam_timestamp: " "timestamp file %s is not expired, " "allowing access ", timestampfile); result = PAM_SUCCESS; } return (result); } /* * pam_sm_setcred * * Creates timestamp directory and writes * timestamp file if it doesn't exist. * * returns PAM_SUCCESS on success, otherwise PAM_IGNORE */ int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv) { struct stat sb; struct stat tty; struct user_info info; int result = PAM_IGNORE; int fd = -1; char user_tty[MAXPATHLEN]; char timestampdir[MAXPATHLEN]; char timestampfile[MAXPATHLEN]; /* validate flags */ if (flags && !(flags & PAM_ESTABLISH_CRED) && !(flags & PAM_REINITIALIZE_CRED) && !(flags & PAM_REFRESH_CRED) && !(flags & PAM_DELETE_CRED) && !(flags & PAM_SILENT)) { syslog(LOG_ERR, "pam_timestamp: illegal flag %d", flags); return (result); } if (validate_basic(pamh, user_tty, timestampfile) != PAM_SUCCESS) return (result); /* * user doesn't need to authenticate for PAM_DELETE_CRED */ if (flags & PAM_DELETE_CRED) { (void) unlink(timestampfile); return (result); } /* if the timestamp file exist, there is nothing to do */ if (lstat(timestampfile, &sb) == 0) { if (debug) syslog(LOG_AUTH | LOG_DEBUG, "pam_timestamp: " "timestamp file %s is not expired", timestampfile); return (result); } if (create_dir(TIMESTAMP_DIR) != PAM_SUCCESS) return (result); (void) strlcpy(timestampdir, timestampfile, MAXPATHLEN); if (create_dir(dirname(timestampdir)) != PAM_SUCCESS) return (result); if (stat(user_tty, &tty) < 0) { syslog(LOG_AUTH | LOG_ERR, "pam_timestamp: " "can't stat tty: %m"); return (result); } info.dev = tty.st_dev; info.ino = tty.st_ino; info.rdev = tty.st_rdev; info.sid = getsid(getpid()); info.uid = getuid(); info.ts = tty.st_ctim; if ((fd = open(timestampfile, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR)) < 0) { syslog(LOG_AUTH | LOG_ERR, "pam_timestamp: " "can't open timestamp file %s for writing: %m", timestampfile); return (result); } else if (fchown(fd, ROOT_UID, ROOT_GID) != 0) { syslog(LOG_AUTH | LOG_ERR, "pam_timestamp: " "can't set permissions on timestamp file %s: %m", timestampfile); (void) close(fd); return (result); } if (write(fd, &info, sizeof (info)) != sizeof (info)) { (void) close(fd); syslog(LOG_AUTH | LOG_ERR, "pam_timestamp: " "can't write timestamp file %s: %m", timestampfile); return (result); } (void) close(fd); return (PAM_SUCCESS); } # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # include ../../Makefile.lib # Hammerhead: amd64-only SUBDIRS= $(MACH64) all : TARGET= all clean : TARGET= clean clobber : TARGET= clobber install : TARGET= install .KEEP_STATE: all clean clobber install: $(SUBDIRS) $(SUBDIRS): FRC @cd $@; pwd; $(MAKE) $(TARGET) FRC: _msg: include ../../Makefile.targ # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # LIBRARY= pam_tsol_account.a VERS= .1 OBJECTS= tsol_acct.o include ../../Makefile.pam_modules LDLIBS += -lc -lpam -ltsol -ltsnet all: $(LIBS) include $(SRC)/lib/Makefile.targ # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # #ident "%Z%%M% %I% %E% SMI" # # # lib/pam_modules/tsol/amd64/Makefile include ../Makefile.com include ../../../Makefile.lib.64 install: all $(ROOTLIBS64) $(ROOTLINKS64) # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. # # # MAPFILE HEADER START # # WARNING: STOP NOW. DO NOT MODIFY THIS FILE. # Object versioning must comply with the rules detailed in # # usr/src/lib/README.mapfiles # # You should not be making modifications here until you've read the most current # copy of that file. If you need help, contact a gatekeeper for guidance. # # MAPFILE HEADER END # $mapfile_version 2 SYMBOL_VERSION SUNW_1.1 { global: pam_sm_acct_mgmt; local: *; }; /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * Copyright 2023 OmniOS Community Edition (OmniOSce) Association. */ #include #include #include #include #include #include #include #include #include /* * pam_tsol_account - Trusted Extensions account management. * Validates that the user's label range contains * the process label (label of the zone). */ static void free_labels(m_range_t *r, m_label_t *l) { m_label_free(r->lower_bound); m_label_free(r->upper_bound); free(r); m_label_free(l); } int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, const char **argv) { int i; int debug = 0; int allow_unlabeled = 0; const char *user; char *rhost; m_range_t *range; m_label_t *plabel; for (i = 0; i < argc; i++) { if (strcmp(argv[i], "debug") == 0) { debug = 1; } else if (strcmp(argv[i], "allow_unlabeled") == 0) { allow_unlabeled = 1; } else { __pam_log(LOG_AUTH | LOG_ERR, "pam_tsol_account: illegal option %s", argv[i]); } } /* Trusted Extensions not enabled */ if (!is_system_labeled()) return (PAM_IGNORE); (void) pam_get_item(pamh, PAM_USER, (const void **)&user); (void) pam_get_item(pamh, PAM_RHOST, (const void **)&rhost); if (debug) { __pam_log(LOG_AUTH | LOG_DEBUG, "pam_tsol_account: allowed_unlabeled = %d, user %s, " "rhost %s", allow_unlabeled, (user == NULL) ? "NULL" : (*user == '\0') ? "ZERO" : user, (rhost == NULL) ? "NULL" : (*rhost == '\0') ? "ZERO" : rhost); } if (user == NULL || *user == '\0') { __pam_log(LOG_AUTH | LOG_ERR, "pam_tsol_account: no user"); return (PAM_USER_UNKNOWN); } if ((range = getuserrange(user)) == NULL) { __pam_log(LOG_AUTH | LOG_ERR, "pam_tsol_account: getuserrange(%s) failure", user); return (PAM_SYSTEM_ERR); } if ((plabel = m_label_alloc(MAC_LABEL)) == NULL) { __pam_log(LOG_AUTH | LOG_ERR, "pam_tsol_account: out of memory"); free_labels(range, NULL); return (PAM_BUF_ERR); } if (getplabel(plabel) < 0) { __pam_log(LOG_AUTH | LOG_CRIT, "pam_tsol_account: Unable to get process label %m"); free_labels(range, plabel); return (PAM_SYSTEM_ERR); } if (!blinrange(plabel, range)) { free_labels(range, plabel); return (PAM_PERM_DENIED); } free_labels(range, plabel); /* Remote Host Type Policy Check */ if ((allow_unlabeled == 0) && (getzoneid() == GLOBAL_ZONEID) && (rhost != NULL && *rhost != '\0')) { tsol_host_type_t host_type; host_type = tsol_getrhtype(rhost); switch (host_type) { case SUN_CIPSO: break; case UNLABELED: default: return (PAM_PERM_DENIED); } } return (PAM_SUCCESS); } # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # include ../../Makefile.lib TEXT_DOMAIN= SUNW_OST_SYSOSPAM POFILE= unix_account.po MSGFILES= unix_acct.c # Hammerhead: amd64-only SUBDIRS= $(MACH64) all : TARGET= all clean : TARGET= clean clobber : TARGET= clobber install : TARGET= install .KEEP_STATE: all clean clobber install: $(SUBDIRS) # need rule here $(POFILE): $(MSGFILES) $(BUILDPO.msgfiles) _msg: $(MSGDOMAINPOFILE) $(SUBDIRS): FRC @cd $@; pwd; $(MAKE) $(TARGET) FRC: include $(SRC)/Makefile.msg.targ include ../../Makefile.targ # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # LIBRARY= pam_unix_account.a VERS= .1 OBJECTS= unix_acct.o include ../../Makefile.pam_modules LDLIBS += -lpam -lc # Enable large file support for reading the lastlog file. CPPFLAGS += -D_FILE_OFFSET_BITS=64 CERRWARN += -Wno-parentheses all: $(LIBS) include $(SRC)/lib/Makefile.targ # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License, Version 1.0 only # (the "License"). You may not use this file except in compliance # with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2005 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" # include ../Makefile.com include ../../../Makefile.lib.64 # Hammerhead: 64-bit only - flatten passwdutil path DYNFLAGS += $(ROOT)/usr/lib/passwdutil.so.1 install: all $(ROOTLIBS64) $(ROOTLINKS64) # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. # # # MAPFILE HEADER START # # WARNING: STOP NOW. DO NOT MODIFY THIS FILE. # Object versioning must comply with the rules detailed in # # usr/src/lib/README.mapfiles # # You should not be making modifications here until you've read the most current # copy of that file. If you need help, contact a gatekeeper for guidance. # # MAPFILE HEADER END # $mapfile_version 2 SYMBOL_VERSION SUNW_1.1 { global: pam_sm_acct_mgmt; local: *; }; /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * Copyright (c) 2016 by Delphix. All rights reserved. * Copyright 2023 OmniOS Community Edition (OmniOSce) Association. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define LASTLOG "/var/adm/lastlog" #define LOGINADMIN "/etc/default/login" #define UNIX_AUTH_DATA "SUNW-UNIX-AUTH-DATA" #define UNIX_AUTHTOK_DATA "SUNW-UNIX-AUTHTOK-DATA" /* * Function Declarations */ extern void setusershell(); extern int _nfssys(int, void *); typedef struct _unix_authtok_data_ { int age_status; }unix_authtok_data; /*ARGSUSED*/ static void unix_cleanup( pam_handle_t *pamh, void *data, int pam_status) { free((unix_authtok_data *)data); } /* * check_for_login_inactivity - Check for login inactivity * */ static int check_for_login_inactivity( uid_t pw_uid, struct spwd *shpwd) { int fdl; struct lastlog ll; int retval; offset_t offset; offset = (offset_t)pw_uid * (offset_t)sizeof (struct lastlog); if ((fdl = open(LASTLOG, O_RDWR|O_CREAT, 0444)) >= 0) { /* * Read the last login (ll) time */ if (llseek(fdl, offset, SEEK_SET) != offset) { __pam_log(LOG_AUTH | LOG_ERR, "pam_unix_acct: pam_sm_acct_mgmt: " "can't obtain last login info on uid %d " "(uid too large)", pw_uid); (void) close(fdl); return (0); } retval = read(fdl, (char *)&ll, sizeof (ll)); /* Check for login inactivity */ if ((shpwd->sp_inact > 0) && (retval == sizeof (ll)) && ll.ll_time) { /* * account inactive too long. * and no update password set * and no last pwd change date in shadow file * and last pwd change more than inactive time * then account inactive too long and no access. */ if (((time_t)((ll.ll_time / DAY) + shpwd->sp_inact) < DAY_NOW) && (shpwd->sp_lstchg != 0) && (shpwd->sp_lstchg != -1) && ((shpwd->sp_lstchg + shpwd->sp_inact) < DAY_NOW)) { /* * Account inactive for too long */ (void) close(fdl); return (1); } } (void) close(fdl); } return (0); } /* * new_password_check() * * check to see if the user needs to change their password */ static int new_password_check(shpwd, flags) struct spwd *shpwd; int flags; { time_t now = DAY_NOW; /* * We want to make sure that we change the password only if * passwords are required for the system, the user does not * have a password, AND the user's NULL password can be changed * according to its password aging information */ if ((flags & PAM_DISALLOW_NULL_AUTHTOK) != 0) { if (shpwd->sp_pwdp[0] == '\0') { if (((shpwd->sp_max == -1) || ((time_t)shpwd->sp_lstchg > now) || ((now >= (time_t)(shpwd->sp_lstchg + shpwd->sp_min)) && (shpwd->sp_max >= shpwd->sp_min)))) { return (PAM_NEW_AUTHTOK_REQD); } } } return (PAM_SUCCESS); } /* * perform_passwd_aging_check * - Check for password exipration. */ static int perform_passwd_aging_check( pam_handle_t *pamh, struct spwd *shpwd, int flags) { time_t now = DAY_NOW; int idledays = -1; char *ptr; char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE]; void *defp; if ((defp = defopen_r(LOGINADMIN)) != NULL) { if ((ptr = defread_r("IDLEWEEKS=", defp)) != NULL) idledays = 7 * atoi(ptr); defclose_r(defp); } /* * if (sp_lstchg == 0), the administrator has forced the * user to change their passwd */ if (shpwd->sp_lstchg == 0) return (PAM_NEW_AUTHTOK_REQD); /* If password aging is disabled (or min>max), all is well */ if (shpwd->sp_max < 0 || shpwd->sp_max < shpwd->sp_min) return (PAM_SUCCESS); /* Password aging is enabled. See if the password has aged */ if (now < (time_t)(shpwd->sp_lstchg + shpwd->sp_max)) return (PAM_SUCCESS); /* Password has aged. Has it aged more than idledays ? */ if (idledays < 0) /* IDLEWEEKS not configured */ return (PAM_NEW_AUTHTOK_REQD); /* idledays is configured */ if (idledays > 0 && (now < (time_t)(shpwd->sp_lstchg + idledays))) return (PAM_NEW_AUTHTOK_REQD); /* password has aged more that allowed for by IDLEWEEKS */ if (!(flags & PAM_SILENT)) { (void) strlcpy(messages[0], dgettext(TEXT_DOMAIN, "Your password has been expired for too long."), sizeof (messages[0])); (void) strlcpy(messages[1], dgettext(TEXT_DOMAIN, "Please contact the system administrator."), sizeof (messages[0])); (void) __pam_display_msg(pamh, PAM_ERROR_MSG, 2, messages, NULL); } return (PAM_AUTHTOK_EXPIRED); } /* * warn_user_passwd_will_expire - warn the user when the password will * expire. */ static void warn_user_passwd_will_expire( pam_handle_t *pamh, struct spwd shpwd) { time_t now = DAY_NOW; char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE]; time_t days; if ((shpwd.sp_warn > 0) && (shpwd.sp_max > 0) && (now + shpwd.sp_warn) >= (time_t)(shpwd.sp_lstchg + shpwd.sp_max)) { days = (time_t)(shpwd.sp_lstchg + shpwd.sp_max) - now; if (days <= 0) (void) snprintf(messages[0], sizeof (messages[0]), dgettext(TEXT_DOMAIN, "Your password will expire within 24 hours.")); else if (days == 1) (void) snprintf(messages[0], sizeof (messages[0]), dgettext(TEXT_DOMAIN, "Your password will expire in 1 day.")); else (void) snprintf(messages[0], sizeof (messages[0]), dgettext(TEXT_DOMAIN, "Your password will expire in %d days."), (int)days); (void) __pam_display_msg(pamh, PAM_TEXT_INFO, 1, messages, NULL); } } /* * pam_sm_acct_mgmt - main account managment routine. * Returns: module error or specific error on failure */ int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, const char **argv) { uid_t pw_uid; char *repository_name = NULL; char *user; attrlist attr_pw[3]; attrlist attr_spw[7]; pwu_repository_t *pwu_rep = PWU_DEFAULT_REP; const pwu_repository_t *auth_rep = NULL; int error = PAM_ACCT_EXPIRED; int result; int i; int debug = 0; int server_policy = 0; unix_authtok_data *status; struct spwd shpwd = {NULL, NULL, -1, -1, -1, -1, -1, -1, 0}; for (i = 0; i < argc; i++) { if (strcasecmp(argv[i], "debug") == 0) debug = 1; else if (strcasecmp(argv[i], "server_policy") == 0) server_policy = 1; else if (strcasecmp(argv[i], "nowarn") == 0) { flags = flags | PAM_SILENT; } else { __pam_log(LOG_AUTH | LOG_ERR, "ACCOUNT:pam_sm_acct_mgmt: illegal option %s", argv[i]); } } if (debug) __pam_log(LOG_AUTH | LOG_DEBUG, "pam_unix_account: entering pam_sm_acct_mgmt()"); if ((error = pam_get_item(pamh, PAM_USER, (const void **)&user)) != PAM_SUCCESS) goto out; if (user == NULL) { error = PAM_USER_UNKNOWN; goto out; } else shpwd.sp_namp = user; if ((error = pam_get_item(pamh, PAM_REPOSITORY, (const void **)&auth_rep)) != PAM_SUCCESS) { goto out; } if (auth_rep == NULL) { pwu_rep = PWU_DEFAULT_REP; } else { if ((pwu_rep = calloc(1, sizeof (*pwu_rep))) == NULL) { error = PAM_BUF_ERR; goto out; } pwu_rep->type = auth_rep->type; pwu_rep->scope = auth_rep->scope; pwu_rep->scope_len = auth_rep->scope_len; } /* * First get the password information */ attr_pw[0].type = ATTR_REP_NAME; attr_pw[0].next = &attr_pw[1]; attr_pw[1].type = ATTR_UID; attr_pw[1].next = &attr_pw[2]; attr_pw[2].type = ATTR_PASSWD; attr_pw[2].next = NULL; result = __get_authtoken_attr(user, pwu_rep, attr_pw); if (result == PWU_NOT_FOUND) { error = PAM_USER_UNKNOWN; goto out; } else if (result == PWU_DENIED) { error = PAM_PERM_DENIED; goto out; } else if (result == PWU_NOMEM) { error = PAM_BUF_ERR; goto out; } else if (result != PWU_SUCCESS) { error = PAM_SERVICE_ERR; goto out; } else { repository_name = attr_pw[0].data.val_s; pw_uid = attr_pw[1].data.val_i; shpwd.sp_pwdp = attr_pw[2].data.val_s; } /* * if repository is not files|nis, and user wants server_policy, * we don't care about aging and hence return PAM_IGNORE */ if (server_policy && strcmp(repository_name, "files") != 0 && strcmp(repository_name, "nis") != 0) { error = PAM_IGNORE; goto out; } /* * Now get the aging information */ attr_spw[0].type = ATTR_LSTCHG; attr_spw[0].next = &attr_spw[1]; attr_spw[1].type = ATTR_MIN; attr_spw[1].next = &attr_spw[2]; attr_spw[2].type = ATTR_MAX; attr_spw[2].next = &attr_spw[3]; attr_spw[3].type = ATTR_WARN; attr_spw[3].next = &attr_spw[4]; attr_spw[4].type = ATTR_INACT; attr_spw[4].next = &attr_spw[5]; attr_spw[5].type = ATTR_EXPIRE; attr_spw[5].next = &attr_spw[6]; attr_spw[6].type = ATTR_FLAG; attr_spw[6].next = NULL; result = __get_authtoken_attr(user, pwu_rep, attr_spw); if (result == PWU_SUCCESS) { shpwd.sp_lstchg = attr_spw[0].data.val_i; shpwd.sp_min = attr_spw[1].data.val_i; shpwd.sp_max = attr_spw[2].data.val_i; shpwd.sp_warn = attr_spw[3].data.val_i; shpwd.sp_inact = attr_spw[4].data.val_i; shpwd.sp_expire = attr_spw[5].data.val_i; shpwd.sp_flag = attr_spw[6].data.val_i; } if (debug) { char *pw = "Unix PW"; if (shpwd.sp_pwdp == NULL) pw = "NULL"; else if (strncmp(shpwd.sp_pwdp, LOCKSTRING, sizeof (LOCKSTRING) - 1) == 0) pw = LOCKSTRING; else if (strcmp(shpwd.sp_pwdp, NOPWDRTR) == 0) pw = NOPWDRTR; if (result == PWU_DENIED) { __pam_log(LOG_AUTH | LOG_DEBUG, "pam_unix_account: %s: permission denied " "to access password aging information. " "Using defaults.", user); } __pam_log(LOG_AUTH | LOG_DEBUG, "%s Policy:Unix, pw=%s, lstchg=%d, min=%d, max=%d, " "warn=%d, inact=%d, expire=%d", user, pw, shpwd.sp_lstchg, shpwd.sp_min, shpwd.sp_max, shpwd.sp_warn, shpwd.sp_inact, shpwd.sp_expire); } if (pwu_rep != PWU_DEFAULT_REP) { free(pwu_rep); pwu_rep = PWU_DEFAULT_REP; } if (result == PWU_NOT_FOUND) { error = PAM_USER_UNKNOWN; goto out; } else if (result == PWU_NOMEM) { error = PAM_BUF_ERR; goto out; } else if (result != PWU_SUCCESS && result != PWU_DENIED) { error = PAM_SERVICE_ERR; goto out; } /* * Check for locked account */ if (shpwd.sp_pwdp != NULL && strncmp(shpwd.sp_pwdp, LOCKSTRING, sizeof (LOCKSTRING) - 1) == 0) { const char *service; const char *rhost = NULL; (void) pam_get_item(pamh, PAM_SERVICE, (const void **)&service); (void) pam_get_item(pamh, PAM_RHOST, (const void **)&rhost); __pam_log(LOG_AUTH | LOG_NOTICE, "pam_unix_account: %s attempting to validate locked " "account %s from %s", service, user, (rhost != NULL && *rhost != '\0') ? rhost : "local host"); error = PAM_PERM_DENIED; goto out; } /* * Check for NULL password and, if so, see if such is allowed */ if (shpwd.sp_pwdp[0] == '\0' && (flags & PAM_DISALLOW_NULL_AUTHTOK) != 0) { const char *service; const char *rhost = NULL; (void) pam_get_item(pamh, PAM_SERVICE, (const void **)&service); (void) pam_get_item(pamh, PAM_RHOST, (const void **)&rhost); __pam_log(LOG_AUTH | LOG_NOTICE, "pam_unix_account: %s: empty password not allowed for " "account %s from %s", service, user, (rhost != NULL && *rhost != '\0') ? rhost : "local host"); error = PAM_PERM_DENIED; goto out; } /* * Check for account expiration */ if (shpwd.sp_expire > 0 && (time_t)shpwd.sp_expire < DAY_NOW) { error = PAM_ACCT_EXPIRED; goto out; } /* * Check for excessive login account inactivity */ if (check_for_login_inactivity(pw_uid, &shpwd)) { error = PAM_PERM_DENIED; goto out; } /* * Check to see if the user needs to change their password */ if (error = new_password_check(&shpwd, flags)) { goto out; } /* * Check to make sure password aging information is okay */ if ((error = perform_passwd_aging_check(pamh, &shpwd, flags)) != PAM_SUCCESS) { goto out; } /* * Finally, warn the user if their password is about to expire. */ if (!(flags & PAM_SILENT)) { warn_user_passwd_will_expire(pamh, shpwd); } /* * All done, return Success */ error = PAM_SUCCESS; out: { int pam_res; unix_authtok_data *authtok_data; if (debug) { __pam_log(LOG_AUTH | LOG_DEBUG, "pam_unix_account: %s: %s", (user == NULL)?"NULL":user, pam_strerror(pamh, error)); } if (repository_name) free(repository_name); if (pwu_rep != PWU_DEFAULT_REP) free(pwu_rep); if (shpwd.sp_pwdp) { (void) memset(shpwd.sp_pwdp, 0, strlen(shpwd.sp_pwdp)); free(shpwd.sp_pwdp); } /* store the password aging status in the pam handle */ pam_res = pam_get_data(pamh, UNIX_AUTHTOK_DATA, (const void **)&authtok_data); if ((status = (unix_authtok_data *)calloc(1, sizeof (unix_authtok_data))) == NULL) { return (PAM_BUF_ERR); } if (pam_res == PAM_SUCCESS) (void) memcpy(status, authtok_data, sizeof (unix_authtok_data)); status->age_status = error; if (pam_set_data(pamh, UNIX_AUTHTOK_DATA, status, unix_cleanup) != PAM_SUCCESS) { free(status); return (PAM_SERVICE_ERR); } } return (error); } # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # include ../../Makefile.lib TEXT_DOMAIN= SUNW_OST_SYSOSPAM POFILE= unix_auth.po MSGFILES= unix_auth.c # Hammerhead: amd64-only SUBDIRS= $(MACH64) all : TARGET= all clean : TARGET= clean clobber : TARGET= clobber install : TARGET= install .KEEP_STATE: all clean clobber install: $(SUBDIRS) _msg: $(MSGDOMAINPOFILE) $(SUBDIRS): FRC @cd $@; pwd; $(MAKE) $(TARGET) FRC: include $(SRC)/Makefile.msg.targ include ../../Makefile.targ # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # LIBRARY= pam_unix_auth.a VERS= .1 OBJECTS= unix_auth.o include ../../Makefile.pam_modules LDLIBS += -lpam -lsecdb -lc all: $(LIBS) include $(SRC)/lib/Makefile.targ # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License, Version 1.0 only # (the "License"). You may not use this file except in compliance # with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2004 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" # include ../Makefile.com include ../../../Makefile.lib.64 # Hammerhead: 64-bit only - flatten passwdutil path DYNFLAGS += $(ROOT)/usr/lib/passwdutil.so.1 install: all $(ROOTLIBS64) $(ROOTLINKS64) # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. # # # MAPFILE HEADER START # # WARNING: STOP NOW. DO NOT MODIFY THIS FILE. # Object versioning must comply with the rules detailed in # # usr/src/lib/README.mapfiles # # You should not be making modifications here until you've read the most current # copy of that file. If you need help, contact a gatekeeper for guidance. # # MAPFILE HEADER END # $mapfile_version 2 SYMBOL_VERSION SUNW_1.1 { global: pam_sm_authenticate; pam_sm_setcred; local: *; }; /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * Copyright 2023 OmniOS Community Edition (OmniOSce) Association. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define LOGINADMIN "/etc/default/login" #define MAXTRYS 5 /*PRINTFLIKE2*/ void error(pam_handle_t *pamh, char *fmt, ...) { va_list ap; char messages[1][PAM_MAX_MSG_SIZE]; va_start(ap, fmt); (void) vsnprintf(messages[0], sizeof (messages[0]), fmt, ap); (void) __pam_display_msg(pamh, PAM_ERROR_MSG, 1, messages, NULL); va_end(ap); } static int get_max_failed(const char *user) { char *val = NULL; userattr_t *uattr; int do_lock = 0; int retval = 0; char *p; void *defp; if ((uattr = getusernam(user)) != NULL) val = kva_match(uattr->attr, USERATTR_LOCK_AFTER_RETRIES_KW); if (val != NULL) { do_lock = (strcasecmp(val, "yes") == 0); } else if ((defp = defopen_r(AUTH_POLICY)) != NULL) { int flags; flags = defcntl_r(DC_GETFLAGS, 0, defp); TURNOFF(flags, DC_CASE); (void) defcntl_r(DC_SETFLAGS, flags, defp); if ((p = defread_r("LOCK_AFTER_RETRIES=", defp)) != NULL) do_lock = (strcasecmp(p, "yes") == 0); defclose_r(defp); } if (uattr != NULL) free_userattr(uattr); if (do_lock) { retval = MAXTRYS; if ((defp = defopen_r(LOGINADMIN)) != NULL) { if ((p = defread_r("RETRIES=", defp)) != NULL) retval = atoi(p); defclose_r(defp); } } return (retval); } static void display_warning(pam_handle_t *pamh, int failures, char *homedir) { char hushpath[MAXPATHLEN]; struct stat buf; (void) snprintf(hushpath, sizeof (hushpath), "%s/.hushlogin", homedir); if (stat(hushpath, &buf) == 0) return; if (failures == 1) error(pamh, "Warning: 1 failed login attempt since last " "successful login."); else if (failures < FAILCOUNT_MASK) error(pamh, "Warning: %d failed login attempts since last " "successful login.", failures); else error(pamh, "Warning: at least %d failed login attempts since " "last successful login.", failures); } /* * int pam_sm_authenticate(pamh, flags, arc, argv) * * This routine verifies that the password as stored in the * PAM_AUTHTOK item is indeed the password that belongs to the user * as stored in PAM_USER. * * This routine will not establish Secure RPC Credentials, the pam_dhkeys * module should be stacked before us if Secure RPC Credentials are needed * to obtain passwords. */ int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) { int i; int debug = 0; int nowarn = (flags & PAM_SILENT) != 0; const char *user; const char *passwd; char *rep_passwd; char *crypt_passwd; char *repository_name; const struct pam_repository *auth_rep; pwu_repository_t *pwu_rep; attrlist attr_pw[4]; int result; int server_policy = 0; int old_failed_count; char *homedir = NULL; int dolock = 1; for (i = 0; i < argc; i++) { if (strcmp(argv[i], "debug") == 0) debug = 1; else if (strcmp(argv[i], "nowarn") == 0) nowarn = 1; else if (strcmp(argv[i], "server_policy") == 0) server_policy = 1; else if (strcmp(argv[i], "nolock") == 0) dolock = 0; } if (debug) __pam_log(LOG_AUTH | LOG_DEBUG, "pam_unix_auth: entering pam_sm_authenticate()"); if (pam_get_item(pamh, PAM_USER, (const void **)&user) != PAM_SUCCESS) { __pam_log(LOG_AUTH | LOG_DEBUG, "pam_unix_auth: USER not set"); return (PAM_SYSTEM_ERR); } if (user == NULL || *user == '\0') { __pam_log(LOG_AUTH | LOG_DEBUG, "pam_unix_auth: USER NULL or empty!\n"); return (PAM_USER_UNKNOWN); } if (pam_get_item(pamh, PAM_AUTHTOK, (const void **)&passwd) != PAM_SUCCESS) { __pam_log(LOG_AUTH | LOG_DEBUG, "pam_unix_auth: AUTHTOK not set!\n"); return (PAM_SYSTEM_ERR); } result = pam_get_item(pamh, PAM_REPOSITORY, (const void **)&auth_rep); if (result == PAM_SUCCESS && auth_rep != NULL) { if ((pwu_rep = calloc(1, sizeof (*pwu_rep))) == NULL) return (PAM_BUF_ERR); pwu_rep->type = auth_rep->type; pwu_rep->scope = auth_rep->scope; pwu_rep->scope_len = auth_rep->scope_len; } else { pwu_rep = PWU_DEFAULT_REP; } /* * Get password and the name of the repository where the * password resides. */ attr_pw[0].type = ATTR_PASSWD; attr_pw[0].next = &attr_pw[1]; attr_pw[1].type = ATTR_REP_NAME; attr_pw[1].next = &attr_pw[2]; /* * Also get the current number of failed logins; we use * this later to determine whether we need to reset the count * on a succesful authentication. We use the home-directory * to look for .hushlogin in order to optionaly surpress the * "failed attempts" message. */ attr_pw[2].type = ATTR_FAILED_LOGINS; attr_pw[2].next = &attr_pw[3]; attr_pw[3].type = ATTR_HOMEDIR; attr_pw[3].next = NULL; result = __get_authtoken_attr(user, pwu_rep, attr_pw); if (pwu_rep != PWU_DEFAULT_REP) free(pwu_rep); if (result == PWU_NOT_FOUND) { __pam_log(LOG_AUTH | LOG_DEBUG, "pam_unix_auth: user %s not found\n", user); return (PAM_USER_UNKNOWN); } if (result == PWU_DENIED) { __pam_log(LOG_AUTH | LOG_DEBUG, "pam_unix_auth: failed to obtain attributes"); return (PAM_PERM_DENIED); } if (result != PWU_SUCCESS) return (PAM_SYSTEM_ERR); rep_passwd = attr_pw[0].data.val_s; repository_name = attr_pw[1].data.val_s; old_failed_count = attr_pw[2].data.val_i; homedir = attr_pw[3].data.val_s; /* * Chop off old SunOS-style password aging information. * * Note: old style password aging is only defined for UNIX-style * crypt strings, hence the comma will always be at position 14. * Note: This code is here because some other vendors might still * support this style of password aging. If we don't remove * the age field, no one will be able to login. * XXX yank this code when we're certain this "compatibility" * isn't needed anymore. */ if (rep_passwd != NULL && rep_passwd[0] != '$' && strlen(rep_passwd) > 13 && rep_passwd[13] == ',') rep_passwd[13] = '\0'; /* Is a password check required? */ if (rep_passwd == NULL || *rep_passwd == '\0') { if (flags & PAM_DISALLOW_NULL_AUTHTOK) { result = PAM_AUTH_ERR; __pam_log(LOG_AUTH | LOG_NOTICE, "pam_unix_auth: empty password for %s not allowed.", user); goto out; } else { result = PAM_SUCCESS; goto out; } } /* * Password check *is* required. Make sure we have a valid * pointer in PAM_AUTHTOK */ if (passwd == NULL) { result = PAM_AUTH_ERR; goto out; } if (server_policy && strcmp(repository_name, "files") != 0 && strcmp(repository_name, "nis") != 0) { result = PAM_IGNORE; goto out; } /* Now check the entered password */ if ((crypt_passwd = crypt(passwd, rep_passwd)) == NULL) { switch (errno) { case ENOMEM: result = PAM_BUF_ERR; break; case ELIBACC: result = PAM_OPEN_ERR; break; default: result = PAM_SYSTEM_ERR; } goto out; } if (strcmp(crypt_passwd, rep_passwd) == 0) result = PAM_SUCCESS; else result = PAM_AUTH_ERR; /* Clear or increment failed failed count */ if (dolock && (result == PAM_SUCCESS && old_failed_count > 0)) { old_failed_count = __rst_failed_count(user, repository_name); if (nowarn == 0 && old_failed_count > 0) display_warning(pamh, old_failed_count, homedir); } else if (dolock && result == PAM_AUTH_ERR) { int max_failed = get_max_failed(user); if (max_failed != 0) { if (__incr_failed_count(user, repository_name, max_failed) == PWU_ACCOUNT_LOCKED) result = PAM_MAXTRIES; } } out: if (rep_passwd) free(rep_passwd); if (repository_name) free(repository_name); if (homedir) free(homedir); return (result); } /*ARGSUSED*/ int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv) { return (PAM_IGNORE); } # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # include ../../Makefile.lib TEXT_DOMAIN= SUNW_OST_SYSOSPAM POFILE= unix_cred.po MSGFILES= unix_cred.c # Hammerhead: amd64-only SUBDIRS= $(MACH64) all : TARGET= all clean : TARGET= clean clobber : TARGET= clobber install : TARGET= install .KEEP_STATE: all clean clobber install: $(SUBDIRS) _msg: $(MSGDOMAINPOFILE) $(SUBDIRS): FRC @cd $@; pwd; $(MAKE) $(TARGET) FRC: include $(SRC)/Makefile.msg.targ include ../../Makefile.targ # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # LIBRARY= pam_unix_cred.a VERS= .1 OBJECTS= unix_cred.o include ../../Makefile.pam_modules LDLIBS += -lbsm -lpam -lsecdb -lproject -lc CERRWARN += -Wno-parentheses CERRWARN += $(CNOWARN_UNINIT) all: $(LIBS) include $(SRC)/lib/Makefile.targ # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License, Version 1.0 only # (the "License"). You may not use this file except in compliance # with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2004 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" # include ../Makefile.com include ../../../Makefile.lib.64 install: all $(ROOTLIBS64) $(ROOTLINKS64) # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. # # # MAPFILE HEADER START # # WARNING: STOP NOW. DO NOT MODIFY THIS FILE. # Object versioning must comply with the rules detailed in # # usr/src/lib/README.mapfiles # # You should not be making modifications here until you've read the most current # copy of that file. If you need help, contact a gatekeeper for guidance. # # MAPFILE HEADER END # $mapfile_version 2 SYMBOL_VERSION SUNW_1.1 { global: pam_sm_authenticate; pam_sm_setcred; local: *; }; /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright 2023 OmniOS Community Edition (OmniOSce) Association. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* adt_get_auid() */ #include #include #include #define PROJECT "project=" #define PROJSZ (sizeof (PROJECT) - 1) /* * unix_cred - PAM auth modules must contain both pam_sm_authenticate * and pam_sm_setcred. Some other auth module is responsible * for authentication (e.g., pam_unix_auth.so), this module * only implements pam_sm_setcred so that the authentication * can be separated without knowledge of the Solaris Unix style * credential setting. * Solaris Unix style credential setting includes initializing * the audit characteristics if not already initialized and * setting the user's default and limit privileges. */ /* * unix_cred - pam_sm_authenticate * * Returns PAM_IGNORE. */ /*ARGSUSED*/ int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) { return (PAM_IGNORE); } /* * Set the privilege set. The attributes are enumerated by _enum_attrs, * including the attribues user_attr, prof_attr and policy.conf */ static int getset(char *str, priv_set_t **res) { priv_set_t *tmp; char *badp; int len; if (str == NULL) return (0); len = strlen(str) + 1; badp = alloca(len); (void) memset(badp, '\0', len); do { const char *q, *endp; tmp = priv_str_to_set(str, ",", &endp); if (tmp == NULL) { if (endp == NULL) break; /* Now remove the bad privilege endp points to */ q = strchr(endp, ','); if (q == NULL) q = endp + strlen(endp); if (*badp != '\0') (void) strlcat(badp, ",", len); /* Memset above guarantees NUL termination */ /* LINTED */ (void) strncat(badp, endp, q - endp); /* excise bad privilege; strtok ignores 2x sep */ (void) memmove((void *)endp, q, strlen(q) + 1); } } while (tmp == NULL && *str != '\0'); if (tmp == NULL) { syslog(LOG_AUTH|LOG_ERR, "pam_setcred: can't parse privilege specification: %m\n"); return (-1); } else if (*badp != '\0') { syslog(LOG_AUTH|LOG_DEBUG, "pam_setcred: unrecognized privilege(s): %s\n", badp); } *res = tmp; return (0); } typedef struct deflim { char *def; char *lim; } deflim_t; /*ARGSUSED*/ static int finddeflim(const char *name, kva_t *kva, void *ctxt, void *pres) { deflim_t *pdef = pres; char *val; if (pdef->def == NULL) { val = kva_match(kva, USERATTR_DFLTPRIV_KW); if (val != NULL) pdef->def = strdup(val); } if (pdef->lim == NULL) { val = kva_match(kva, USERATTR_LIMPRIV_KW); if (val != NULL) pdef->lim = strdup(val); } return (pdef->lim != NULL && pdef->def != NULL); } /* * unix_cred - pam_sm_setcred * * Entry flags = PAM_ESTABLISH_CRED, set up Solaris Unix cred. * PAM_DELETE_CRED, NOP, return PAM_SUCCESS. * PAM_REINITIALIZE_CRED, set up Solaris Unix cred, * or merge the current context with the new * user. * PAM_REFRESH_CRED, set up Solaris Unix cred. * PAM_SILENT, print no messages to user. * * Returns PAM_SUCCESS, if all successful. * PAM_CRED_ERR, if unable to set credentials. * PAM_USER_UNKNOWN, if PAM_USER not set, or unable to find * user in databases. * PAM_SYSTEM_ERR, if no valid flag, or unable to get/set * user's audit state. */ int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv) { int i; int debug = 0; uint_t nowarn = flags & PAM_SILENT; int ret = PAM_SUCCESS; const char *user; const char *auser; const char *rhost; const char *tty; au_id_t auid; adt_session_data_t *ah; adt_termid_t *termid = NULL; priv_set_t *lim, *def, *tset; char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE]; char buf[PROJECT_BUFSZ]; struct project proj, *pproj; int error; char *projname; const char *kvs; char *nckvs = NULL; struct passwd pwd; char pwbuf[NSS_BUFLEN_PASSWD]; deflim_t deflim; for (i = 0; i < argc; i++) { if (strcmp(argv[i], "debug") == 0) debug = 1; else if (strcmp(argv[i], "nowarn") == 0) nowarn |= 1; } if (debug) syslog(LOG_AUTH | LOG_DEBUG, "pam_unix_cred: pam_sm_setcred(flags = %x, argc= %d)", flags, argc); (void) pam_get_item(pamh, PAM_USER, (const void **)&user); if (user == NULL || *user == '\0') { syslog(LOG_AUTH | LOG_ERR, "pam_unix_cred: USER NULL or empty!\n"); return (PAM_USER_UNKNOWN); } (void) pam_get_item(pamh, PAM_AUSER, (const void **)&auser); (void) pam_get_item(pamh, PAM_RHOST, (const void **)&rhost); (void) pam_get_item(pamh, PAM_TTY, (const void **)&tty); if (debug) syslog(LOG_AUTH | LOG_DEBUG, "pam_unix_cred: user = %s, auser = %s, rhost = %s, " "tty = %s", user, (auser == NULL) ? "NULL" : (*auser == '\0') ? "ZERO" : auser, (rhost == NULL) ? "NULL" : (*rhost == '\0') ? "ZERO" : rhost, (tty == NULL) ? "NULL" : (*tty == '\0') ? "ZERO" : tty); /* validate flags */ switch (flags & (PAM_ESTABLISH_CRED | PAM_DELETE_CRED | PAM_REINITIALIZE_CRED | PAM_REFRESH_CRED)) { case 0: /* set default flag */ flags |= PAM_ESTABLISH_CRED; break; case PAM_ESTABLISH_CRED: case PAM_REINITIALIZE_CRED: case PAM_REFRESH_CRED: break; case PAM_DELETE_CRED: return (PAM_SUCCESS); default: syslog(LOG_AUTH | LOG_ERR, "pam_unix_cred: invalid flags %x", flags); return (PAM_SYSTEM_ERR); } /* * if auditing on and process audit state not set, * setup audit context for process. */ if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0) { syslog(LOG_AUTH | LOG_ERR, "pam_unix_cred: cannot create start audit session %m"); return (PAM_SYSTEM_ERR); } adt_get_auid(ah, &auid); if (debug) { int auditstate; if (auditon(A_GETCOND, (caddr_t)&auditstate, sizeof (auditstate)) != 0) { auditstate = AUC_DISABLED; } syslog(LOG_AUTH | LOG_DEBUG, "pam_unix_cred: state = %d, auid = %d", auditstate, auid); } if (getpwnam_r(user, &pwd, pwbuf, sizeof (pwbuf)) == NULL) { syslog(LOG_AUTH | LOG_ERR, "pam_unix_cred: cannot get passwd entry for user = %s", user); ret = PAM_USER_UNKNOWN; goto adt_done; } if ((auid == AU_NOAUDITID) && (flags & PAM_ESTABLISH_CRED)) { struct passwd apwd; char apwbuf[NSS_BUFLEN_PASSWD]; errno = 0; if ((rhost == NULL || *rhost == '\0')) { if (adt_load_ttyname(tty, &termid) != 0) { if (errno == ENETDOWN) { /* * tolerate not being able to * translate local hostname * to a termid -- it will be * "loopback". */ syslog(LOG_AUTH | LOG_ERR, "pam_unix_cred: cannot load " "ttyname: %m, continuing."); goto adt_setuser; } else if (errno != 0) { syslog(LOG_AUTH | LOG_ERR, "pam_unix_cred: cannot load " "ttyname: %m."); } else { syslog(LOG_AUTH | LOG_ERR, "pam_unix_cred: cannot load " "ttyname."); } ret = PAM_SYSTEM_ERR; goto adt_done; } } else { if (adt_load_hostname(rhost, &termid) != 0) { if (errno != 0) { syslog(LOG_AUTH | LOG_ERR, "pam_unix_cred: cannot load " "hostname: %m."); } else { syslog(LOG_AUTH | LOG_ERR, "pam_unix_cred: cannot load " "hostname."); } ret = PAM_SYSTEM_ERR; goto adt_done; } } adt_setuser: if ((auser != NULL) && (*auser != '\0') && (getpwnam_r(auser, &apwd, apwbuf, sizeof (apwbuf)) != NULL)) { /* * set up the initial audit for user coming * from another user */ if (adt_set_user(ah, apwd.pw_uid, apwd.pw_gid, apwd.pw_uid, apwd.pw_gid, termid, ADT_NEW) != 0) { syslog(LOG_AUTH | LOG_ERR, "pam_unix_cred: cannot set auser audit " "%m"); ret = PAM_SYSTEM_ERR; goto adt_done; } if (adt_set_user(ah, pwd.pw_uid, pwd.pw_gid, pwd.pw_uid, pwd.pw_gid, NULL, ADT_UPDATE) != 0) { syslog(LOG_AUTH | LOG_ERR, "pam_unix_cred: cannot merge user audit " "%m"); ret = PAM_SYSTEM_ERR; goto adt_done; } if (debug) { syslog(LOG_AUTH | LOG_DEBUG, "pam_unix_cred: new audit set for %d:%d", apwd.pw_uid, pwd.pw_uid); } } else { /* * No authenticated user or authenticated user is * not a local user, no remote attribution, set * up the initial audit as for direct user login */ if (adt_set_user(ah, pwd.pw_uid, pwd.pw_gid, pwd.pw_uid, pwd.pw_gid, termid, ADT_NEW) != 0) { syslog(LOG_AUTH | LOG_ERR, "pam_unix_cred: cannot set user audit %m"); ret = PAM_SYSTEM_ERR; goto adt_done; } } if (adt_set_proc(ah) != 0) { syslog(LOG_AUTH | LOG_ERR, "pam_unix_cred: cannot set process audit %m"); ret = PAM_CRED_ERR; goto adt_done; } if (debug) { syslog(LOG_AUTH | LOG_DEBUG, "pam_unix_cred: new audit set for %d", pwd.pw_uid); } } else if ((auid != AU_NOAUDITID) && (flags & PAM_REINITIALIZE_CRED)) { if (adt_set_user(ah, pwd.pw_uid, pwd.pw_gid, pwd.pw_uid, pwd.pw_gid, NULL, ADT_UPDATE) != 0) { syslog(LOG_AUTH | LOG_ERR, "pam_unix_cred: cannot set user audit %m"); ret = PAM_SYSTEM_ERR; goto adt_done; } if (adt_set_proc(ah) != 0) { syslog(LOG_AUTH | LOG_ERR, "pam_unix_cred: cannot set process audit %m"); ret = PAM_CRED_ERR; goto adt_done; } if (debug) { syslog(LOG_AUTH | LOG_DEBUG, "pam_unix_cred: audit merged for %d:%d", auid, pwd.pw_uid); } } else if (debug) { syslog(LOG_AUTH | LOG_DEBUG, "pam_unix_cred: audit already set for %d", auid); } adt_done: if (termid != NULL) free(termid); if (adt_end_session(ah) != 0) { syslog(LOG_AUTH | LOG_ERR, "pam_unix_cred: unable to end audit session"); } if (ret != PAM_SUCCESS) return (ret); /* Initialize the user's project */ (void) pam_get_item(pamh, PAM_RESOURCE, (const void **)&kvs); if (kvs != NULL) { char *tmp, *lasts, *tok; nckvs = tmp = strdup(kvs); if (nckvs == NULL) return (PAM_BUF_ERR); while ((tok = strtok_r(tmp, ";", &lasts)) != NULL) { if (strncmp(tok, PROJECT, PROJSZ) == 0) { projname = tok + PROJSZ; break; } tmp = NULL; } } else { projname = NULL; } if (projname == NULL || *projname == '\0') { pproj = getdefaultproj(user, &proj, (void *)&buf, PROJECT_BUFSZ); } else { pproj = getprojbyname(projname, &proj, (void *)&buf, PROJECT_BUFSZ); } /* projname points into nckvs; this is the first opportunity to free */ free(nckvs); if (pproj == NULL) { syslog(LOG_AUTH | LOG_ERR, "pam_unix_cred: no default project for user %s", user); goto setprivs; } if ((error = setproject(proj.pj_name, user, TASK_NORMAL)) != 0) { kva_t *kv_array; switch (error) { case SETPROJ_ERR_TASK: if (errno == EAGAIN) { syslog(LOG_AUTH | LOG_ERR, "pam_unix_cred: project \"%s\" resource " "control limit has been reached", proj.pj_name); (void) snprintf(messages[0], sizeof (messages[0]), dgettext( TEXT_DOMAIN, "Resource control limit has been " "reached")); } else { syslog(LOG_AUTH | LOG_ERR, "pam_unix_cred: user %s could not join " "project \"%s\": %m", user, proj.pj_name); (void) snprintf(messages[0], sizeof (messages[0]), dgettext( TEXT_DOMAIN, "Could not join default project")); } if (!nowarn) (void) __pam_display_msg(pamh, PAM_ERROR_MSG, 1, messages, NULL); break; case SETPROJ_ERR_POOL: (void) snprintf(messages[0], sizeof (messages[0]), dgettext(TEXT_DOMAIN, "Could not bind to resource pool")); switch (errno) { case EACCES: syslog(LOG_AUTH | LOG_ERR, "pam_unix_cred: project \"%s\" could not " "bind to resource pool: No resource pool " "accepting default bindings exists", proj.pj_name); (void) snprintf(messages[1], sizeof (messages[1]), dgettext(TEXT_DOMAIN, "No resource pool accepting " "default bindings exists")); break; case ESRCH: syslog(LOG_AUTH | LOG_ERR, "pam_unix_cred: project \"%s\" could not " "bind to resource pool: The resource pool " "is unknown", proj.pj_name); (void) snprintf(messages[1], sizeof (messages[1]), dgettext(TEXT_DOMAIN, "The specified resource pool " "is unknown")); break; default: (void) snprintf(messages[1], sizeof (messages[1]), dgettext(TEXT_DOMAIN, "Failure during pool binding")); syslog(LOG_AUTH | LOG_ERR, "pam_unix_cred: project \"%s\" could not " "bind to resource pool: %m", proj.pj_name); } if (!nowarn) (void) __pam_display_msg(pamh, PAM_ERROR_MSG, 2, messages, NULL); break; default: /* * Resource control assignment failed. Unlike * newtask(1), we treat this as an error. */ if (error < 0) { /* * This isn't supposed to happen, but in * case it does, this error message * doesn't use error as an index, like * the others might. */ syslog(LOG_AUTH | LOG_ERR, "pam_unix_cred: unkwown error joining " "project \"%s\" (%d)", proj.pj_name, error); (void) snprintf(messages[0], sizeof (messages[0]), dgettext(TEXT_DOMAIN, "unkwown error joining project \"%s\"" " (%d)"), proj.pj_name, error); } else if ((kv_array = _str2kva(proj.pj_attr, KV_ASSIGN, KV_DELIMITER)) != NULL) { syslog(LOG_AUTH | LOG_ERR, "pam_unix_cred: %s resource control " "assignment failed for project \"%s\"", kv_array->data[error - 1].key, proj.pj_name); (void) snprintf(messages[0], sizeof (messages[0]), dgettext(TEXT_DOMAIN, "%s resource control assignment failed for " "project \"%s\""), kv_array->data[error - 1].key, proj.pj_name); _kva_free(kv_array); } else { syslog(LOG_AUTH | LOG_ERR, "pam_unix_cred: resource control " "assignment failed for project \"%s\"" "attribute %d", proj.pj_name, error); (void) snprintf(messages[0], sizeof (messages[0]), dgettext(TEXT_DOMAIN, "resource control assignment failed for " "project \"%s\" attribute %d"), proj.pj_name, error); } if (!nowarn) (void) __pam_display_msg(pamh, PAM_ERROR_MSG, 1, messages, NULL); } return (PAM_SYSTEM_ERR); } setprivs: tset = def = lim = NULL; deflim.def = deflim.lim = NULL; (void) _enum_attrs(user, finddeflim, NULL, &deflim); if (getset(deflim.lim, &lim) != 0 || getset(deflim.def, &def) != 0) { ret = PAM_SYSTEM_ERR; goto out; } if (def == NULL) { def = priv_allocset(); if (def == NULL) { ret = PAM_SYSTEM_ERR; goto out; } priv_basicset(def); errno = 0; if ((pathconf("/", _PC_CHOWN_RESTRICTED) == -1) && (errno == 0)) (void) priv_addset(def, PRIV_FILE_CHOWN_SELF); } /* * Silently limit the privileges to those actually available * in the current zone. */ tset = priv_allocset(); if (tset == NULL) { ret = PAM_SYSTEM_ERR; goto out; } if (getppriv(PRIV_PERMITTED, tset) != 0) { ret = PAM_SYSTEM_ERR; goto out; } if (!priv_issubset(def, tset)) priv_intersect(tset, def); /* * We set privilege awareness here so that I gets copied to * P & E when the final setuid(uid) happens. */ (void) setpflags(PRIV_AWARE, 1); if (setppriv(PRIV_SET, PRIV_INHERITABLE, def) != 0) { syslog(LOG_AUTH | LOG_ERR, "pam_setcred: setppriv(defaultpriv) failed: %m"); ret = PAM_CRED_ERR; } if (lim != NULL) { /* * Silently limit the privileges to the limit set available. */ if (getppriv(PRIV_LIMIT, tset) != 0) { ret = PAM_SYSTEM_ERR; goto out; } if (!priv_issubset(lim, tset)) priv_intersect(tset, lim); if (setppriv(PRIV_SET, PRIV_LIMIT, lim) != 0) { syslog(LOG_AUTH | LOG_ERR, "pam_setcred: setppriv(limitpriv) failed: %m"); ret = PAM_CRED_ERR; goto out; } /* * In order not to surprise certain applications, we * need to get rid of privilege awareness and thus we must * set this flag which will cause a reset on set*uid(). */ (void) setpflags(PRIV_AWARE_RESET, 1); } /* * This may fail but we do not care as this will be reset later * when the uids are set to their final values. */ (void) setpflags(PRIV_AWARE, 0); /* * Remove PRIV_PFEXEC; stop running as if we are under a profile * shell. A user with a profile shell will set PRIV_PFEXEC. */ (void) setpflags(PRIV_PFEXEC, 0); out: free(deflim.lim); free(deflim.def); if (lim != NULL) priv_freeset(lim); if (def != NULL) priv_freeset(def); if (tset != NULL) priv_freeset(tset); return (ret); } # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # include ../../Makefile.lib TEXT_DOMAIN= SUNW_OST_SYSOSPAM POFILE= unix_session.po MSGFILES= unix_session.c # Hammerhead: amd64-only SUBDIRS= $(MACH64) all : TARGET= all clean : TARGET= clean clobber : TARGET= clobber install : TARGET= install .KEEP_STATE: all clean clobber install: $(SUBDIRS) _msg: $(MSGDOMAINPOFILE) $(SUBDIRS): FRC @cd $@; pwd; $(MAKE) $(TARGET) FRC: include $(SRC)/Makefile.msg.targ include ../../Makefile.targ # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License, Version 1.0 only # (the "License"). You may not use this file except in compliance # with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2004 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # LIBRARY= pam_unix_session.a VERS= .1 OBJECTS= unix_session.o include ../../Makefile.pam_modules LDLIBS += -lpam -lc # Enable large file support for accessing the lastlog file. CPPFLAGS += -D_FILE_OFFSET_BITS=64 all: $(LIBS) include $(SRC)/lib/Makefile.targ # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License, Version 1.0 only # (the "License"). You may not use this file except in compliance # with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2004 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" # include ../Makefile.com include ../../../Makefile.lib.64 install: all $(ROOTLIBS64) $(ROOTLINKS64) # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. # # # MAPFILE HEADER START # # WARNING: STOP NOW. DO NOT MODIFY THIS FILE. # Object versioning must comply with the rules detailed in # # usr/src/lib/README.mapfiles # # You should not be making modifications here until you've read the most current # copy of that file. If you need help, contact a gatekeeper for guidance. # # MAPFILE HEADER END # $mapfile_version 2 SYMBOL_VERSION SUNW_1.1 { global: pam_sm_close_session; pam_sm_open_session; local: *; }; /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * Copyright 2016 Toomas Soome * Copyright 2023 OmniOS Community Edition (OmniOSce) Association. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define LASTLOG "/var/adm/lastlog" /* * pam_sm_close_session - Terminate a PAM authenticated session */ /*ARGSUSED*/ int pam_sm_close_session(pam_handle_t *pamh, int flags, int argc, const char **argv) { int i; int debug = 0; for (i = 0; i < argc; i++) { if (strcasecmp(argv[i], "debug") == 0) debug = 1; else if (strcasecmp(argv[i], "nowarn") != 0) syslog(LOG_ERR, "illegal option %s", argv[i]); } if (debug) syslog(LOG_DEBUG, "pam_unix_session: inside pam_sm_close_session()"); return (PAM_SUCCESS); } int pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, const char **argv) { int error; const char *ttyn, *rhost, *user; int fdl; struct lastlog newll; struct passwd pwd; char buffer[NSS_BUFLEN_PASSWD]; int i; int debug = 0; offset_t offset; time_t cur_time; for (i = 0; i < argc; i++) { if (strcasecmp(argv[i], "debug") == 0) debug = 1; else if (strcasecmp(argv[i], "nowarn") == 0) flags = flags | PAM_SILENT; else syslog(LOG_ERR, "illegal option %s", argv[i]); } if (debug) syslog(LOG_DEBUG, "pam_unix_session: inside pam_sm_open_session()"); if ((error = pam_get_item(pamh, PAM_TTY, (const void **)&ttyn)) != PAM_SUCCESS || (error = pam_get_item(pamh, PAM_USER, (const void **)&user)) != PAM_SUCCESS || (error = pam_get_item(pamh, PAM_RHOST, (const void **)&rhost)) != PAM_SUCCESS) { return (error); } if (user == NULL || *user == '\0') return (PAM_USER_UNKNOWN); /* report error if ttyn not set */ if (ttyn == NULL) return (PAM_SESSION_ERR); if (getpwnam_r(user, &pwd, buffer, sizeof (buffer)) == NULL) { return (PAM_USER_UNKNOWN); } if ((fdl = open(LASTLOG, O_RDWR|O_CREAT|O_DSYNC, 0444)) >= 0) { /* * The value of lastlog is read by the UNIX * account management module */ offset = (offset_t)pwd.pw_uid * (offset_t)sizeof (struct lastlog); if (llseek(fdl, offset, SEEK_SET) != offset) { syslog(LOG_ERR, "pam_unix_session: Can't update lastlog: uid %d " "too large", pwd.pw_uid); (void) close(fdl); return (PAM_SUCCESS); } /* * use time32_t in case of _LP64 * since it's written in lastlog.h */ (void) time(&cur_time); bzero((char *)&newll, sizeof (struct lastlog)); #ifdef _LP64 newll.ll_time = (time32_t)cur_time; #else newll.ll_time = cur_time; #endif if ((strncmp(ttyn, "/dev/", 5) == 0)) { (void) strlcpy(newll.ll_line, (ttyn + sizeof ("/dev/")-1), sizeof (newll.ll_line)); } else { (void) strlcpy(newll.ll_line, ttyn, sizeof (newll.ll_line)); } if (rhost != NULL) { (void) strlcpy(newll.ll_host, rhost, sizeof (newll.ll_host)); } if (debug) { char buf[26]; (void) ctime_r((const time_t *)&cur_time, buf, sizeof (buf)); buf[24] = '\000'; syslog(LOG_DEBUG, "pam_unix_session: " "user = %s, time = %s, tty = %s, host = %s.", user, buf, newll.ll_line, newll.ll_host); } if (write(fdl, (char *)&newll, sizeof (newll)) != sizeof (newll)) syslog(LOG_ERR, "pam_unix_session: Can't write " "lastlog: uid %d: %m", pwd.pw_uid); if (close(fdl) != 0) syslog(LOG_ERR, "pam_unix_session: Can't close " "lastlog: uid %d: %m", pwd.pw_uid); } return (PAM_SUCCESS); }