1 /* Generic SASL plugin utility functions
2  * Rob Siemborski
3  */
4 /*
5  * Copyright (c) 1998-2016 Carnegie Mellon University.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  *
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in
16  *    the documentation and/or other materials provided with the
17  *    distribution.
18  *
19  * 3. The name "Carnegie Mellon University" must not be used to
20  *    endorse or promote products derived from this software without
21  *    prior written permission. For permission or any other legal
22  *    details, please contact
23  *      Carnegie Mellon University
24  *      Center for Technology Transfer and Enterprise Creation
25  *      4615 Forbes Avenue
26  *      Suite 302
27  *      Pittsburgh, PA  15213
28  *      (412) 268-7393, fax: (412) 268-7395
29  *      innovation@andrew.cmu.edu
30  *
31  * 4. Redistributions of any form whatsoever must retain the following
32  *    acknowledgment:
33  *    "This product includes software developed by Computing Services
34  *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
35  *
36  * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
37  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
38  * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
39  * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
40  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
41  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
42  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
43  */
44 
45 #include <config.h>
46 #ifndef macintosh
47 #ifdef WIN32
48 # include <winsock2.h>
49 # include <versionhelpers.h>
50 #else
51 # include <sys/socket.h>
52 # include <netinet/in.h>
53 # include <arpa/inet.h>
54 # include <netdb.h>
55 # include <sys/utsname.h>
56 #endif /* WIN32 */
57 #endif /* macintosh */
58 #ifdef HAVE_UNISTD_H
59 #include <unistd.h>
60 #endif
61 #include <fcntl.h>
62 #include <sasl.h>
63 #include <saslutil.h>
64 #include <saslplug.h>
65 
66 #include <errno.h>
67 #include <ctype.h>
68 #include <stdio.h>
69 
70 #ifdef HAVE_INTTYPES_H
71 #include <inttypes.h>
72 #endif
73 
74 #include "plugin_common.h"
75 
76 /* translate IPv4 mapped IPv6 address to IPv4 address */
sockaddr_unmapped(struct sockaddr * sa,socklen_t * len)77 static void sockaddr_unmapped(
78 #ifdef IN6_IS_ADDR_V4MAPPED
79   struct sockaddr *sa, socklen_t *len
80 #else
81   struct sockaddr *sa __attribute__((unused)),
82   socklen_t *len __attribute__((unused))
83 #endif
84 )
85 {
86 #ifdef IN6_IS_ADDR_V4MAPPED
87     struct sockaddr_in6 *sin6;
88     struct sockaddr_in *sin4;
89     uint32_t addr;
90     int port;
91 
92     if (sa->sa_family != AF_INET6)
93 	return;
94     sin6 = (struct sockaddr_in6 *)sa;
95     if (!IN6_IS_ADDR_V4MAPPED((&sin6->sin6_addr)))
96 	return;
97     sin4 = (struct sockaddr_in *)sa;
98 #ifdef s6_addr32
99     addr = *(uint32_t *)&sin6->sin6_addr.s6_addr32[3];
100 #else
101     memcpy(&addr, &sin6->sin6_addr.s6_addr[12], 4);
102 #endif
103     port = sin6->sin6_port;
104     memset(sin4, 0, sizeof(struct sockaddr_in));
105     sin4->sin_addr.s_addr = addr;
106     sin4->sin_port = port;
107     sin4->sin_family = AF_INET;
108 #ifdef HAVE_SOCKADDR_SA_LEN
109     sin4->sin_len = sizeof(struct sockaddr_in);
110 #endif
111     *len = sizeof(struct sockaddr_in);
112 #else
113     return;
114 #endif
115 }
116 
_plug_ipfromstring(const sasl_utils_t * utils,const char * addr,struct sockaddr * out,socklen_t outlen)117 int _plug_ipfromstring(const sasl_utils_t *utils, const char *addr,
118 		       struct sockaddr *out, socklen_t outlen)
119 {
120     int i, j;
121     socklen_t len;
122     struct sockaddr_storage ss;
123     struct addrinfo hints, *ai = NULL;
124     char hbuf[NI_MAXHOST];
125 
126     if(!utils || !addr || !out) {
127 	if(utils) PARAMERROR( utils );
128 	return SASL_BADPARAM;
129     }
130 
131     /* Parse the address */
132     for (i = 0; addr[i] != '\0' && addr[i] != ';'; i++) {
133 	if (i + 1 >= NI_MAXHOST) {
134 	    if(utils) PARAMERROR( utils );
135 	    return SASL_BADPARAM;
136 	}
137 	hbuf[i] = addr[i];
138     }
139     hbuf[i] = '\0';
140 
141     if (addr[i] == ';')
142 	i++;
143     /* XXX/FIXME: Do we need this check? */
144     for (j = i; addr[j] != '\0'; j++)
145 	if (!isdigit((int)(addr[j]))) {
146 	    PARAMERROR( utils );
147 	    return SASL_BADPARAM;
148 	}
149 
150     memset(&hints, 0, sizeof(hints));
151     hints.ai_family = PF_UNSPEC;
152     hints.ai_socktype = SOCK_STREAM;
153     hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
154 
155     if (getaddrinfo(hbuf, &addr[i], &hints, &ai) != 0) {
156 	PARAMERROR( utils );
157 	return SASL_BADPARAM;
158     }
159 
160     len = (socklen_t) ai->ai_addrlen;
161     memcpy(&ss, ai->ai_addr, len);
162     freeaddrinfo(ai);
163     sockaddr_unmapped((struct sockaddr *)&ss, &len);
164     if (outlen < len) {
165 	PARAMERROR( utils );
166 	return SASL_BUFOVER;
167     }
168 
169     memcpy(out, &ss, len);
170 
171     return SASL_OK;
172 }
173 
_plug_iovec_to_buf(const sasl_utils_t * utils,const struct iovec * vec,unsigned numiov,buffer_info_t ** output)174 int _plug_iovec_to_buf(const sasl_utils_t *utils, const struct iovec *vec,
175 		       unsigned numiov, buffer_info_t **output)
176 {
177     unsigned i;
178     int ret;
179     buffer_info_t *out;
180     char *pos;
181 
182     if(!utils || !vec || !output) {
183 	if(utils) PARAMERROR( utils );
184 	return SASL_BADPARAM;
185     }
186 
187     if(!(*output)) {
188 	*output = utils->malloc(sizeof(buffer_info_t));
189 	if(!*output) {
190 	    MEMERROR(utils);
191 	    return SASL_NOMEM;
192 	}
193 	memset(*output,0,sizeof(buffer_info_t));
194     }
195 
196     out = *output;
197 
198     out->curlen = 0;
199     for(i=0; i<numiov; i++)
200 	out->curlen += vec[i].iov_len;
201 
202     ret = _plug_buf_alloc(utils, &out->data, &out->reallen, out->curlen);
203 
204     if(ret != SASL_OK) {
205 	MEMERROR(utils);
206 	return SASL_NOMEM;
207     }
208 
209     memset(out->data, 0, out->reallen);
210     pos = out->data;
211 
212     for(i=0; i<numiov; i++) {
213 	memcpy(pos, vec[i].iov_base, vec[i].iov_len);
214 	pos += vec[i].iov_len;
215     }
216 
217     return SASL_OK;
218 }
219 
220 /* Basically a conditional call to realloc(), if we need more */
_plug_buf_alloc(const sasl_utils_t * utils,char ** rwbuf,unsigned * curlen,unsigned newlen)221 int _plug_buf_alloc(const sasl_utils_t *utils, char **rwbuf,
222 		    unsigned *curlen, unsigned newlen)
223 {
224     if(!utils || !rwbuf || !curlen) {
225 	if (utils) PARAMERROR(utils);
226 	return SASL_BADPARAM;
227     }
228 
229     if(!(*rwbuf)) {
230 	*rwbuf = utils->malloc(newlen);
231 	if (*rwbuf == NULL) {
232 	    *curlen = 0;
233 	    MEMERROR(utils);
234 	    return SASL_NOMEM;
235 	}
236 	*curlen = newlen;
237     } else if(*rwbuf && *curlen < newlen) {
238 	unsigned needed = 2*(*curlen);
239 
240 	while(needed < newlen)
241 	    needed *= 2;
242 
243 	*rwbuf = utils->realloc(*rwbuf, needed);
244 	if (*rwbuf == NULL) {
245 	    *curlen = 0;
246 	    MEMERROR(utils);
247 	    return SASL_NOMEM;
248 	}
249 	*curlen = needed;
250     }
251 
252     return SASL_OK;
253 }
254 
255 /* copy a string */
_plug_strdup(const sasl_utils_t * utils,const char * in,char ** out,int * outlen)256 int _plug_strdup(const sasl_utils_t * utils, const char *in,
257 		 char **out, int *outlen)
258 {
259   size_t len = 0;
260 
261   if(!utils || !in || !out) {
262       if(utils) PARAMERROR(utils);
263       return SASL_BADPARAM;
264   }
265 
266   len = strlen(in);
267 
268   *out = utils->malloc(len + 1);
269   if (!*out) {
270       MEMERROR(utils);
271       return SASL_NOMEM;
272   }
273 
274   strcpy((char *) *out, in);
275 
276   if (outlen)
277       *outlen = (int) len;
278 
279   return SASL_OK;
280 }
281 
_plug_free_string(const sasl_utils_t * utils,char ** str)282 void _plug_free_string(const sasl_utils_t *utils, char **str)
283 {
284   size_t len;
285 
286   if (!utils || !str || !(*str)) return;
287 
288   len = strlen(*str);
289 
290   utils->erasebuffer(*str, (unsigned int) len);
291   utils->free(*str);
292 
293   *str=NULL;
294 }
295 
_plug_free_secret(const sasl_utils_t * utils,sasl_secret_t ** secret)296 void _plug_free_secret(const sasl_utils_t *utils, sasl_secret_t **secret)
297 {
298     if(!utils || !secret || !(*secret)) return;
299 
300     utils->erasebuffer((char *)(*secret)->data, (*secret)->len);
301     utils->free(*secret);
302     *secret = NULL;
303 }
304 
305 /*
306  * Trys to find the prompt with the lookingfor id in the prompt list
307  * Returns it if found. NULL otherwise
308  */
_plug_find_prompt(sasl_interact_t ** promptlist,unsigned int lookingfor)309 sasl_interact_t *_plug_find_prompt(sasl_interact_t **promptlist,
310 				   unsigned int lookingfor)
311 {
312     sasl_interact_t *prompt;
313 
314     if (promptlist && *promptlist) {
315 	for (prompt = *promptlist; prompt->id != SASL_CB_LIST_END; ++prompt) {
316 	    if (prompt->id==lookingfor)
317 		return prompt;
318 	}
319     }
320 
321     return NULL;
322 }
323 
324 /*
325  * Retrieve the simple string given by the callback id.
326  */
_plug_get_simple(const sasl_utils_t * utils,unsigned int id,int required,const char ** result,sasl_interact_t ** prompt_need)327 int _plug_get_simple(const sasl_utils_t *utils, unsigned int id, int required,
328 		     const char **result, sasl_interact_t **prompt_need)
329 {
330 
331     int ret = SASL_FAIL;
332     sasl_getsimple_t *simple_cb;
333     void *simple_context;
334     sasl_interact_t *prompt;
335 
336     *result = NULL;
337 
338     /* see if we were given the result in the prompt */
339     prompt = _plug_find_prompt(prompt_need, id);
340     if (prompt != NULL) {
341 	/* We prompted, and got.*/
342 
343 	if (required && !prompt->result) {
344 	    SETERROR(utils, "Unexpectedly missing a prompt result in _plug_get_simple");
345 	    return SASL_BADPARAM;
346 	}
347 
348 	*result = prompt->result;
349 	return SASL_OK;
350     }
351 
352     /* Try to get the callback... */
353     ret = utils->getcallback(utils->conn, id, (sasl_callback_ft *)&simple_cb, &simple_context);
354 
355     if (ret == SASL_FAIL && !required)
356 	return SASL_OK;
357 
358     if (ret == SASL_OK && simple_cb) {
359 	ret = simple_cb(simple_context, id, result, NULL);
360 	if (ret != SASL_OK)
361 	    return ret;
362 
363 	if (required && !*result) {
364 	    PARAMERROR(utils);
365 	    return SASL_BADPARAM;
366 	}
367     }
368 
369     return ret;
370 }
371 
372 /*
373  * Retrieve the user password.
374  */
_plug_get_password(const sasl_utils_t * utils,sasl_secret_t ** password,unsigned int * iscopy,sasl_interact_t ** prompt_need)375 int _plug_get_password(const sasl_utils_t *utils, sasl_secret_t **password,
376 		       unsigned int *iscopy, sasl_interact_t **prompt_need)
377 {
378     int ret = SASL_FAIL;
379     sasl_getsecret_t *pass_cb;
380     void *pass_context;
381     sasl_interact_t *prompt;
382 
383     *password = NULL;
384     *iscopy = 0;
385 
386     /* see if we were given the password in the prompt */
387     prompt = _plug_find_prompt(prompt_need, SASL_CB_PASS);
388     if (prompt != NULL) {
389 	/* We prompted, and got.*/
390 
391 	if (!prompt->result) {
392 	    SETERROR(utils, "Unexpectedly missing a prompt result in _plug_get_password");
393 	    return SASL_BADPARAM;
394 	}
395 
396 	/* copy what we got into a secret_t */
397 	*password = (sasl_secret_t *) utils->malloc(sizeof(sasl_secret_t) +
398 						    prompt->len + 1);
399 	if (!*password) {
400 	    MEMERROR(utils);
401 	    return SASL_NOMEM;
402 	}
403 
404 	(*password)->len=prompt->len;
405 	memcpy((*password)->data, prompt->result, prompt->len);
406 	(*password)->data[(*password)->len]=0;
407 
408 	*iscopy = 1;
409 
410 	return SASL_OK;
411     }
412 
413     /* Try to get the callback... */
414     ret = utils->getcallback(utils->conn, SASL_CB_PASS,
415 			     (sasl_callback_ft *)&pass_cb, &pass_context);
416 
417     if (ret == SASL_OK && pass_cb) {
418 	ret = pass_cb(utils->conn, pass_context, SASL_CB_PASS, password);
419 	if (ret != SASL_OK)
420 	    return ret;
421 
422 	if (!*password) {
423 	    PARAMERROR(utils);
424 	    return SASL_BADPARAM;
425 	}
426     }
427 
428     return ret;
429 }
430 
431 /*
432  * Retrieve the string given by the challenge prompt id.
433  */
_plug_challenge_prompt(const sasl_utils_t * utils,unsigned int id,const char * challenge,const char * promptstr,const char ** result,sasl_interact_t ** prompt_need)434 int _plug_challenge_prompt(const sasl_utils_t *utils, unsigned int id,
435 			   const char *challenge, const char *promptstr,
436 			   const char **result, sasl_interact_t **prompt_need)
437 {
438     int ret = SASL_FAIL;
439     sasl_chalprompt_t *chalprompt_cb;
440     void *chalprompt_context;
441     sasl_interact_t *prompt;
442 
443     *result = NULL;
444 
445     /* see if we were given the password in the prompt */
446     prompt = _plug_find_prompt(prompt_need, id);
447     if (prompt != NULL) {
448 	/* We prompted, and got.*/
449 
450 	if (!prompt->result) {
451 	    SETERROR(utils, "Unexpectedly missing a prompt result in _plug_challenge_prompt");
452 	    return SASL_BADPARAM;
453 	}
454 
455 	*result = prompt->result;
456 	return SASL_OK;
457     }
458 
459     /* Try to get the callback... */
460     ret = utils->getcallback(utils->conn, id,
461 			     (sasl_callback_ft *)&chalprompt_cb, &chalprompt_context);
462 
463     if (ret == SASL_OK && chalprompt_cb) {
464 	ret = chalprompt_cb(chalprompt_context, id,
465 			    challenge, promptstr, NULL, result, NULL);
466 	if (ret != SASL_OK)
467 	    return ret;
468 
469 	if (!*result) {
470 	    PARAMERROR(utils);
471 	    return SASL_BADPARAM;
472 	}
473     }
474 
475     return ret;
476 }
477 
478 /*
479  * Retrieve the client realm.
480  */
_plug_get_realm(const sasl_utils_t * utils,const char ** availrealms,const char ** realm,sasl_interact_t ** prompt_need)481 int _plug_get_realm(const sasl_utils_t *utils, const char **availrealms,
482 		    const char **realm, sasl_interact_t **prompt_need)
483 {
484     int ret = SASL_FAIL;
485     sasl_getrealm_t *realm_cb;
486     void *realm_context;
487     sasl_interact_t *prompt;
488 
489     *realm = NULL;
490 
491     /* see if we were given the result in the prompt */
492     prompt = _plug_find_prompt(prompt_need, SASL_CB_GETREALM);
493     if (prompt != NULL) {
494 	/* We prompted, and got.*/
495 
496 	if (!prompt->result) {
497 	    SETERROR(utils, "Unexpectedly missing a prompt result in _plug_get_realm");
498 	    return SASL_BADPARAM;
499 	}
500 
501 	*realm = prompt->result;
502 	return SASL_OK;
503     }
504 
505     /* Try to get the callback... */
506     ret = utils->getcallback(utils->conn, SASL_CB_GETREALM,
507 			     (sasl_callback_ft *)&realm_cb, &realm_context);
508 
509     if (ret == SASL_OK && realm_cb) {
510 	ret = realm_cb(realm_context, SASL_CB_GETREALM, availrealms, realm);
511 	if (ret != SASL_OK)
512 	    return ret;
513 
514 	if (!*realm) {
515 	    PARAMERROR(utils);
516 	    return SASL_BADPARAM;
517 	}
518     }
519 
520     return ret;
521 }
522 
523 /*
524  * Make the requested prompts. (prompt==NULL means we don't want it)
525  */
_plug_make_prompts(const sasl_utils_t * utils,sasl_interact_t ** prompts_res,const char * user_prompt,const char * user_def,const char * auth_prompt,const char * auth_def,const char * pass_prompt,const char * pass_def,const char * echo_chal,const char * echo_prompt,const char * echo_def,const char * realm_chal,const char * realm_prompt,const char * realm_def)526 int _plug_make_prompts(const sasl_utils_t *utils,
527 		       sasl_interact_t **prompts_res,
528 		       const char *user_prompt, const char *user_def,
529 		       const char *auth_prompt, const char *auth_def,
530 		       const char *pass_prompt, const char *pass_def,
531 		       const char *echo_chal,
532 		       const char *echo_prompt, const char *echo_def,
533 		       const char *realm_chal,
534 		       const char *realm_prompt, const char *realm_def)
535 {
536     int num = 1;
537     int alloc_size;
538     sasl_interact_t *prompts;
539 
540     if (user_prompt) num++;
541     if (auth_prompt) num++;
542     if (pass_prompt) num++;
543     if (echo_prompt) num++;
544     if (realm_prompt) num++;
545 
546     if (num == 1) {
547 	SETERROR( utils, "make_prompts() called with no actual prompts" );
548 	return SASL_FAIL;
549     }
550 
551     alloc_size = sizeof(sasl_interact_t)*num;
552     prompts = utils->malloc(alloc_size);
553     if (!prompts) {
554 	MEMERROR( utils );
555 	return SASL_NOMEM;
556     }
557     memset(prompts, 0, alloc_size);
558 
559     *prompts_res = prompts;
560 
561     if (user_prompt) {
562 	(prompts)->id = SASL_CB_USER;
563 	(prompts)->challenge = "Authorization Name";
564 	(prompts)->prompt = user_prompt;
565 	(prompts)->defresult = user_def;
566 
567 	prompts++;
568     }
569 
570     if (auth_prompt) {
571 	(prompts)->id = SASL_CB_AUTHNAME;
572 	(prompts)->challenge = "Authentication Name";
573 	(prompts)->prompt = auth_prompt;
574 	(prompts)->defresult = auth_def;
575 
576 	prompts++;
577     }
578 
579     if (pass_prompt) {
580 	(prompts)->id = SASL_CB_PASS;
581 	(prompts)->challenge = "Password";
582 	(prompts)->prompt = pass_prompt;
583 	(prompts)->defresult = pass_def;
584 
585 	prompts++;
586     }
587 
588     if (echo_prompt) {
589 	(prompts)->id = SASL_CB_ECHOPROMPT;
590 	(prompts)->challenge = echo_chal;
591 	(prompts)->prompt = echo_prompt;
592 	(prompts)->defresult = echo_def;
593 
594 	prompts++;
595     }
596 
597     if (realm_prompt) {
598 	(prompts)->id = SASL_CB_GETREALM;
599 	(prompts)->challenge = realm_chal;
600 	(prompts)->prompt = realm_prompt;
601 	(prompts)->defresult = realm_def;
602 
603 	prompts++;
604     }
605 
606     /* add the ending one */
607     (prompts)->id = SASL_CB_LIST_END;
608     (prompts)->challenge = NULL;
609     (prompts)->prompt = NULL;
610     (prompts)->defresult = NULL;
611 
612     return SASL_OK;
613 }
614 
_plug_decode_init(decode_context_t * text,const sasl_utils_t * utils,unsigned int in_maxbuf)615 void _plug_decode_init(decode_context_t *text,
616 		       const sasl_utils_t *utils, unsigned int in_maxbuf)
617 {
618     memset(text, 0, sizeof(decode_context_t));
619 
620     text->utils = utils;
621     text->needsize = 4;
622     text->in_maxbuf = in_maxbuf;
623 }
624 
625 /*
626  * Decode as much of the input as possible (possibly none),
627  * using decode_pkt() to decode individual packets.
628  */
_plug_decode(decode_context_t * text,const char * input,unsigned inputlen,char ** output,unsigned * outputsize,unsigned * outputlen,int (* decode_pkt)(void * rock,const char * input,unsigned inputlen,char ** output,unsigned * outputlen),void * rock)629 int _plug_decode(decode_context_t *text,
630 		 const char *input, unsigned inputlen,
631 		 char **output,		/* output buffer */
632 		 unsigned *outputsize,	/* current size of output buffer */
633 		 unsigned *outputlen,	/* length of data in output buffer */
634 		 int (*decode_pkt)(void *rock,
635 				   const char *input, unsigned inputlen,
636 				   char **output, unsigned *outputlen),
637 		 void *rock)
638 {
639     unsigned int tocopy;
640     unsigned diff;
641     char *tmp;
642     unsigned tmplen;
643     int ret;
644 
645     *outputlen = 0;
646 
647     while (inputlen) { /* more input */
648 	if (text->needsize) { /* need to get the rest of the 4-byte size */
649 
650 	    /* copy as many bytes (up to 4) as we have into size buffer */
651 	    tocopy = (inputlen > text->needsize) ? text->needsize : inputlen;
652 	    memcpy(text->sizebuf + 4 - text->needsize, input, tocopy);
653 	    text->needsize -= tocopy;
654 
655 	    input += tocopy;
656 	    inputlen -= tocopy;
657 
658 	    if (!text->needsize) { /* we have the entire 4-byte size */
659 		memcpy(&(text->size), text->sizebuf, 4);
660 		text->size = ntohl(text->size);
661 		text->cursize = 0;
662 	    } else {
663 		/* We do NOT have the entire 4-byte size...
664 		 * wait for more data */
665 		return SASL_OK;
666 	    }
667 	}
668 
669 	if (!text->size) /* should never happen */
670 	    return SASL_FAIL;
671 
672 	if (text->size > text->in_maxbuf) {
673 	    text->utils->log(NULL, SASL_LOG_ERR,
674 			     "encoded packet size too big (%d > %d)",
675 			     text->size, text->in_maxbuf);
676 	    return SASL_FAIL;
677 	}
678 
679 	if (!text->buffer) {
680 	    text->buffer = text->utils->malloc(text->in_maxbuf);
681 	    if (text->buffer == NULL) return SASL_NOMEM;
682 	}
683 
684 	diff = text->size - text->cursize; /* bytes needed for full packet */
685 
686 	if (inputlen < diff) {	/* not a complete packet, need more input */
687 	    memcpy(text->buffer + text->cursize, input, inputlen);
688 	    text->cursize += inputlen;
689 	    return SASL_OK;
690 	}
691 
692 	/* copy the rest of the packet */
693 	memcpy(text->buffer + text->cursize, input, diff);
694 	input += diff;
695 	inputlen -= diff;
696 
697 	/* decode the packet (no need to free tmp) */
698 	ret = decode_pkt(rock, text->buffer, text->size, &tmp, &tmplen);
699 	if (ret != SASL_OK) return ret;
700 
701 	/* append the decoded packet to the output */
702 	ret = _plug_buf_alloc(text->utils, output, outputsize,
703 			      *outputlen + tmplen + 1); /* +1 for NUL */
704 	if (ret != SASL_OK) return ret;
705 
706 	memcpy(*output + *outputlen, tmp, tmplen);
707 	*outputlen += tmplen;
708 
709 	/* protect stupid clients */
710 	*(*output + *outputlen) = '\0';
711 
712 	/* reset for the next packet */
713 	text->needsize = 4;
714     }
715 
716     return SASL_OK;
717 }
718 
_plug_decode_free(decode_context_t * text)719 void _plug_decode_free(decode_context_t *text)
720 {
721     if (text->buffer) text->utils->free(text->buffer);
722 }
723 
724 /* returns the realm we should pretend to be in */
_plug_parseuser(const sasl_utils_t * utils,char ** user,char ** realm,const char * user_realm,const char * serverFQDN,const char * input)725 int _plug_parseuser(const sasl_utils_t *utils,
726 		    char **user, char **realm, const char *user_realm,
727 		    const char *serverFQDN, const char *input)
728 {
729     int ret;
730     char *r;
731 
732     if(!user || !serverFQDN) {
733 	PARAMERROR( utils );
734 	return SASL_BADPARAM;
735     }
736 
737     r = strchr(input, '@');
738     if (!r) {
739 	/* hmmm, the user didn't specify a realm */
740 	if(user_realm && user_realm[0]) {
741 	    ret = _plug_strdup(utils, user_realm, realm, NULL);
742 	} else {
743 	    /* Default to serverFQDN */
744 	    ret = _plug_strdup(utils, serverFQDN, realm, NULL);
745 	}
746 
747 	if (ret == SASL_OK) {
748 	    ret = _plug_strdup(utils, input, user, NULL);
749 	}
750     } else {
751 	r++;
752 	ret = _plug_strdup(utils, r, realm, NULL);
753 	*--r = '\0';
754 	*user = utils->malloc(r - input + 1);
755 	if (*user) {
756 	    strncpy(*user, input, r - input +1);
757 	} else {
758 	    MEMERROR( utils );
759 	    ret = SASL_NOMEM;
760 	}
761 	*r = '@';
762     }
763 
764     return ret;
765 }
766 
_plug_make_fulluser(const sasl_utils_t * utils,char ** fulluser,const char * useronly,const char * realm)767 int _plug_make_fulluser(const sasl_utils_t *utils,
768 			char **fulluser,
769 			const char * useronly,
770 			const char *realm)
771 {
772     if(!fulluser || !useronly || !realm) {
773 	PARAMERROR( utils );
774 	return (SASL_BADPARAM);
775     }
776 
777     *fulluser = utils->malloc (strlen(useronly) + strlen(realm) + 2);
778     if (*fulluser == NULL) {
779 	MEMERROR( utils );
780 	return (SASL_NOMEM);
781     }
782 
783     strcpy (*fulluser, useronly);
784     strcat (*fulluser, "@");
785     strcat (*fulluser, realm);
786 
787     return (SASL_OK);
788 }
789 
_plug_get_error_message(const sasl_utils_t * utils,DWORD error)790 char * _plug_get_error_message (const sasl_utils_t *utils,
791 #ifdef WIN32
792 				DWORD error
793 #else
794 				int error
795 #endif
796 				)
797 {
798     char * return_value;
799 #ifdef WIN32
800     LPVOID lpMsgBuf;
801 
802     FormatMessage(
803 	FORMAT_MESSAGE_ALLOCATE_BUFFER |
804 	FORMAT_MESSAGE_FROM_SYSTEM |
805 	FORMAT_MESSAGE_IGNORE_INSERTS,
806 	NULL,
807 	error,
808 	MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */
809 	(LPTSTR) &lpMsgBuf,
810 	0,
811 	NULL
812     );
813 
814     if (_plug_strdup (utils, lpMsgBuf, &return_value, NULL) != SASL_OK) {
815 	return_value = NULL;
816     }
817 
818     LocalFree( lpMsgBuf );
819 #else /* !WIN32 */
820     if (_plug_strdup (utils, strerror(error), &return_value, NULL) != SASL_OK) {
821 	return_value = NULL;
822     }
823 #endif /* WIN32 */
824     return (return_value);
825 }
826 
_plug_snprintf_os_info(char * osbuf,int osbuf_len)827 void _plug_snprintf_os_info (char * osbuf, int osbuf_len)
828 {
829 #ifdef WIN32
830     char *sysname;
831     sysname = "Unknown Windows";
832 
833 /* Let's suppose it's still compilable with win2k sdk. So define everythig missing */
834 #ifndef _WIN32_WINNT_WINXP
835 # define _WIN32_WINNT_WINXP                  0x0501
836 #endif
837 #ifndef _WIN32_WINNT_WS03
838 # define _WIN32_WINNT_WS03                   0x0502
839 #endif
840 #ifndef _WIN32_WINNT_WIN6
841 # define _WIN32_WINNT_WIN6                   0x0600
842 #endif
843 #ifndef _WIN32_WINNT_VISTA
844 # define _WIN32_WINNT_VISTA                  0x0600
845 #endif
846 #ifndef _WIN32_WINNT_WS08
847 # define _WIN32_WINNT_WS08                   0x0600
848 #endif
849 #ifndef _WIN32_WINNT_LONGHORN
850 # define _WIN32_WINNT_LONGHORN               0x0600
851 #endif
852 #ifndef _WIN32_WINNT_WIN7
853 # define _WIN32_WINNT_WIN7                   0x0601
854 #endif
855 #ifndef _WIN32_WINNT_WIN8
856 # define _WIN32_WINNT_WIN8                   0x0602
857 #endif
858 #ifndef _WIN32_WINNT_WINBLUE
859 # define _WIN32_WINNT_WINBLUE                0x0603
860 #endif
861 #ifndef _WIN32_WINNT_WIN10
862 # define _WIN32_WINNT_WIN10                  0x0A00
863 #endif
864 
865     /* and use IsWindowsVersionOrGreater instead of convenient wrappers by the same reason */
866     if (IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN10), LOBYTE(_WIN32_WINNT_WIN10), 0)) {
867         sysname = "Windows 10 or greater";
868     } else
869     if (IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINBLUE), LOBYTE(_WIN32_WINNT_WINBLUE), 0)) {
870         sysname = "Windows 8.1";
871     } else
872     if (IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN8), LOBYTE(_WIN32_WINNT_WIN8), 0)) {
873         sysname = "Windows 8";
874     } else
875     if (IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN7), LOBYTE(_WIN32_WINNT_WIN7), 1)) {
876         sysname = "Windows 7 SP1";
877     } else
878     if (IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN7), LOBYTE(_WIN32_WINNT_WIN7), 0)) {
879         sysname = "Windows 7";
880     } else
881     if (IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA), LOBYTE(_WIN32_WINNT_VISTA), 2)) {
882         sysname = "Windows Vista SP2";
883     } else
884     if (IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA), LOBYTE(_WIN32_WINNT_VISTA), 1)) {
885         sysname = "Windows Vista SP1";
886     } else
887     if (IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA), LOBYTE(_WIN32_WINNT_VISTA), 0)) {
888         sysname = "Windows Vista";
889     } else
890     if (IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP), LOBYTE(_WIN32_WINNT_WINXP), 3)) {
891         sysname = "Windows XP SP3";
892     } else
893     if (IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP), LOBYTE(_WIN32_WINNT_WINXP), 2)) {
894         sysname = "Windows XP SP2";
895     } else
896     if (IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP), LOBYTE(_WIN32_WINNT_WINXP), 1)) {
897         sysname = "Windows XP SP1";
898     } else
899     if (IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP), LOBYTE(_WIN32_WINNT_WINXP), 0)) {
900         sysname = "Windows XP";
901     }
902 
903 	snprintf(osbuf, osbuf_len, "%s", sysname);
904 
905 #else /* !WIN32 */
906     struct utsname os;
907 
908     uname(&os);
909     snprintf(osbuf, osbuf_len, "%s %s", os.sysname, os.release);
910 #endif /* WIN32 */
911 }
912 
913 #if defined(WIN32)
plug_sleep(unsigned int seconds)914 unsigned int plug_sleep (unsigned int seconds)
915 {
916     long dwSec = seconds*1000;
917     Sleep (dwSec);
918     return 0;
919 }
920 #endif
921