1#include "portable.h" 2#include <stdio.h> 3#include <string.h> //used for strcpy, etc. 4#include <stdlib.h> //used for malloc 5#include <stdarg.h> 6#include <errno.h> 7 8#include <unistd.h> 9 10#include <syslog.h> 11 12#include "psauth.h" 13#include <sasl.h> 14#include "saslutil.h" 15#include "saslplug.h" 16#include <lber.h> 17#include "slap.h" 18 19#undef calloc 20#undef free 21 22/* In sasl.c */ 23extern int slap_sasl_log( void *context, int priority, const char *message); 24extern int slap_sasl_getopt( void *context, const char *plugin_name, const char *option, const char **result, unsigned *len); 25extern int pws_auxprop_init( const sasl_utils_t *utils, int max_version, int *out_version, sasl_auxprop_plug_t **plug, const char *plugname); 26static const char *slap_propnames[] = { 27 "*slapConn", "*slapAuthcDNlen", "*slapAuthcDN", 28 "*slapAuthzDNlen", "*slapAuthzDN", NULL }; 29#define SLAP_SASL_PROP_CONN 0 30#define SLAP_SASL_PROP_AUTHCLEN 1 31#define SLAP_SASL_PROP_AUTHC 2 32#define SLAP_SASL_PROP_AUTHZLEN 3 33#define SLAP_SASL_PROP_AUTHZ 4 34#define SLAP_SASL_PROP_COUNT 5 /* Number of properties we used */ 35 36typedef struct sSASLContext { 37 sasl_secret_t *secret; 38 char username[35]; 39} sSASLContext; 40 41typedef struct sSASLCanonCtx { 42 Connection *conn; 43 const char *dn; 44} sSASLCanonCtx; 45 46int getrealm(void *context /*__attribute__((unused))*/, 47 int id, 48 const char **availrealms, 49 const char **result); 50int ol_simple(void *context /*__attribute__((unused))*/, 51 int id, 52 const char **result, 53 unsigned *len); 54int 55ol_getsecret(sasl_conn_t *conn, 56 void *context /*__attribute__((unused))*/, 57 int id, 58 sasl_secret_t **psecret); 59 60//------------- 61int getrealm(void *context /*__attribute__((unused))*/, 62 int id, 63 const char **availrealms, 64 const char **result) 65{ 66 /* paranoia check */ 67 if (id != SASL_CB_GETREALM) return SASL_BADPARAM; 68 if (!result) return SASL_BADPARAM; 69 70 if ( availrealms ) { 71 *result = *availrealms; 72 } 73 74 return SASL_OK; 75} 76 77int ol_simple(void *context /*__attribute__((unused))*/, 78 int id, 79 const char **result, 80 unsigned *len) 81{ 82#ifdef DEBUG_PRINTFS 83 printf("in simple\n"); 84#endif 85 86 /* paranoia check */ 87 if (! result) 88 return SASL_BADPARAM; 89 90 switch (id) { 91 case SASL_CB_USER: 92 case SASL_CB_AUTHNAME: 93 //printf("please enter an authorization id: "); 94 *result = ((sSASLContext *)context)->username; 95 if (len != NULL) 96 *len = strlen(((sSASLContext *)context)->username); 97#ifdef DEBUG_PRINTFS 98 printf("simple - user = %s (len = %d)\n", *result, *len); 99#endif 100 break; 101 102 default: 103 return SASL_BADPARAM; 104 } 105 106 return SASL_OK; 107} 108 109 110int 111ol_getsecret(sasl_conn_t *conn, 112 void *context /*__attribute__((unused))*/, 113 int id, 114 sasl_secret_t **psecret) 115{ 116#ifdef DEBUG_PRINTFS 117 printf("in getsecret\n"); 118#endif 119 /* paranoia check */ 120 if (! conn || ! psecret || id != SASL_CB_PASS) 121 return SASL_BADPARAM; 122 123 *psecret = ((sSASLContext *)context)->secret; 124 return SASL_OK; 125} 126 127int CheckAuthType(char* inAuthAuthorityData, char* authType) 128{ 129 char* temp; 130 temp = strchr(inAuthAuthorityData, ';'); 131 return ((temp != NULL) && (strncmp(temp+1, authType, strlen(authType)) == 0)); 132} 133 134int 135pws_canonicalize( 136 sasl_conn_t *sconn, 137 void *context, 138 const char *in, 139 unsigned inlen, 140 unsigned flags, 141 const char *user_realm, 142 char *out, 143 unsigned out_max, 144 unsigned *out_len) 145{ 146 sSASLCanonCtx *ctx = (sSASLCanonCtx*)context; 147 struct propctx *props = sasl_auxprop_getctx( sconn ); 148 struct propval auxvals[ SLAP_SASL_PROP_COUNT ] = { { 0 } }; 149 const char *names[2]; 150 ber_len_t blen; 151 152 prop_getnames(props, slap_propnames, auxvals); 153 if(!auxvals[0].name) 154 prop_request(props, slap_propnames); 155 156 names[0] = slap_propnames[SLAP_SASL_PROP_CONN]; 157 names[1] = NULL; 158 prop_set(props, names[0], (char*)&ctx->conn, sizeof(ctx->conn)); 159 160 names[0] = slap_propnames[SLAP_SASL_PROP_AUTHCLEN]; 161 162 blen = strlen(ctx->dn); 163 prop_set(props, names[0], (char*)&blen, sizeof(blen)); 164 165 names[0] = slap_propnames[SLAP_SASL_PROP_AUTHC]; 166 prop_set(props, names[0], ctx->dn, blen); 167 168 if(out_max < (inlen+1)) return SASL_BADPARAM; 169 memcpy(out, in, inlen); 170 out[inlen] = '\0'; 171 *out_len = inlen; 172 return SASL_OK; 173} 174 175int DoPSAuth(char* userName, char* password, char* inAuthAuthorityData, Connection* conn, const char* dn) 176{ 177 int result = -1; 178 sasl_conn_t *client_conn; 179 sasl_security_properties_t secprops = {0,65535,4096,0,NULL,NULL}; 180 sasl_callback_t callbacks[5]; 181 const char *data = NULL; 182 unsigned int len = 0; 183 const char *chosenmech = NULL; 184 sSASLContext saslContext; 185 sasl_conn_t *server_conn = NULL; 186 const char *serverOut = NULL; 187 unsigned int serverOutLen = 0; 188 sasl_security_properties_t server_secprops = {0, 65536, 4096, SASL_SEC_NOPLAINTEXT, NULL, NULL}; 189 static sasl_callback_t server_callbacks[] = { 190 { SASL_CB_LOG, &slap_sasl_log, NULL }, 191 { SASL_CB_GETOPT, &slap_sasl_getopt, NULL }, 192 { SASL_CB_LIST_END, NULL, NULL } 193 }; 194 sasl_callback_t server_session_callbacks[5]; 195 struct propctx *props = NULL; 196 struct propval auxvals[SLAP_SASL_PROP_COUNT] = {{0}}; 197 const char *names[2]; 198 ber_len_t blen; 199 sSASLCanonCtx canonctx; 200 201 canonctx.conn = conn; 202 canonctx.dn = dn; 203 204 /* server session callbacks */ 205 server_session_callbacks[0].id = SASL_CB_LOG; 206 server_session_callbacks[0].proc = &slap_sasl_log; 207 server_session_callbacks[0].context = conn; 208 server_session_callbacks[1].id = SASL_CB_CANON_USER; 209 server_session_callbacks[1].proc = &pws_canonicalize; 210 server_session_callbacks[1].context = &canonctx; 211 server_session_callbacks[2].id = SASL_CB_LIST_END; 212 server_session_callbacks[2].proc = NULL; 213 server_session_callbacks[2].context = NULL; 214 215 memset(&saslContext, 0, sizeof(saslContext)); 216 strncpy(saslContext.username, userName, 35); 217 saslContext.secret = (sasl_secret_t*)calloc(1, sizeof(sasl_secret_t) + strlen(password) + 1); 218 saslContext.secret->len = strlen(password); 219 strcpy((char*)saslContext.secret->data, password); 220 221 /* client side callbacks */ 222 callbacks[0].id = SASL_CB_GETREALM; 223 callbacks[0].proc = &getrealm; 224 callbacks[0].context = &saslContext; 225 226 callbacks[1].id = SASL_CB_USER; 227 callbacks[1].proc = &ol_simple; 228 callbacks[1].context = &saslContext; 229 230 callbacks[2].id = SASL_CB_AUTHNAME; 231 callbacks[2].proc = &ol_simple; 232 callbacks[2].context = &saslContext; 233 234 callbacks[3].id = SASL_CB_PASS; 235 callbacks[3].proc = &ol_getsecret; 236 callbacks[3].context = &saslContext; 237 238 callbacks[4].id = SASL_CB_LIST_END; 239 callbacks[4].proc = NULL; 240 callbacks[4].context = NULL; 241 242 result = sasl_client_init(NULL); 243 if(result != SASL_OK) { 244 syslog(LOG_ERR, "sasl_client_init returned: %d", result); 245 goto out; 246 } 247 248 result = sasl_client_new("slapd", "localhost", NULL, NULL, callbacks, 0, &client_conn); 249 if ( result != SASL_OK ) { 250 syslog(LOG_ERR, "sasl_client_new returned: %d", result); 251 goto out; 252 } 253 254 result = sasl_setprop(client_conn, SASL_SEC_PROPS, &secprops); 255 256 result = sasl_client_start(client_conn, "CRAM-MD5", NULL, &data, &len, &chosenmech); 257 if(result != SASL_CONTINUE) { 258 syslog(LOG_ERR, "sasl_client_start returned: %d", result); 259 goto out; 260 } 261 262 result = sasl_auxprop_add_plugin( "appleldap", pws_auxprop_init ); 263 if( result != SASL_OK ) { 264 syslog(LOG_ERR, "sasl_auxprop_add_plugin returned: %d", result); 265 goto out; 266 } 267 268 result = sasl_set_path(SASL_PATH_TYPE_PLUGIN, "/usr/lib/sasl2/openldap"); 269 if(result != SASL_OK) { 270 syslog(LOG_ERR, "sasl_set_path returned: %d", result); 271 goto out; 272 } 273 274 result = sasl_server_init(server_callbacks, "slapd"); 275 if(result != SASL_OK) { 276 syslog(LOG_ERR, "sasl_server_init_alt returned: %d", result); 277 goto out; 278 } 279 280 result = sasl_server_new("slapd", "localhost", NULL, NULL, NULL, server_session_callbacks, SASL_SUCCESS_DATA, &server_conn); 281 if(result != SASL_OK) { 282 syslog(LOG_ERR, "sasl_server_new returned: %d", result); 283 goto out; 284 } 285 286 result = sasl_setprop(server_conn, SASL_SEC_PROPS, &server_secprops); 287 288 result = sasl_server_start(server_conn, "CRAM-MD5", data, len, &serverOut, &serverOutLen); 289 if(result != SASL_CONTINUE) { 290 syslog(LOG_ERR, "sasl_server_start returned: %d", result); 291 goto out; 292 } 293 294 result = sasl_client_step(client_conn, serverOut, serverOutLen, NULL, &data, &len); 295 if(result != SASL_OK) { 296 syslog(LOG_ERR, "sasl_client_step returned: %d", result); 297 goto out; 298 } 299 300 result = sasl_server_step(server_conn, data, len, &serverOut, &serverOutLen); 301 302out: 303 if(client_conn) sasl_dispose(&client_conn); 304 if(server_conn) sasl_dispose(&server_conn); 305 if(saslContext.secret) free(saslContext.secret); 306 307 return result; 308} 309