📄 authreg.c
字号:
/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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., 59 Temple Place, Suite 330, Boston, MA02111-1307USA */#include "c2s.h"#ifdef HAVE_IDN#include <stringprep.h>#endif/* authreg module manager *//* if you add a module, you'll need to update these arrays */#ifdef STORAGE_MYSQLextern int ar_mysql_init(authreg_t);#endif#ifdef STORAGE_PGSQLextern int ar_pgsql_init(authreg_t);#endif#ifdef STORAGE_DBextern int ar_db_init(authreg_t);#endif#ifdef STORAGE_LDAPextern int ar_ldap_init(authreg_t);#endif#ifdef STORAGE_PAMextern int ar_pam_init(authreg_t);#endif#ifdef STORAGE_PIPEextern int ar_pipe_init(authreg_t);#endif#ifdef STORAGE_ANONextern int ar_anon_init(authreg_t);#endifchar *module_names[] = {#ifdef STORAGE_MYSQL "mysql",#endif#ifdef STORAGE_PGSQL "pgsql",#endif#ifdef STORAGE_DB "db",#endif#ifdef STORAGE_LDAP "ldap",#endif#ifdef STORAGE_PAM "pam",#endif#ifdef STORAGE_PIPE "pipe",#endif#ifdef STORAGE_ANON "anon",#endif NULL};ar_module_init_fn module_inits[] = {#ifdef STORAGE_MYSQL ar_mysql_init,#endif#ifdef STORAGE_PGSQL ar_pgsql_init,#endif#ifdef STORAGE_DB ar_db_init,#endif#ifdef STORAGE_LDAP ar_ldap_init,#endif#ifdef STORAGE_PAM ar_pam_init,#endif#ifdef STORAGE_PIPE ar_pipe_init,#endif#ifdef STORAGE_ANON ar_anon_init,#endif NULL};typedef struct _authreg_error_st { char *class; char *name; char *code; char *uri;} *authreg_error_t;/** get a handle for the named module */authreg_t authreg_init(c2s_t c2s, char *name) { int n; ar_module_init_fn init = NULL; authreg_t ar; /* hunt it down */ n = 0; while(module_names[n] != NULL) { if(strcmp(module_names[n], name) == 0) { init = module_inits[n]; break; } n++; } if(init == NULL) { log_write(c2s->log, LOG_ERR, "no such auth module '%s'", name); return NULL; } /* make a new one */ ar = (authreg_t) malloc(sizeof(struct authreg_st)); memset(ar, 0, sizeof(struct authreg_st)); ar->c2s = c2s; /* call the initialiser */ if((init)(ar) != 0) { log_write(c2s->log, LOG_ERR, "failed to initialise auth module '%s'", name); authreg_free(ar); return NULL; } /* we need user_exists(), at the very least */ if(ar->user_exists == NULL) { log_write(c2s->log, LOG_ERR, "auth module '%s' has no check for user existence", name); authreg_free(ar); return NULL; } /* its good */ log_write(c2s->log, LOG_NOTICE, "initialised auth module '%s'", name); return ar;}/** shutdown the authreg system */void authreg_free(authreg_t ar) { if(ar->free != NULL) (ar->free)(ar); free(ar);}/** auth get handler */static void _authreg_auth_get(c2s_t c2s, sess_t sess, nad_t nad) { int ns, elem, ssequence, attr; char username[1024], shash[41], stoken[11], seqs[10], id[128]; /* can't auth if they're active */ if(sess->active) { sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_NOT_ALLOWED), 0)); return; } /* sort out the username */ ns = nad_find_scoped_namespace(nad, "jabber:iq:auth", NULL); elem = nad_find_elem(nad, 1, ns, "username", 1); if(elem < 0) { log_debug(ZONE, "auth get with no username, bouncing it"); sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_BAD_REQUEST), 0)); return; } snprintf(username, 1024, "%.*s", NAD_CDATA_L(nad, elem), NAD_CDATA(nad, elem));#ifdef HAVE_IDN if(stringprep_xmpp_nodeprep(username, 1024) != 0) { log_debug(ZONE, "auth get username failed nodeprep, bouncing it"); sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_JID_MALFORMED), 0)); return; }#endif /* no point going on if we have no mechanisms */ if(!(c2s->ar_mechanisms & (AR_MECH_TRAD_PLAIN | AR_MECH_TRAD_DIGEST | AR_MECH_TRAD_ZEROK))) { sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_FORBIDDEN), 0)); return; } /* do we have the user? */ if((c2s->ar->user_exists)(c2s->ar, username, sess->realm) == 0) { sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_OLD_UNAUTH), 0)); return; } /* extract the id */ attr = nad_find_attr(nad, 0, -1, "id", NULL); if(attr >= 0) snprintf(id, 128, "%.*s", NAD_AVAL_L(nad, attr), NAD_AVAL(nad, attr)); nad_free(nad); /* build a result packet */ nad = nad_new(sess->s->nad_cache); ns = nad_add_namespace(nad, uri_CLIENT, NULL); nad_append_elem(nad, ns, "iq", 0); nad_append_attr(nad, -1, "type", "result"); if(attr >= 0) nad_append_attr(nad, -1, "id", id); ns = nad_add_namespace(nad, "jabber:iq:auth", NULL); nad_append_elem(nad, ns, "query", 1); nad_append_elem(nad, ns, "username", 2); nad_append_cdata(nad, username, strlen(username), 3); nad_append_elem(nad, ns, "resource", 2); /* fill out the packet with available auth mechanisms */ if(c2s->ar_mechanisms & AR_MECH_TRAD_PLAIN && (c2s->ar->get_password != NULL || c2s->ar->check_password != NULL)) nad_append_elem(nad, ns, "password", 2); if(c2s->ar_mechanisms & AR_MECH_TRAD_DIGEST && c2s->ar->get_password != NULL) nad_append_elem(nad, ns, "digest", 2); /* don't offer zerok if the sequence is zero */ if(c2s->ar_mechanisms & AR_MECH_TRAD_ZEROK && c2s->ar->get_zerok != NULL && c2s->ar->set_zerok != NULL && (c2s->ar->get_zerok)(c2s->ar, username, sess->realm, shash, stoken, &ssequence) == 0 && ssequence > 0) { snprintf(seqs, 10, "%d", ssequence - 1); nad_append_elem(nad, ns, "sequence", 2); nad_append_cdata(nad, seqs, strlen(seqs), 3); nad_append_elem(nad, ns, "token", 2); nad_append_cdata(nad, stoken, strlen(stoken), 3); } /* give it back to the client */ sx_nad_write(sess->s, nad); return;}/** auth set handler */static void _authreg_auth_set(c2s_t c2s, sess_t sess, nad_t nad) { int ns, elem, attr, authd = 0, ssequence; char username[1024], resource[1024], str[1024], shash[41], stoken[11], hash[280]; /* can't auth if they're active */ if(sess->active) { sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_NOT_ALLOWED), 0)); return; } ns = nad_find_scoped_namespace(nad, "jabber:iq:auth", NULL); /* sort out the username */ elem = nad_find_elem(nad, 1, ns, "username", 1); if(elem < 0) { log_debug(ZONE, "auth set with no username, bouncing it"); sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_BAD_REQUEST), 0)); return; } snprintf(username, 1024, "%.*s", NAD_CDATA_L(nad, elem), NAD_CDATA(nad, elem));#ifdef HAVE_IDN if(stringprep_xmpp_nodeprep(username, 1024) != 0) { log_debug(ZONE, "auth set username failed nodeprep, bouncing it"); sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_JID_MALFORMED), 0)); return; }#endif /* make sure we have the resource */ elem = nad_find_elem(nad, 1, ns, "resource", 1); if(elem < 0) { log_debug(ZONE, "auth set with no resource, bouncing it"); sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_BAD_REQUEST), 0)); return; } snprintf(resource, 1024, "%.*s", NAD_CDATA_L(nad, elem), NAD_CDATA(nad, elem));#ifdef HAVE_IDN if(stringprep_xmpp_resourceprep(resource, 1024) != 0) { log_debug(ZONE, "auth set resource failed resourceprep, bouncing it"); sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_JID_MALFORMED), 0)); return; }#endif /* no point going on if we have no mechanisms */ if(!(c2s->ar_mechanisms & (AR_MECH_TRAD_PLAIN | AR_MECH_TRAD_DIGEST | AR_MECH_TRAD_ZEROK))) { sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_FORBIDDEN), 0)); return; } /* do we have the user? */ if((c2s->ar->user_exists)(c2s->ar, username, sess->realm) == 0) { sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_OLD_UNAUTH), 0)); return; } /* zerok auth */ if(!authd && c2s->ar_mechanisms & AR_MECH_TRAD_ZEROK && c2s->ar->get_zerok != NULL && c2s->ar->set_zerok != NULL && (c2s->ar->get_zerok)(c2s->ar, username, sess->realm, shash, stoken, &ssequence) == 0) { elem = nad_find_elem(nad, 1, ns, "hash", 1); if(elem >= 0) { snprintf(hash, 41, "%.*s", NAD_CDATA_L(nad, elem), NAD_CDATA(nad, elem)); shahash_r(hash, hash); if(strcmp(hash, shash) == 0) { /* update the auth creds */ ssequence--; /* don't auth them if we can't update their auth creds */ snprintf(str, 41, "%.*s", NAD_CDATA_L(nad, elem), NAD_CDATA(nad, elem)); if((c2s->ar->set_zerok)(c2s->ar, username, sess->realm, str, stoken, ssequence) == 0) { authd = 1; log_debug(ZONE, "zerok auth succeeded"); } else log_debug(ZONE, "couldn't update auth creds, not allowing zerok auth"); } } } /* digest auth */ if(!authd && c2s->ar_mechanisms & AR_MECH_TRAD_DIGEST && c2s->ar->get_password != NULL) { elem = nad_find_elem(nad, 1, ns, "digest", 1); if(elem >= 0) { if((c2s->ar->get_password)(c2s->ar, username, sess->realm, str) == 0) { snprintf(hash, 280, "%s%s", sess->s->id, str); shahash_r(hash, hash); if(strlen(hash) == NAD_CDATA_L(nad, elem) && strncmp(hash, NAD_CDATA(nad, elem), NAD_CDATA_L(nad, elem)) == 0) { log_debug(ZONE, "digest auth succeeded"); authd = 1; } } } } /* plaintext auth (compare) */ if(!authd && c2s->ar_mechanisms & AR_MECH_TRAD_PLAIN && c2s->ar->get_password != NULL) { elem = nad_find_elem(nad, 1, ns, "password", 1); if(elem >= 0) { if((c2s->ar->get_password)(c2s->ar, username, sess->realm, str) == 0 && strlen(str) == NAD_CDATA_L(nad, elem) && strncmp(str, NAD_CDATA(nad, elem), NAD_CDATA_L(nad, elem)) == 0) { log_debug(ZONE, "plaintext auth (compare) succeeded"); authd = 1; } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -