static int converse(pam_handle_t *pamh, int ctrl, int nargs , struct pam_message **message , struct pam_response **response) { int retval; struct pam_conv *conv; D(("begin to converse")); retval = pam_get_item( pamh, PAM_CONV, (const void **) &conv ) ; if ( retval == PAM_SUCCESS ) { retval = conv->conv(nargs, ( const struct pam_message ** ) message , response, conv->appdata_ptr); D(("returned from application's conversation function")); if (retval != PAM_SUCCESS && (PAM_DEBUG_ARG & ctrl) ) { _log_err(LOG_DEBUG, "conversation failure [%s]" , pam_strerror(pamh, retval)); } } else { _log_err(LOG_ERR, "couldn't obtain coversation function [%s]" , pam_strerror(pamh, retval)); } D(("ready to return from module conversation")); return retval; /* propagate error status */ }
PAM_EXTERN int pam_sm_close_session(pam_handle_t * pamh, int flags, int argc, const char **argv) { char *user_name, *service; unsigned int ctrl; int retval; D(("called.")); ctrl = _set_ctrl(pamh, flags, NULL, argc, argv); retval = pam_get_item(pamh, PAM_USER, (void *) &user_name); if (user_name == NULL || retval != PAM_SUCCESS) { _log_err(LOG_CRIT, pamh, "close_session - error recovering username"); return PAM_SESSION_ERR; /* How did we get authenticated with no username?! */ } retval = pam_get_item(pamh, PAM_SERVICE, (void *) &service); if (service == NULL || retval != PAM_SUCCESS) { _log_err(LOG_CRIT, pamh, "close_session - error recovering service"); return PAM_SESSION_ERR; } _log_err(LOG_INFO, pamh, "session closed for user %s" ,user_name); return PAM_SUCCESS; }
static int parse_args(struct login_info *loginfo, int argc, const char **argv) { int i; for (i=0; i<argc; ++i) { if (!strncmp("fieldsep=", argv[i], 9)) { /* the admin wants to override the default field separators */ fs = argv[i]+9; } else if (!strncmp("accessfile=", argv[i], 11)) { FILE *fp = fopen(11 + argv[i], "r"); if (fp) { loginfo->config_file = 11 + argv[i]; fclose(fp); } else { _log_err("for service [%s] failed to open accessfile=[%s]" , loginfo->service, 11 + argv[i]); return 0; } } else { _log_err("unrecognized option [%s]", argv[i]); } } return 1; /* OK */ }
static char *getNISserver(pam_handle_t *pamh) { char *master; char *domainname; int port, err; if ((err = yp_get_default_domain(&domainname)) != 0) { _log_err(LOG_WARNING, pamh, "can't get local yp domain: %s\n", yperr_string(err)); return NULL; } if ((err = yp_master(domainname, "passwd.byname", &master)) != 0) { _log_err(LOG_WARNING, pamh, "can't find the master ypserver: %s\n", yperr_string(err)); return NULL; } port = getrpcport(master, YPPASSWDPROG, YPPASSWDPROC_UPDATE, IPPROTO_UDP); if (port == 0) { _log_err(LOG_WARNING, pamh, "yppasswdd not running on NIS master host\n"); return NULL; } if (port >= IPPORT_RESERVED) { _log_err(LOG_WARNING, pamh, "yppasswd daemon running on illegal port.\n"); return NULL; } return master; }
static _ctx * _profile_thread(PyThreadState *ts) { uintptr_t ctx_id; _ctx *ctx; _hitem *it; ctx_id = _current_context_id(ts); it = hfind(contexts, ctx_id); if (!it) { ctx = _create_ctx(); if (!ctx) { return NULL; } if (!hadd(contexts, ctx_id, (uintptr_t)ctx)) { _del_ctx(ctx); if (!flput(flctx, ctx)) { _log_err(10); } _log_err(11); return NULL; } } else { ctx = (_ctx *)it->val; } ts->use_tracing = 1; ts->c_profilefunc = _yapp_callback; ctx->id = ctx_id; ctx->tid = ts->thread_id; return ctx; }
static int _pam_parse(int flags, int argc, const char **argv, char **maildir, int *hashcount) { int ctrl=0; if (flags & PAM_SILENT) { ctrl |= PAM_MAIL_SILENT; } *hashcount = 0; /* step through arguments */ for (; argc-- > 0; ++argv) { /* generic options */ if (!strcmp(*argv,"debug")) ctrl |= PAM_DEBUG_ARG; else if (!strcmp(*argv,"quiet")) ctrl |= PAM_QUIET_MAIL; else if (!strcmp(*argv,"standard")) ctrl |= PAM_STANDARD_MAIL | PAM_EMPTY_TOO; else if (!strncmp(*argv,"dir=",4)) { *maildir = x_strdup(4+*argv); if (*maildir != NULL) { D(("new mail directory: %s", *maildir)); ctrl |= PAM_NEW_MAIL_DIR; } else { _log_err(LOG_CRIT, "failed to duplicate mail directory - ignored"); } } else if (!strncmp(*argv,"hash=",5)) { char *ep = NULL; *hashcount = strtol(*argv+5,&ep,10); if (!ep || (*hashcount < 0)) { *hashcount = 0; } } else if (!strcmp(*argv,"close")) { ctrl |= PAM_LOGOUT_TOO; } else if (!strcmp(*argv,"nopen")) { ctrl |= PAM_NO_LOGIN; } else if (!strcmp(*argv,"noenv")) { ctrl |= PAM_NO_ENV; } else if (!strcmp(*argv,"empty")) { ctrl |= PAM_EMPTY_TOO; } else { _log_err(LOG_ERR,"pam_parse: unknown option; %s",*argv); } } if ((*hashcount != 0) && !(ctrl & PAM_NEW_MAIL_DIR)) { *maildir = x_strdup(DEFAULT_MAIL_DIRECTORY); ctrl |= PAM_NEW_MAIL_DIR; } return ctrl; }
static int login_access(struct login_info *item) { FILE *fp; char line[BUFSIZ]; char *perm; /* becomes permission field */ char *users; /* becomes list of login names */ char *froms; /* becomes list of terminals or hosts */ int match = NO; int end; int lineno = 0; /* for diagnostics */ /* * Process the table one line at a time and stop at the first match. * Blank lines and lines that begin with a '#' character are ignored. * Non-comment lines are broken at the ':' character. All fields are * mandatory. The first field should be a "+" or "-" character. A * non-existing table means no access control. */ if ((fp = fopen(item->config_file, "r"))!=NULL) { while (!match && fgets(line, sizeof(line), fp)) { lineno++; if (line[end = strlen(line) - 1] != '\n') { _log_err("%s: line %d: missing newline or line too long", item->config_file, lineno); continue; } if (line[0] == '#') continue; /* comment line */ while (end > 0 && isspace(line[end - 1])) end--; line[end] = 0; /* strip trailing whitespace */ if (line[0] == 0) /* skip blank lines */ continue; if (!(perm = strtok(line, fs)) || !(users = strtok((char *) 0, fs)) || !(froms = strtok((char *) 0, fs)) || strtok((char *) 0, fs)) { _log_err("%s: line %d: bad field count", item->config_file, lineno); continue; } if (perm[0] != '+' && perm[0] != '-') { _log_err("%s: line %d: bad first field", item->config_file, lineno); continue; } match = (list_match(froms, item, from_match) && list_match(users, item, user_match)); } (void) fclose(fp); } else if (errno != ENOENT) { _log_err("cannot open %s: %m", item->config_file); } return (match == 0 || (line[0] == '+')); }
static int _pam_unix_approve_pass(pam_handle_t * pamh ,unsigned int ctrl ,const char *pass_old ,const char *pass_new) { const char *user; const char *remark = NULL; int retval = PAM_SUCCESS; D(("&new=%p, &old=%p", pass_old, pass_new)); D(("new=[%s]", pass_new)); D(("old=[%s]", pass_old)); if (pass_new == NULL || (pass_old && !strcmp(pass_old, pass_new))) { if (on(UNIX_DEBUG, ctrl)) { _log_err(LOG_DEBUG, pamh, "bad authentication token"); } _make_remark(pamh, ctrl, PAM_ERROR_MSG, pass_new == NULL ? "No password supplied" : "Password unchanged"); return PAM_AUTHTOK_ERR; } /* * if one wanted to hardwire authentication token strength * checking this would be the place - AGM */ retval = pam_get_item(pamh, PAM_USER, (const void **) &user); if (retval != PAM_SUCCESS) { if (on(UNIX_DEBUG, ctrl)) { _log_err(LOG_ERR, pamh, "Can not get username"); return PAM_AUTHTOK_ERR; } } if (off(UNIX__IAMROOT, ctrl)) { #ifdef USE_CRACKLIB remark = FascistCheck(pass_new, CRACKLIB_DICTS); D(("called cracklib [%s]", remark)); #else if (strlen(pass_new) < 6) remark = "You must choose a longer password"; D(("lenth check [%s]", remark)); #endif if (on(UNIX_REMEMBER_PASSWD, ctrl)) if ((retval = check_old_password(user, pass_new)) != PAM_SUCCESS) remark = "Password has been already used. Choose another."; } if (remark) { _make_remark(pamh, ctrl, PAM_ERROR_MSG, remark); retval = PAM_AUTHTOK_ERR; } return retval; }
PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t *pamh,int flags,int argc ,const char **argv) { const char *service=NULL, *tty=NULL; const char *user=NULL; /* set service name */ if (pam_get_item(pamh, PAM_SERVICE, (const void **)&service) != PAM_SUCCESS || service == NULL) { _log_err("cannot find the current service name"); return PAM_ABORT; } /* set username */ if (pam_get_user(pamh, &user, NULL) != PAM_SUCCESS || user == NULL || *user == '\0') { _log_err("cannot determine the user's name"); return PAM_USER_UNKNOWN; } /* set tty name */ if (pam_get_item(pamh, PAM_TTY, (const void **)&tty) != PAM_SUCCESS || tty == NULL) { D(("PAM_TTY not set, probing stdin")); tty = ttyname(STDIN_FILENO); if (tty == NULL) { _log_err("couldn't get the tty name"); return PAM_ABORT; } if (pam_set_item(pamh, PAM_TTY, tty) != PAM_SUCCESS) { _log_err("couldn't set tty name"); return PAM_ABORT; } } if (strncmp("/dev/",tty,5) == 0) { /* strip leading /dev/ */ tty += 5; } /* good, now we have the service name, the user and the terminal name */ D(("service=%s", service)); D(("user=%s", user)); D(("tty=%s", tty)); return check_account(service,tty,user); }
static void su_sighandler(int sig) { if (sig > 0) { _log_err(LOG_NOTICE, "caught signal %d.", sig); exit(sig); } }
static int _pam_parse(int flags, int argc, const char **argv) { int ctrl = 0; /* does the appliction require quiet? */ if ((flags & PAM_SILENT) == PAM_SILENT) ctrl |= MKHOMEDIR_QUIET; /* step through arguments */ for (; argc-- > 0; ++argv) { if (!strcmp(*argv, "silent")) { ctrl |= MKHOMEDIR_QUIET; } else if (!strncmp(*argv,"umask=",6)) { UMask = strtol(*argv+6,0,0); } else if (!strncmp(*argv,"skel=",5)) { strncpy(SkelDir,*argv+5,sizeof(SkelDir)); SkelDir[sizeof(SkelDir)-1] = '\0'; } else { _log_err(LOG_ERR, "unknown option; %s", *argv); } } D(("ctrl = %o", ctrl)); return ctrl; }
PAM_EXTERN int pam_sm_open_session(pam_handle_t * pamh, int flags, int argc ,const char **argv) { int retval, ctrl; const char *user; const struct passwd *pwd; struct stat St; /* Parse the flag values */ ctrl = _pam_parse(flags, argc, argv); /* Determine the user name so we can get the home directory */ retval = pam_get_item(pamh, PAM_USER, (const void **) &user); if (retval != PAM_SUCCESS || user == NULL || *user == '\0') { _log_err(LOG_NOTICE, "user unknown"); return PAM_USER_UNKNOWN; } /* Get the password entry */ pwd = getpwnam(user); if (pwd == NULL) { D(("couldn't identify user %s", user)); return PAM_CRED_INSUFFICIENT; } /* Stat the home directory, if something exists then we assume it is correct and return a success*/ if (stat(pwd->pw_dir,&St) == 0) return PAM_SUCCESS; return create_homedir(pamh,ctrl,pwd,SkelDir,pwd->pw_dir); }
static boolean logic_field(const void *me, const char *x, int rule, boolean (*agrees)(const void *, const char * , int, int)) { boolean left=FALSE, right, not=FALSE; operator oper=OR; int at=0, l; expect next=VAL; while ((l = logic_member(x,&at))) { int c = x[at]; if (next == VAL) { if (c == '!') not = !not; else if (isalpha(c) || c == '*') { right = not ^ agrees(me, x+at, l, rule); if (oper == AND) left &= right; else left |= right; next = OP; } else { _log_err("garbled syntax; expected name (rule #%d)", rule); return FALSE; } } else { /* OP */ switch (c) { case '&': oper = AND; break; case '|': oper = OR; break; default: _log_err("garbled syntax; expected & or | (rule #%d)" , rule); D(("%c at %d",c,at)); return FALSE; } next = VAL; } at += l; } return left; }
static void _call_enter(PyObject *self, PyFrameObject *frame, PyObject *arg, int ccall) { _pit *cp,*pp; _cstackitem *ci; _pit_children_info *pci; if (ccall) { cp = _ccode2pit((PyCFunctionObject *)arg); } else { cp = _code2pit(frame); } // something went wrong. No mem, or another error. we cannot find // a corresponding pit. just run away:) if (!cp) { _log_err(4); return; } // create/update children info if we have a valid parent pp = _get_frame(); if (pp) { pci = _get_child_info(pp, cp); if(!pci) { pci = _add_child_info(pp, cp); } pci->callcount++; incr_rec_level((uintptr_t)pci); } ci = _push_frame(cp); if (!ci) { // runaway! (defensive) _log_err(5); return; } ci->t0 = tickcount(); cp->callcount++; incr_rec_level((uintptr_t)cp); }
/* Helper function for adding a user to the db. */ static int _smb_add_user(pam_handle_t *pamh, unsigned int ctrl, const char *name, struct samu *sampass, bool exist) { char *err_str = NULL; char *msg_str = NULL; const char *pass = NULL; int retval; TALLOC_CTX *frame = talloc_stackframe(); /* Get the authtok; if we don't have one, silently fail. */ retval = _pam_get_item( pamh, PAM_AUTHTOK, &pass ); if (retval != PAM_SUCCESS) { _log_err(pamh, LOG_ALERT , "pam_get_item returned error to pam_sm_authenticate" ); TALLOC_FREE(frame); return PAM_AUTHTOK_RECOVER_ERR; } /* Add the user to the db if they aren't already there. */ if (!exist) { retval = NT_STATUS_IS_OK(local_password_change(name, LOCAL_ADD_USER|LOCAL_SET_PASSWORD, pass, &err_str, &msg_str)); if (!retval && err_str) { make_remark(pamh, ctrl, PAM_ERROR_MSG, err_str ); } else if (msg_str) { make_remark(pamh, ctrl, PAM_TEXT_INFO, msg_str ); } pass = NULL; SAFE_FREE(err_str); SAFE_FREE(msg_str); TALLOC_FREE(frame); return PAM_IGNORE; } else { /* mimick 'update encrypted' as long as the 'no pw req' flag is not set */ if ( pdb_get_acct_ctrl(sampass) & ~ACB_PWNOTREQ ) { retval = NT_STATUS_IS_OK(local_password_change(name, LOCAL_SET_PASSWORD, pass, &err_str, &msg_str)); if (!retval && err_str) { make_remark(pamh, ctrl, PAM_ERROR_MSG, err_str ); } else if (msg_str) { make_remark(pamh, ctrl, PAM_TEXT_INFO, msg_str ); } } } SAFE_FREE(err_str); SAFE_FREE(msg_str); pass = NULL; TALLOC_FREE(frame); return PAM_IGNORE; }
static long get_rec_level(uintptr_t key) { _hitem *it; it = hfind(current_ctx->rec_levels, key); if (!it) { _log_err(1); return -1; // should not happen } return it->val; }
static int _authenticate(const char *service, const char *user) { struct pam_conv conv = { _converse, NULL }; pam_handle_t *pamh; int err; err = pam_start(service, user, &conv, &pamh); if (err != PAM_SUCCESS) { _log_err(LOG_ERR, "pam_start(%s, %s) failed (errno %d)", service, user, err); return UNIX_FAILED; } err = pam_authenticate(pamh, 0); if (err != PAM_SUCCESS) _log_err(LOG_ERR, "pam_authenticate(%s, %s): %s", service, user, pam_strerror(pamh, err)); if (err == PAM_SUCCESS) { int err2 = pam_setcred(pamh, PAM_REFRESH_CRED); if (err2 != PAM_SUCCESS) _log_err(LOG_ERR, "pam_setcred(%s, %s): %s", service, user, pam_strerror(pamh, err2)); /* * ignore errors on refresh credentials. * If this did not work we use the old once. */ } pam_end(pamh, err); if (err != PAM_SUCCESS) return UNIX_FAILED; return UNIX_PASSED; }
static int netgroup_match(char *group, char *machine, char *user) { #ifdef NIS static char *mydomain = 0; if (mydomain == 0) yp_get_default_domain(&mydomain); return (innetgr(group, machine, user, mydomain)); #else _log_err("NIS netgroup support not configured"); return (NO); #endif }
static int incr_rec_level(uintptr_t key) { _hitem *it; it = hfind(current_ctx->rec_levels, key); if (it) { it->val++; } else { if (!hadd(current_ctx->rec_levels, key, 1)) { _log_err(2); return 0; // should not happen } } return 1; }
static int decr_rec_level(uintptr_t key) { _hitem *it; uintptr_t v; it = hfind(current_ctx->rec_levels, key); if (it) { v = it->val--; /*supress warning -- it is safe to cast long vs pointers*/ if (v == 0) { hfree(current_ctx->rec_levels, it); } } else { _log_err(3); return 0; // should not happen } return 1; }
static int _converse(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr) { struct pam_response *reply; int num; if (!(reply = malloc(sizeof(*reply) * num_msg))) return PAM_CONV_ERR; for (num = 0; num < num_msg; num++) { reply[num].resp_retcode = PAM_SUCCESS; reply[num].resp = NULL; switch (msg[num]->msg_style) { case PAM_PROMPT_ECHO_ON: return PAM_CONV_ERR; case PAM_PROMPT_ECHO_OFF: /* read the password from stdin */ if (npass < 0) { npass = read(STDIN_FILENO, pass, sizeof(pass)-1); if (npass < 0) { _log_err(LOG_DEBUG, "error reading password"); return UNIX_FAILED; } pass[npass] = '\0'; } reply[num].resp = strdup(pass); break; case PAM_TEXT_INFO: case PAM_ERROR_MSG: /* ignored */ break; default: /* Must be an error of some sort... */ return PAM_CONV_ERR; } } *resp = reply; return PAM_SUCCESS; }
static int _do_mail(pam_handle_t *pamh, int flags, int argc, const char **argv, int est) { int retval, ctrl, hashcount; char *path_mail=NULL, *folder; const char *type; /* * this module (un)sets the MAIL environment variable, and checks if * the user has any new mail. */ ctrl = _pam_parse(flags, argc, argv, &path_mail, &hashcount); /* Do we have anything to do? */ if (flags & PAM_SILENT) return PAM_SUCCESS; /* which folder? */ retval = get_folder(pamh, ctrl, &path_mail, &folder, hashcount); if (retval != PAM_SUCCESS) { D(("failed to find folder")); return retval; } /* set the MAIL variable? */ if (!(ctrl & PAM_NO_ENV) && est) { char *tmp; tmp = malloc(strlen(folder)+sizeof(MAIL_ENV_FORMAT)); if (tmp != NULL) { sprintf(tmp, MAIL_ENV_FORMAT, folder); D(("setting env: %s", tmp)); retval = pam_putenv(pamh, tmp); _pam_overwrite(tmp); _pam_drop(tmp); if (retval != PAM_SUCCESS) { _pam_overwrite(folder); _pam_drop(folder); _log_err(LOG_CRIT, "unable to set " MAIL_ENV_NAME " variable"); return retval; } } else { _log_err(LOG_CRIT, "no memory for " MAIL_ENV_NAME " variable"); _pam_overwrite(folder); _pam_drop(folder); return retval; } } else { D(("not setting " MAIL_ENV_NAME " variable")); } /* * OK. we've got the mail folder... what about its status? */ if ((est && !(ctrl & PAM_NO_LOGIN)) || (!est && (ctrl & PAM_LOGOUT_TOO))) { type = get_mail_status(ctrl, folder); if (type != NULL) { retval = report_mail(pamh, ctrl, type, folder); type = NULL; } } /* Delete environment variable? */ if (!est) (void) pam_putenv(pamh, MAIL_ENV_NAME); _pam_overwrite(folder); /* clean up */ _pam_drop(folder); /* indicate success or failure */ return retval; }
static int get_folder(pam_handle_t *pamh, int ctrl, char **path_mail, char **folder_p, int hashcount) { int retval; const char *user, *path; char *folder; const struct passwd *pwd=NULL; retval = pam_get_user(pamh, &user, NULL); if (retval != PAM_SUCCESS || user == NULL) { _log_err(LOG_ERR, "no user specified"); return PAM_USER_UNKNOWN; } if (ctrl & PAM_NEW_MAIL_DIR) { path = *path_mail; if (*path == '~') { /* support for $HOME delivery */ pwd = getpwnam(user); if (pwd == NULL) { _log_err(LOG_ERR, "user [%s] unknown", user); _pam_overwrite(*path_mail); _pam_drop(*path_mail); return PAM_USER_UNKNOWN; } /* * "~/xxx" and "~xxx" are treated as same */ if (!*++path || (*path == '/' && !*++path)) { _log_err(LOG_ALERT, "badly formed mail path [%s]", *path_mail); _pam_overwrite(*path_mail); _pam_drop(*path_mail); return PAM_ABORT; } ctrl |= PAM_HOME_MAIL; if (hashcount != 0) { _log_err(LOG_ALERT, "can't do hash= and home directory mail"); } } } else { path = DEFAULT_MAIL_DIRECTORY; } /* put folder together */ if (ctrl & PAM_HOME_MAIL) { folder = malloc(sizeof(MAIL_FILE_FORMAT) +strlen(pwd->pw_dir)+strlen(path)); } else { folder = malloc(sizeof(MAIL_FILE_FORMAT)+strlen(path)+strlen(user) +2*hashcount); } if (folder != NULL) { if (ctrl & PAM_HOME_MAIL) { sprintf(folder, MAIL_FILE_FORMAT, pwd->pw_dir, "", path); } else { int i; char *hash = malloc(2*hashcount+1); if (hash) { for (i = 0; i < hashcount; i++) { hash[2*i] = '/'; hash[2*i+1] = user[i]; } hash[2*i] = '\0'; sprintf(folder, MAIL_FILE_FORMAT, path, hash, user); _pam_overwrite(hash); _pam_drop(hash); } else { sprintf(folder, "error"); } } D(("folder =[%s]", folder)); } /* tidy up */ _pam_overwrite(*path_mail); _pam_drop(*path_mail); user = NULL; if (folder == NULL) { _log_err(LOG_CRIT, "out of memory for mail folder"); return PAM_BUF_ERR; } *folder_p = folder; folder = NULL; return PAM_SUCCESS; }
static int read_field(int fd, char **buf, int *from, int *to) { /* is buf set ? */ if (! *buf) { *buf = (char *) malloc(PAM_TIME_BUFLEN); if (! *buf) { _log_err("out of memory"); D(("no memory")); return -1; } *from = *to = 0; fd = open(PAM_TIME_CONF, O_RDONLY); } /* do we have a file open ? return error */ if (fd < 0 && *to <= 0) { _log_err( PAM_TIME_CONF " not opened"); memset(*buf, 0, PAM_TIME_BUFLEN); _pam_drop(*buf); return -1; } /* check if there was a newline last time */ if ((*to > *from) && (*to > 0) && ((*buf)[*from] == '\0')) { /* previous line ended */ (*from)++; (*buf)[0] = '\0'; return fd; } /* ready for more data: first shift the buffer's remaining data */ *to -= *from; shift_bytes(*buf, *from, *to); *from = 0; (*buf)[*to] = '\0'; while (fd >= 0 && *to < PAM_TIME_BUFLEN) { int i; /* now try to fill the remainder of the buffer */ i = read(fd, *to + *buf, PAM_TIME_BUFLEN - *to); if (i < 0) { _log_err("error reading " PAM_TIME_CONF); return -1; } else if (!i) { close(fd); fd = -1; /* end of file reached */ } else *to += i; /* * contract the buffer. Delete any comments, and replace all * multiple spaces with single commas */ i = 0; #ifdef DEBUG_DUMP D(("buffer=<%s>",*buf)); #endif while (i < *to) { if ((*buf)[i] == ',') { int j; for (j=++i; j<*to && (*buf)[j] == ','; ++j); if (j!=i) { shift_bytes(i + (*buf), j-i, (*to) - j); *to -= j-i; } } switch ((*buf)[i]) { int j,c; case '#': for (j=i; j < *to && (c = (*buf)[j]) != '\n'; ++j); if (j >= *to) { (*buf)[*to = ++i] = '\0'; } else if (c == '\n') { shift_bytes(i + (*buf), j-i, (*to) - j); *to -= j-i; ++i; } else { _log_err("internal error in " __FILE__ " at line %d", __LINE__ ); return -1; } break; case '\\': if ((*buf)[i+1] == '\n') { shift_bytes(i + *buf, 2, *to - (i+2)); *to -= 2; } else { ++i; /* we don't escape non-newline characters */ } break; case '!': case ' ': case '\t': if ((*buf)[i] != '!') (*buf)[i] = ','; /* delete any trailing spaces */ for (j=++i; j < *to && ( (c = (*buf)[j]) == ' ' || c == '\t' ); ++j); shift_bytes(i + *buf, j-i, (*to)-j ); *to -= j-i; break; default: ++i; } } } (*buf)[*to] = '\0'; /* now return the next field (set the from/to markers) */ { int i; for (i=0; i<*to; ++i) { switch ((*buf)[i]) { case '#': case '\n': /* end of the line/file */ (*buf)[i] = '\0'; *from = i; return fd; case FIELD_SEPARATOR: /* end of the field */ (*buf)[i] = '\0'; *from = ++i; return fd; } } *from = i; (*buf)[*from] = '\0'; } if (*to <= 0) { D(("[end of text]")); *buf = NULL; } return fd; }
static int check_account(const char *service , const char *tty, const char *user) { int from=0,to=0,fd=-1; char *buffer=NULL; int count=0; TIME here_and_now; int retval=PAM_SUCCESS; here_and_now = time_now(); /* find current time */ do { boolean good=TRUE,intime; /* here we get the service name field */ fd = read_field(fd,&buffer,&from,&to); if (!buffer || !buffer[0]) { /* empty line .. ? */ continue; } ++count; good = logic_field(service, buffer, count, is_same); D(("with service: %s", good ? "passes":"fails" )); /* here we get the terminal name field */ fd = read_field(fd,&buffer,&from,&to); if (!buffer || !buffer[0]) { _log_err(PAM_TIME_CONF "; no tty entry #%d", count); continue; } good &= logic_field(tty, buffer, count, is_same); D(("with tty: %s", good ? "passes":"fails" )); /* here we get the username field */ fd = read_field(fd,&buffer,&from,&to); if (!buffer || !buffer[0]) { _log_err(PAM_TIME_CONF "; no user entry #%d", count); continue; } good &= logic_field(user, buffer, count, is_same); D(("with user: %s", good ? "passes":"fails" )); /* here we get the time field */ fd = read_field(fd,&buffer,&from,&to); if (!buffer || !buffer[0]) { _log_err(PAM_TIME_CONF "; no time entry #%d", count); continue; } intime = logic_field(&here_and_now, buffer, count, check_time); D(("with time: %s", intime ? "passes":"fails" )); fd = read_field(fd,&buffer,&from,&to); if (buffer && buffer[0]) { _log_err(PAM_TIME_CONF "; poorly terminated rule #%d", count); continue; } if (good && !intime) { /* * for security parse whole file.. also need to ensure * that the buffer is free()'d and the file is closed. */ retval = PAM_PERM_DENIED; } else { D(("rule passed")); } } while (buffer); return retval; }
/* take the current date and see if the range "date" passes it */ static boolean check_time(const void *AT, const char *times, int len, int rule) { boolean not,pass; int marked_day, time_start, time_end; const TIME *at; int i,j=0; at = AT; D(("chcking: 0%o/%.4d vs. %s", at->day, at->minute, times)); if (times == NULL) { /* this should not happen */ _log_err("internal error: " __FILE__ " line %d", __LINE__); return FALSE; } if (times[j] == '!') { ++j; not = TRUE; } else { not = FALSE; } for (marked_day = 0; len > 0 && isalpha(times[j]); --len) { int this_day=-1; D(("%c%c ?", times[j], times[j+1])); for (i=0; days[i].d != NULL; ++i) { if (tolower(times[j]) == days[i].d[0] && tolower(times[j+1]) == days[i].d[1] ) { this_day = days[i].bit; break; } } j += 2; if (this_day == -1) { _log_err("bad day specified (rule #%d)", rule); return FALSE; } marked_day ^= this_day; } if (marked_day == 0) { _log_err("no day specified"); return FALSE; } D(("day range = 0%o", marked_day)); time_start = 0; for (i=0; len > 0 && i < 4 && isdigit(times[i+j]); ++i, --len) { time_start *= 10; time_start += times[i+j]-'0'; /* is this portable? */ } j += i; if (times[j] == '-') { time_end = 0; for (i=1; len > 0 && i < 5 && isdigit(times[i+j]); ++i, --len) { time_end *= 10; time_end += times[i+j]-'0'; /* is this portable */ } j += i; } else time_end = -1; D(("i=%d, time_end=%d, times[j]='%c'", i, time_end, times[j])); if (i != 5 || time_end == -1) { _log_err("no/bad times specified (rule #%d)", rule); return TRUE; } D(("times(%d to %d)", time_start,time_end)); D(("marked_day = 0%o", marked_day)); /* compare with the actual time now */ pass = FALSE; if (time_start < time_end) { /* start < end ? --> same day */ if ((at->day & marked_day) && (at->minute >= time_start) && (at->minute < time_end)) { D(("time is listed")); pass = TRUE; } } else { /* spans two days */ if ((at->day & marked_day) && (at->minute >= time_start)) { D(("caught on first day")); pass = TRUE; } else { marked_day <<= 1; marked_day |= (marked_day & 0200) ? 1:0; D(("next day = 0%o", marked_day)); if ((at->day & marked_day) && (at->minute <= time_end)) { D(("caught on second day")); pass = TRUE; } } } return (not ^ pass); }
PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags, int argc, const char **argv) { unsigned int ctrl, lctrl; int retval, i; int remember = -1; /* <DO NOT free() THESE> */ const char *user; char *pass_old, *pass_new; /* </DO NOT free() THESE> */ D(("called.")); #ifdef USE_LCKPWDF /* our current locking system requires that we lock the entire password database. This avoids both livelock and deadlock. */ /* These values for the number of attempts and the sleep time are, of course, completely arbitrary. My reading of the PAM docs is that, once pam_chauthtok() has been called with PAM_UPDATE_AUTHTOK, we are obliged to take any reasonable steps to make sure the token is updated; so retrying for 1/10 sec. isn't overdoing it. The other possibility is to call lckpwdf() on the first pam_chauthtok() pass, and hold the lock until released in the second pass--but is this guaranteed to work? -SRL */ i=0; while((retval = lckpwdf()) != 0 && i < 100) { usleep(1000); } if(retval != 0) { return PAM_AUTHTOK_LOCK_BUSY; } #endif ctrl = _set_ctrl(pamh, flags, &remember, argc, argv); /* * First get the name of a user */ retval = pam_get_user(pamh, &user, "Username: "******"bad username [%s]", user); #ifdef USE_LCKPWDF ulckpwdf(); #endif return PAM_USER_UNKNOWN; } if (retval == PAM_SUCCESS && on(UNIX_DEBUG, ctrl)) _log_err(LOG_DEBUG, pamh, "username [%s] obtained", user); } else { if (on(UNIX_DEBUG, ctrl)) _log_err(LOG_DEBUG, pamh, "password - could not identify user"); #ifdef USE_LCKPWDF ulckpwdf(); #endif return retval; } D(("Got username of %s", user)); /* * This is not an AUTH module! */ if (on(UNIX__NONULL, ctrl)) set(UNIX__NULLOK, ctrl); if (on(UNIX__PRELIM, ctrl)) { /* * obtain and verify the current password (OLDAUTHTOK) for * the user. */ char *Announce; D(("prelim check")); if (_unix_blankpasswd(ctrl, user)) { #ifdef USE_LCKPWDF ulckpwdf(); #endif return PAM_SUCCESS; } else if (off(UNIX__IAMROOT, ctrl)) { /* instruct user what is happening */ #define greeting "Changing password for " Announce = (char *) malloc(sizeof(greeting) + strlen(user)); if (Announce == NULL) { _log_err(LOG_CRIT, pamh, "password - out of memory"); #ifdef USE_LCKPWDF ulckpwdf(); #endif return PAM_BUF_ERR; } (void) strcpy(Announce, greeting); (void) strcpy(Announce + sizeof(greeting) - 1, user); #undef greeting lctrl = ctrl; set(UNIX__OLD_PASSWD, lctrl); retval = _unix_read_password(pamh, lctrl ,Announce ,"(current) UNIX password: "******"password - (old) token not obtained"); #ifdef USE_LCKPWDF ulckpwdf(); #endif return retval; } /* verify that this is the password for this user */ retval = _unix_verify_password(pamh, user, pass_old, ctrl); } else { D(("process run by root so do nothing this time around")); pass_old = NULL; retval = PAM_SUCCESS; /* root doesn't have too */ } if (retval != PAM_SUCCESS) { D(("Authentication failed")); pass_old = NULL; #ifdef USE_LCKPWDF ulckpwdf(); #endif return retval; } retval = pam_set_item(pamh, PAM_OLDAUTHTOK, (const void *) pass_old); pass_old = NULL; if (retval != PAM_SUCCESS) { _log_err(LOG_CRIT, pamh, "failed to set PAM_OLDAUTHTOK"); } retval = _unix_verify_shadow(user, ctrl); if (retval == PAM_AUTHTOK_ERR) { if (off(UNIX__IAMROOT, ctrl)) _make_remark(pamh, ctrl, PAM_ERROR_MSG, "You must wait longer to change your password"); else retval = PAM_SUCCESS; } } else if (on(UNIX__UPDATE, ctrl)) { /* * tpass is used below to store the _pam_md() return; it * should be _pam_delete()'d. */ char *tpass = NULL; int retry = 0; /* * obtain the proposed password */ D(("do update")); /* * get the old token back. NULL was ok only if root [at this * point we assume that this has already been enforced on a * previous call to this function]. */ if (off(UNIX_NOT_SET_PASS, ctrl)) { retval = pam_get_item(pamh, PAM_OLDAUTHTOK ,(const void **) &pass_old); } else { retval = pam_get_data(pamh, _UNIX_OLD_AUTHTOK ,(const void **) &pass_old); if (retval == PAM_NO_MODULE_DATA) { retval = PAM_SUCCESS; pass_old = NULL; } } D(("pass_old [%s]", pass_old)); if (retval != PAM_SUCCESS) { _log_err(LOG_NOTICE, pamh, "user not authenticated"); #ifdef USE_LCKPWDF ulckpwdf(); #endif return retval; } retval = _unix_verify_shadow(user, ctrl); if (retval != PAM_SUCCESS) { _log_err(LOG_NOTICE, pamh, "user not authenticated 2"); #ifdef USE_LCKPWDF ulckpwdf(); #endif return retval; } D(("get new password now")); lctrl = ctrl; if (on(UNIX_USE_AUTHTOK, lctrl)) { set(UNIX_USE_FIRST_PASS, lctrl); } retry = 0; retval = PAM_AUTHTOK_ERR; while ((retval != PAM_SUCCESS) && (retry++ < MAX_PASSWD_TRIES)) { /* * use_authtok is to force the use of a previously entered * password -- needed for pluggable password strength checking */ retval = _unix_read_password(pamh, lctrl ,NULL ,"Enter new UNIX password: "******"Retype new UNIX password: "******"password - new password not obtained"); } pass_old = NULL; /* tidy up */ #ifdef USE_LCKPWDF ulckpwdf(); #endif return retval; } D(("returned to _unix_chauthtok")); /* * At this point we know who the user is and what they * propose as their new password. Verify that the new * password is acceptable. */ if (pass_new[0] == '\0') { /* "\0" password = NULL */ pass_new = NULL; } retval = _pam_unix_approve_pass(pamh, ctrl, pass_old, pass_new); } if (retval != PAM_SUCCESS) { _log_err(LOG_NOTICE, pamh, "new password not acceptable"); _pam_overwrite(pass_new); _pam_overwrite(pass_old); pass_new = pass_old = NULL; /* tidy up */ #ifdef USE_LCKPWDF ulckpwdf(); #endif return retval; } /* * By reaching here we have approved the passwords and must now * rebuild the password database file. */ /* * First we encrypt the new password. */ if (on(UNIX_MD5_PASS, ctrl)) { tpass = crypt_md5_wrapper(pass_new); } else { /* * Salt manipulation is stolen from Rick Faith's passwd * program. Sorry Rick :) -- alex */ time_t tm; char salt[3]; time(&tm); salt[0] = bin_to_ascii(tm & 0x3f); salt[1] = bin_to_ascii((tm >> 6) & 0x3f); salt[2] = '\0'; if (off(UNIX_BIGCRYPT, ctrl) && strlen(pass_new) > 8) { /* * to avoid using the _extensions_ of the bigcrypt() * function we truncate the newly entered password */ char *temp = malloc(9); char *e; if (temp == NULL) { _log_err(LOG_CRIT, pamh, "out of memory for password"); _pam_overwrite(pass_new); _pam_overwrite(pass_old); pass_new = pass_old = NULL; /* tidy up */ #ifdef USE_LCKPWDF ulckpwdf(); #endif return PAM_BUF_ERR; } /* copy first 8 bytes of password */ strncpy(temp, pass_new, 8); temp[8] = '\0'; /* no longer need cleartext */ e = bigcrypt(temp, salt); tpass = x_strdup(e); _pam_overwrite(e); _pam_delete(temp); /* tidy up */ } else { char *e; /* no longer need cleartext */ e = bigcrypt(pass_new, salt); tpass = x_strdup(e); _pam_overwrite(e); } } D(("password processed")); /* update the password database(s) -- race conditions..? */ retval = _do_setpass(pamh, user, pass_old, tpass, ctrl, remember); _pam_overwrite(pass_new); _pam_overwrite(pass_old); _pam_delete(tpass); pass_old = pass_new = NULL; } else { /* something has broken with the module */
int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) { unsigned int ctrl; int retval, *ret_data = NULL; SAM_ACCOUNT *sampass = NULL; extern BOOL in_client; const char *name; void (*oldsig_handler)(int); BOOL found; /* Points to memory managed by the PAM library. Do not free. */ char *p = NULL; /* Samba initialization. */ setup_logging("pam_smbpass",False); in_client = True; ctrl = set_ctrl(flags, argc, argv); /* Get a few bytes so we can pass our return value to pam_sm_setcred(). */ ret_data = malloc(sizeof(int)); /* get the username */ retval = pam_get_user( pamh, &name, "Username: "******"auth: could not identify user"); } AUTH_RETURN; } if (on( SMB_DEBUG, ctrl )) { _log_err( LOG_DEBUG, "username [%s] obtained", name ); } /* Getting into places that might use LDAP -- protect the app from a SIGPIPE it's not expecting */ oldsig_handler = CatchSignal(SIGPIPE, SIGNAL_CAST SIG_IGN); if (!initialize_password_db(True)) { _log_err( LOG_ALERT, "Cannot access samba password database" ); retval = PAM_AUTHINFO_UNAVAIL; AUTH_RETURN; } pdb_init_sam(&sampass); found = pdb_getsampwnam( sampass, name ); if (on( SMB_MIGRATE, ctrl )) { retval = _smb_add_user(pamh, ctrl, name, sampass, found); pdb_free_sam(&sampass); AUTH_RETURN; } if (!found) { _log_err(LOG_ALERT, "Failed to find entry for user %s.", name); retval = PAM_USER_UNKNOWN; pdb_free_sam(&sampass); sampass = NULL; AUTH_RETURN; } /* if this user does not have a password... */ if (_smb_blankpasswd( ctrl, sampass )) { pdb_free_sam(&sampass); retval = PAM_SUCCESS; AUTH_RETURN; } /* get this user's authentication token */ retval = _smb_read_password(pamh, ctrl, NULL, "Password: "******"auth: no password provided for [%s]" , name); pdb_free_sam(&sampass); AUTH_RETURN; } /* verify the password of this user */ retval = _smb_verify_password( pamh, sampass, p, ctrl ); pdb_free_sam(&sampass); p = NULL; AUTH_RETURN; }
int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) { unsigned int ctrl; int retval, *ret_data = NULL; struct samu *sampass = NULL; const char *name; void (*oldsig_handler)(int) = NULL; bool found; /* Points to memory managed by the PAM library. Do not free. */ char *p = NULL; /* Samba initialization. */ load_case_tables(); lp_set_in_client(True); ctrl = set_ctrl(pamh, flags, argc, argv); /* Get a few bytes so we can pass our return value to pam_sm_setcred(). */ ret_data = SMB_MALLOC_P(int); /* we need to do this before we call AUTH_RETURN */ /* Getting into places that might use LDAP -- protect the app from a SIGPIPE it's not expecting */ oldsig_handler = CatchSignal(SIGPIPE, SIGNAL_CAST SIG_IGN); /* get the username */ retval = pam_get_user( pamh, &name, "Username: "******"auth: could not identify user"); } AUTH_RETURN; } if (on( SMB_DEBUG, ctrl )) { _log_err(pamh, LOG_DEBUG, "username [%s] obtained", name ); } if (geteuid() != 0) { _log_err(pamh, LOG_DEBUG, "Cannot access samba password database, not running as root."); retval = PAM_AUTHINFO_UNAVAIL; AUTH_RETURN; } if (!initialize_password_db(True, NULL)) { _log_err(pamh, LOG_ALERT, "Cannot access samba password database" ); retval = PAM_AUTHINFO_UNAVAIL; AUTH_RETURN; } sampass = samu_new( NULL ); if (!sampass) { _log_err(pamh, LOG_ALERT, "Cannot talloc a samu struct" ); retval = nt_status_to_pam(NT_STATUS_NO_MEMORY); AUTH_RETURN; } found = pdb_getsampwnam( sampass, name ); if (on( SMB_MIGRATE, ctrl )) { retval = _smb_add_user(pamh, ctrl, name, sampass, found); TALLOC_FREE(sampass); AUTH_RETURN; } if (!found) { _log_err(pamh, LOG_ALERT, "Failed to find entry for user %s.", name); retval = PAM_USER_UNKNOWN; TALLOC_FREE(sampass); sampass = NULL; AUTH_RETURN; } /* if this user does not have a password... */ if (_smb_blankpasswd( ctrl, sampass )) { TALLOC_FREE(sampass); retval = PAM_SUCCESS; AUTH_RETURN; } /* get this user's authentication token */ retval = _smb_read_password(pamh, ctrl, NULL, "Password: "******"auth: no password provided for [%s]", name); TALLOC_FREE(sampass); AUTH_RETURN; } /* verify the password of this user */ retval = _smb_verify_password( pamh, sampass, p, ctrl ); TALLOC_FREE(sampass); p = NULL; AUTH_RETURN; }
/* Helper function for adding a user to the db. */ static int _smb_add_user(pam_handle_t *pamh, unsigned int ctrl, const char *name, SAM_ACCOUNT *sampass, BOOL exist) { pstring err_str; pstring msg_str; const char *pass = NULL; int retval; err_str[0] = '\0'; msg_str[0] = '\0'; /* Get the authtok; if we don't have one, silently fail. */ retval = pam_get_item( pamh, PAM_AUTHTOK, (const void **) &pass ); if (retval != PAM_SUCCESS) { _log_err( LOG_ALERT , "pam_get_item returned error to pam_sm_authenticate" ); return PAM_AUTHTOK_RECOVER_ERR; } else if (pass == NULL) { return PAM_AUTHTOK_RECOVER_ERR; } /* Add the user to the db if they aren't already there. */ if (!exist) { retval = local_password_change( name, LOCAL_ADD_USER, pass, err_str, sizeof(err_str), msg_str, sizeof(msg_str) ); if (!retval && *err_str) { err_str[PSTRING_LEN-1] = '\0'; make_remark( pamh, ctrl, PAM_ERROR_MSG, err_str ); } else if (*msg_str) { msg_str[PSTRING_LEN-1] = '\0'; make_remark( pamh, ctrl, PAM_TEXT_INFO, msg_str ); } pass = NULL; return PAM_IGNORE; } else { /* Change the user's password IFF it's null. */ if ((pdb_get_lanman_passwd(sampass) == NULL) && (pdb_get_acct_ctrl(sampass) & ACB_PWNOTREQ)) { retval = local_password_change( name, 0, pass, err_str, sizeof(err_str), msg_str, sizeof(msg_str) ); if (!retval && *err_str) { err_str[PSTRING_LEN-1] = '\0'; make_remark( pamh, ctrl, PAM_ERROR_MSG, err_str ); } else if (*msg_str) { msg_str[PSTRING_LEN-1] = '\0'; make_remark( pamh, ctrl, PAM_TEXT_INFO, msg_str ); } } } pass = NULL; return PAM_IGNORE; }