pax_global_header00006660000000000000000000000064126704600050014512gustar00rootroot0000000000000052 comment=dc45334bab8407ce2bab873ff830e64279d38678 pam_ufpidentity-1.0/000077500000000000000000000000001267046000500145535ustar00rootroot00000000000000pam_ufpidentity-1.0/LICENSE000066400000000000000000000014161267046000500155620ustar00rootroot00000000000000pam_ufpidentity - UFP Identity PAM module Copyright (C) 2016 Richard Levenberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. pam_ufpidentity-1.0/Makefile000066400000000000000000000007761267046000500162250ustar00rootroot00000000000000CC?=gcc ODIR=. LIBS=-lpam -lufpidentity LIBDIR?=$(PREFIX)/lib _OBJ = pam_ufpidentity.o OBJ = $(patsubst %,$(ODIR)/%,$(_OBJ)) $(ODIR)/%.o: %.c $(DEPS) $(CC) -fPIC -c -o $@ $< $(CPPFLAGS) $(CFLAGS) pam_ufpidentity.so: $(OBJ) gcc -shared -Wl,-soname,$@ -o $@ $^ $(LIBS) -Wl,-z,defs $(LDFLAGS) .PHONY: clean clean: rm -f $(ODIR)/*.o *~ core $(INCDIR)/*~ pam_ufpidentity.so install: pam_ufpidentity.so mkdir -p $(DESTDIR)$(LIBDIR)/security install -m 644 pam_ufpidentity.so $(DESTDIR)$(LIBDIR)/security pam_ufpidentity-1.0/README.md000066400000000000000000000053271267046000500160410ustar00rootroot00000000000000UFP Identity PAM module ======================= Overview -------- The UFP Identity PAM module provides integration of the UFP Identity service into your existing user authentication infrastructure. PAM is used by Linux/BSD, Solaris and Mac OS X for user authentication to various services such as SSH, login, and sudo. Installation ------------ After acquiring the source, and the required dependencies, you can build with: make clean make export LIBDIR=/lib/i386-linux-gnu ; sudo make install That will install pam_ufpidentity.so into /lib/i386-linux-gnu/security (n.b. change the directory for your multi-arch setup) Then you need to get credentials for accessing the UFP Identity service. Please read [Getting Started](https://www.ufp.com/identity/integration.html#getting_started) for an overview. Make sure to have an ASCII representable key for your private key. And make sure to carefully think about the CN you use. For a large number of machines you may want a base domain like example.com, rather than web01.example.com, web02.example.com, etc. On a Linux machine it is recommended to keepy your private keys in /etc/ssl/private and your certificates in /etc/ssl/certs. You will also need our truststore somewhere (/etc/ssl/certs is good). n.b. /etc/ssl/private is a restricted directory. Make sure you understand and configure appropriate permissions for access to files in there. You can test with the check\_user application. Configure the check\_user service with a file called check\_user in /etc/pam.d/ The contents of the file look like: # check authorization auth required pam_ufpidentity.so cert= passphrase= key= truststore= account required pam_unix.so Compile the check_user application like: gcc -o check_user check_user.c -lpam -lpam_misc Make sure the check_user application is run with permissions to access the file(s) in /etc/ssl/private sudo ./check_user To configure ssh modifiy the /etc/pam.d/sshd (n.b. do this from a console to ensure that access is not compromised) Comment out the line that includes common-auth (we no longer want pam_unix to check against /etc/passwd). Under that line add the configuration for UFP Identity auth required pam_ufpidentity.so cert= passphrase= key= truststore= Then some modifications to /etc/ssh/sshd_config are required including: ChallengeResponseAuthentication yes PasswordAuthentication no UsePAM yes Restart sshd and try it out. Integrate and enroll and we'll send you a free Yubico or you can use our [iOS OATH app](https://itunes.apple.com/us/app/ufp-identity-oath-token/id794203464?mt=8) pam_ufpidentity-1.0/check_user.c000066400000000000000000000021641267046000500170350ustar00rootroot00000000000000#include #include #include static struct pam_conv conv = { misc_conv, NULL }; int main(int argc, char *argv[]) { pam_handle_t *pamh=NULL; int retval; const char *user=NULL; if(argc == 2) { user = argv[1]; } if(argc > 2) { fprintf(stderr, "Usage: check_user [username]\n"); exit(1); } retval = pam_start("check_user", user, &conv, &pamh); if (retval == PAM_SUCCESS) retval = pam_authenticate(pamh, 0); /* is user really user? */ if (retval == PAM_SUCCESS) retval = pam_acct_mgmt(pamh, 0); /* permitted access? */ /* This is where we have been authorized or not. */ if (retval == PAM_SUCCESS) { fprintf(stdout, "Authenticated\n"); } else { fprintf(stdout, "Not Authenticated\n"); } if (pam_end(pamh,retval) != PAM_SUCCESS) { /* close Linux-PAM */ pamh = NULL; fprintf(stderr, "check_user: failed to release authenticator\n"); exit(1); } return ( retval == PAM_SUCCESS ? 0:1 ); /* indicate success */ } pam_ufpidentity-1.0/pam_ufpidentity.c000066400000000000000000000202601267046000500201200ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #define PAM_SM_AUTH #include #define MODULE_NAME "pam_ufpidentity" #include "identity.h" static int check_authentication_context(authentication_context_t * authentication_context); static int get_display_item_count(display_item_t * display_items); static char *get_display_item_string(display_item_t * display_items); const char *get_key_value(const char *key, int argc, const char **argv) { char *delim, sep = '='; int i; for (i = 0; i < argc; ++i) { delim = strchr(argv[i], sep); /* No separator found */ if (delim == NULL) continue; /* No key */ if (delim == argv[i]) continue; if (strncmp(key, argv[i], delim - argv[i]) == 0) return delim + 1; } return NULL; } static void log_message(int priority, pam_handle_t * pamh, const char *format, ...) { char *service = NULL; if (pamh) pam_get_item(pamh, PAM_SERVICE, (void *) &service); if (!service) service = ""; char logname[80]; snprintf(logname, sizeof(logname), "%s(" MODULE_NAME ")", service); va_list args; va_start(args, format); openlog(logname, LOG_CONS | LOG_PID, LOG_AUTHPRIV); vsyslog(priority, format, args); closelog(); va_end(args); } PAM_EXTERN int pam_sm_setcred(pam_handle_t * pamh, int flags, int argc, const char **argv) { return PAM_SUCCESS; } /* this function is ripped from pam_unix/support.c, it lets us do IO via PAM */ int converse(pam_handle_t * pamh, int nargs, struct pam_message **message, struct pam_response **response) { int retval; struct pam_conv *pam_conv; retval = pam_get_item(pamh, PAM_CONV, (const void **) &pam_conv); if (retval == PAM_SUCCESS) { retval = pam_conv->conv(nargs, (const struct pam_message **) message, response, pam_conv->appdata_ptr); } return retval; } int hostname_to_ip(const char *hostname, char *ip) { struct hostent *he; struct in_addr **addr_list; int i; if ( (he = gethostbyname( hostname ) ) == NULL) { // get the host info herror("gethostbyname"); return 1; } addr_list = (struct in_addr **) he->h_addr_list; for(i = 0; addr_list[i] != NULL; i++) { //Return the first one; strcpy(ip , inet_ntoa(*addr_list[i]) ); return 0; } return 1; } void try_rhost(StrMap *sm, pam_handle_t *pamh) { const void *from = NULL; pam_get_item(pamh, PAM_RHOST, &from); log_message(LOG_DEBUG, pamh, "PAM_RHOST %s", from); if (from != NULL) { char ip[100]; memset(ip, 0, 100*sizeof(char)); int r = hostname_to_ip(from, ip); sm_put(sm, "client_ip", (r == 0)?ip:from); } } /* expected hook, this is where custom stuff happens */ PAM_EXTERN int pam_sm_authenticate(pam_handle_t * pamh, int flags, int argc, const char **argv) { int retval; /* getting the username that was used in the previous authentication */ const char *username; if ((retval = pam_get_user(pamh, &username, NULL)) != PAM_SUCCESS) { return retval; } log_message(LOG_INFO, pamh, "username %s", username); /** * preAuthenticate with username, if success continue, else return error. At this point * we are going to be allocating memory so we can't just retun without cleaning things up. */ identity_context_t *identity_context = get_identity_context((char *)get_key_value("cert", argc, argv), (char *)get_key_value("truststore", argc, argv), (char *)get_key_value("key", argc, argv), (char *)get_key_value("passphrase", argc, argv)); authentication_context_t *authentication_context = NULL; StrMap *sm = sm_new(10); try_rhost(sm, pamh); authentication_pretext_t *authentication_pretext = pre_authenticate(identity_context, username, sm); if (authentication_pretext != NULL) { log_message(LOG_DEBUG, pamh, "response %s", authentication_pretext->authentication_result->message); if ((strcmp(authentication_pretext->authentication_result->message, "OK") == 0) && (strcmp(authentication_pretext->authentication_result->text, "SUCCESS") == 0)) { do { int count = get_display_item_count(authentication_pretext->display_items); char *input; struct pam_message msg[count], *pmsg[count]; struct pam_response *response = NULL; display_item_t *display_item = authentication_pretext->display_items; int index = 0; do { pmsg[index] = &msg[index]; msg[index].msg_style = (strncmp(display_item->name, "passphrase", 10) == 0) ? PAM_PROMPT_ECHO_OFF : PAM_PROMPT_ECHO_ON; msg[index].msg = get_display_item_string(display_item); index++; display_item = display_item->next; } while (display_item != NULL); retval = converse(pamh, count, pmsg, &response); // clean up the messages int i; for (i = 0; i < count; i++) free((void *)msg[i].msg); if (retval == PAM_SUCCESS) { // if this function fails, make sure that ChallengeResponseAuthentication in sshd_config is set to yes display_item = authentication_pretext->display_items; index = 0; StrMap *sm = sm_new(10); do { sm_put(sm, display_item->name, response[index].resp); index++; display_item = display_item->next; } while (display_item != NULL); try_rhost(sm, pamh); authentication_context = authenticate(identity_context, authentication_pretext->name, sm); } else break; } while (!check_authentication_context(authentication_context)); } else retval = PAM_USER_UNKNOWN; free_authentication_pretext(authentication_pretext); } else log_message(LOG_DEBUG, pamh, "authentication_pretext is NULL"); if (authentication_context != NULL) { log_message(LOG_DEBUG, pamh, "message %s, text %s", authentication_context->authentication_result->message, authentication_context->authentication_result->text); if (strcmp(authentication_context->authentication_result->text, "SUCCESS") == 0) retval = PAM_SUCCESS; else retval = PAM_MAXTRIES; free_authentication_context(authentication_context); } if (identity_context != NULL) free_identity_context(identity_context); return retval; } static char *get_display_item_string(display_item_t * display_item) { int length = strlen(display_item->display_name) + strlen(display_item->nickname) + 5; // a space, two parens, colon and terminating null char *buffer = malloc(length); memset(buffer, 0, length); sprintf(buffer, "%s (%s):", display_item->display_name, display_item->nickname); return buffer; } static int check_authentication_context(authentication_context_t * authentication_context) { log_message(LOG_DEBUG, NULL, "message %s, text %s", authentication_context->authentication_result->message, authentication_context->authentication_result->text); return (((strcmp(authentication_context->authentication_result->message, "OK") == 0) && (strcmp(authentication_context->authentication_result->text, "SUCCESS") == 0)) || (strcmp(authentication_context->authentication_result->text, "RESET") == 0)); } static int get_display_item_count(display_item_t * display_items) { int count = 0; display_item_t *display_item = display_items; do { display_item = display_item->next; count++; } while (display_item != NULL); return count; }