📄 extens.c
字号:
if (retval == PAM_SUCCESS) { debug("unix_PAM: function pam_authenticate succeeded for <%s>\n", name); retval = pam_acct_mgmt(pamh, 0); } /* do not remove block braces, it could break things due to debug * macro */ if (retval == PAM_SUCCESS) { debug("unix_PAM: function pam_acct_mgmt succeeded for <%s>\n", name); } else { debug("unix_PAM: PAM FAILED for <%s> failed\n", name); } if (pam_end(pamh, retval) != PAM_SUCCESS) { pamh = NULL; log_err("ERROR!!!: PAM failed to release authenticator items"); } return (retval == PAM_SUCCESS)?0:-1;}/* * Function: PAM_conv_session * Purpose: A dummy conversation function between the radiusd and the * session modules. */static int PAM_conv_session(int num_msg, const struct pam_message **msg,struct pam_response **resp, void *appdata_ptr){ /* this one should never be called; use appdata_ptr instead */ return PAM_CONV_ERR;} /* * We use this structure to pass the network packet pairs to * the session module(s) */static struct pam_conv conv_session = { (int (*)())PAM_conv_session, NULL };/* * This is to save the handle of the PAM session betwenn incantations... */static pam_handle_t *PAM_handle = NULL;/* * Function: pam_session * Purpose: This is called when we are using PAM to inform the PAM * library about the new sessions being open or closed by * the NASes. */void pam_session(AUTH_REQ *authreq){ char *username = NULL; VALUE_PAIR *pair; int retval; pam_handle_t *pamh = NULL; int type=0; /* First, get some important data: username and the type of the packet */ pair = authreq->request; while (pair != (VALUE_PAIR *)NULL) { switch (pair->attribute) { case PW_USER_NAME: username = pair->strvalue; break; case PW_ACCT_STATUS_TYPE: type = pair->lvalue; break; } pair = pair->next; } /* To do: * -we should maybe look at the NAS ip and set the * PAM_RHOST item too. But for now it is not critical, * and I am lazy.. * --cristiang */ if ((username == NULL) || !type) /* nothing to do */ return; /* initialize the conv_session struct */ conv_session.appdata_ptr = authreq->request; /* we avoid to open to many sessions with pam_start because of the * overhead induced by this call. On a busy accounting server, * this is critical. We open just one session and reuse it later... */ if (PAM_handle == (pam_handle_t *)NULL) { /* we need to open a new session */ debug("about to init PAM session call for %s\n", username); retval = pam_start(RADIUS_PAM_SERVICE, username, &conv_session, &pamh); if (retval != PAM_SUCCESS) {#if !defined(OLD_PAM) log_err("cannot initialize PAM session for %s (%s)\n", username, pam_strerror(PAM_handle, retval));#else log_err("cannot initialize PAM session for %s (%s)\n", username, pam_strerror(retval));#endif return; } else /* opened successfuly - save it for later use... */ PAM_handle = pamh; } else { /* we have already an open session - use that... */ pamh = PAM_handle; /* and update the username */ retval = pam_set_item(pamh, PAM_USER, username); if (retval != PAM_SUCCESS) {#if !defined(OLD_PAM) /* The new pam libraries have 2 params for pam_strerr - misa*/ log_err("can not set username (%s) for acct packet: %s\n", username, pam_strerror(PAM_handle, retval));#else log_err("can not set username (%s) for acct packet: %s\n", username, pam_strerror(retval));#endif /*OLD_PAM*/ return; } /* and the conversation structure, to get appdata pointer * updated with the new pointer to the network packet... */ retval = pam_set_item(pamh, PAM_CONV, &conv_session); if (retval != PAM_SUCCESS) {#if !defined(OLD_PAM) /* The new pam libraries have 2 params for pam_strerr - misa*/ log_err("can not pass acct packet for %s: %s\n", username, pam_strerror(PAM_handle, retval));#else log_err("can not pass acct packet for %s: %s\n", username, pam_strerror(retval));#endif /*OLD_PAM*/ return; } } /* all good, now do we start or close a session ? */ if (type == PW_STATUS_START) { /* start session */ debug("opening session for user %s\n", username); retval = pam_open_session(pamh, 0); if (retval != PAM_SUCCESS) {#if !defined(OLD_PAM) /* The new pam libraries have 2 params for pam_strerr - misa*/ log_err("could not start session for user %s (%s)\n", username, pam_strerror(PAM_handle, retval));#else log_err("could not start session for user %s (%s)\n", username, pam_strerror(retval));#endif /*OLD_PAM*/ return; } } if (type == PW_STATUS_STOP) { /* close session */ debug("closing session for user %s\n", username); retval = pam_close_session(pamh, 0); if (retval != PAM_SUCCESS) {#if !defined(OLD_PAM) /* The new pam libraries have 2 params for pam_strerr - misa*/ log_err("could not close session for user %s (%s)\n", username, pam_strerror(PAM_handle, retval));#else log_err("could not close session for user %s (%s)\n", username, pam_strerror(retval));#endif /*OLD_PAM*/ return; } } /* we don't call pam_end because this code is not supposed to die()... * <sigh!> --cristiang */ return;}#else #if defined(PAM) && !defined(HAVE_LIBPAM)#error "PAM development library missed. Check your configuration."#endif#endif /* PAM *//* * SOME BASIC PACKET QUEUE MANAGEMENT STUFF * * Idea: eliminate the duplicate acct packets problem and sort out the * out-of-order packets to get better accounting */static acct_packet *root_acct_packet = NULL;static int acct_queue_entries = 0;static acct_packet *in_acct_queue(acct_packet *packet, int type){ acct_packet *this; this = root_acct_packet; while (this != (acct_packet *)NULL) { if ( (this->port == packet->port) && (this->nas_ip == packet->nas_ip) && !strncmp(this->username, packet->username, sizeof(packet->username)) && !strncmp(this->sessionid, packet->sessionid, sizeof(packet->sessionid)) && (this->type & type) ) return this; this = this->next; } return (acct_packet *)NULL;}/* * Adds a pack to the queue */static int add_acct_queue(acct_packet *packet){ acct_packet *this, *temp; this = root_acct_packet; temp = in_acct_queue(packet, packet->type); if (temp != (acct_packet *)NULL) return 0; temp = in_acct_queue(packet, PW_STATUS_STOP | PW_STATUS_START); if (temp != (acct_packet *)NULL) { temp->type |= packet->type; return 1; } temp = (acct_packet *)NULL; while (this != (acct_packet *)NULL) { temp = this; this = this->next; } this = (acct_packet *)malloc(sizeof(acct_packet)); if (this == (acct_packet *)NULL) { log_err("MEMORY ERROR !!! Can not alloc memory for acct packet %s (user %s)", packet->sessionid, packet->username); return 0; } if (temp == (acct_packet *)NULL) temp = this; else { temp->next = this; temp = this; } temp->next = (acct_packet *)NULL; /* one more entry */ acct_queue_entries++; /* root list empty */ if (root_acct_packet == (acct_packet *)NULL) root_acct_packet = temp; /* copy over */ memcpy(temp, packet, sizeof(acct_packet)); return 1;}/* * Removes a packet from the queue */static int remove_acct_queue(acct_packet *packet){ acct_packet *temp, *temp1; temp = in_acct_queue(packet, PW_STATUS_START | PW_STATUS_STOP); if (temp == (acct_packet *)NULL) return 0; if (temp->type != (PW_STATUS_START | PW_STATUS_STOP)) return 0; if (temp == root_acct_packet) { /* oops. the root is here ... */ root_acct_packet = root_acct_packet->next; } else { temp1 = root_acct_packet; while (temp1->next != temp) temp1 = temp1->next; temp1->next = temp->next; }; free(temp); acct_queue_entries--; return 1;}/* * Delete the oldest pair of (start,stop) packets from the queue * to make room for more */static int cleanup_acct_queue(void){ acct_packet *temp; temp = root_acct_packet; while (temp != (acct_packet*)NULL) { if (temp->type == (PW_STATUS_START | PW_STATUS_STOP)) return remove_acct_queue(temp); temp = temp->next; } return 1;}/* * Returns > 0 if the packet passed is valid, 0 otherwise * A valid packet is: * - a new one (we haven't seen it before) * - a stop packet * - a start packet which is not out of order (we haven't seen * the corresponsing packet for it yet */int validate_acct_packet(AUTH_REQ *authreq){ acct_packet packet; VALUE_PAIR *pair; /* Some run-time debugging */ if (acct_queue_entries > 2*MAX_ACCT_QUEUE) { log_debug("WARNING: acct queue is large: %d entries, max %d\n", acct_queue_entries, MAX_ACCT_QUEUE); log_debug("possible unreliable communication with term servers ?\n"); } pair = authreq->request; memset(&packet, 0, sizeof(acct_packet)); while (pair != (VALUE_PAIR *)NULL) { switch (pair->attribute) { case PW_ACCT_STATUS_TYPE: packet.type = pair->lvalue; break; case PW_USER_NAME: strncpy(packet.username, (char *)pair->strvalue, sizeof(packet.username)); break; case PW_CLIENT_PORT_ID: packet.port = pair->lvalue; break; case PW_CLIENT_ID: packet.nas_ip = pair->lvalue; break; case PW_ACCT_SESSION_ID: strncpy(packet.sessionid, (char *)pair->strvalue, sizeof(packet.sessionid)); break; }; pair = pair->next; }; /* we have a complete packet ... */ if (in_acct_queue(&packet, packet.type) != (acct_packet *)NULL) return 0; if (packet.type == PW_STATUS_START) { if (!add_acct_queue(&packet)) log_err("ERROR!!!: could not add acct packet to queue (%s/%s)", packet.sessionid, packet.username); if (in_acct_queue(&packet, PW_STATUS_STOP) != (acct_packet *)NULL) return 0; } else if (packet.type == PW_STATUS_STOP) { if (!add_acct_queue(&packet)) log_err("ERROR!!!: could not add acct packet to queue (%s/%s)", packet.sessionid, packet.username); if (in_acct_queue(&packet, PW_STATUS_START) != (acct_packet *)NULL) if (acct_queue_entries > MAX_ACCT_QUEUE) if (!cleanup_acct_queue()) log_err("ERROR!!!: could not cleanup the acct packet queue!"); } else return 0; return 1;}/* * MD5 crypt() support for systems using both DES and MD5 */static unsigned char itoa64[] = /* 0 ... 63 => ascii - 64 */ "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";static void to64(char *s, unsigned long v, int n){ while (--n >= 0) { *s++ = itoa64[v&0x3f]; v >>= 6; }}/* * UNIX password * * Use MD5 for what it is best at... */char * crypt_md5(const char *pw, const char *salt){ const char *magic = "$1$"; /* This string is magic for this algorithm. Having * it this way, we can get get better later on */ static char passwd[120], *p; static const char *sp,*ep; unsigned char final[16]; int sl,pl,i,j; MD5_CTX ctx,ctx1; unsigned long l; /* Refine the Salt first */ sp = salt; /* If it starts with the magic string, then skip that */ if(!strncmp(sp,magic,strlen(magic))) sp += strlen(magic); /* It stops at the first '$', max 8 chars */ for(ep=sp;*ep && *ep != '$' && ep < (sp+8);ep++) continue; /* get the length of the true salt */ sl = ep - sp; MD5Init(&ctx); /* The password first, since that is what is most unknown */ MD5Update(&ctx, (unsigned const char *)pw, strlen(pw)); /* Then our magic string */ MD5Update(&ctx, (unsigned const char *)magic,strlen(magic)); /* Then the raw salt */ MD5Update(&ctx, (unsigned const char *)sp, sl); /* Then just as many characters of the MD5(pw,salt,pw) */ MD5Init(&ctx1); MD5Update(&ctx1, (unsigned const char *)pw, strlen(pw)); MD5Update(&ctx1, (unsigned const char *)sp, sl); MD5Update(&ctx1, (unsigned const char *)pw, strlen(pw)); MD5Final(final,&ctx1); for(pl = strlen(pw); pl > 0; pl -= 16) MD5Update(&ctx, (unsigned const char *)final,pl>16 ? 16 : pl); /* Don't leave anything around in vm they could use. */ memset(final,0,sizeof final); /* Then something really weird... */ for (j=0,i = strlen(pw); i ; i >>= 1) if(i&1) MD5Update(&ctx, (unsigned const char *)final+j, 1); else MD5Update(&ctx, (unsigned const char *)pw+j, 1); /* Now make the output string */ strcpy(passwd,magic); strncat(passwd,sp,sl); strcat(passwd,"$"); MD5Final(final,&ctx); /* * and now, just to make sure things don't run too fast * On a 60 Mhz Pentium this takes 34 msec, so you would * need 30 seconds to build a 1000 entry dictionary... */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -