File indexing completed on 2024-05-12 05:22:31

0001 /* Generic SASL plugin utility functions
0002  * Rob Siemborski
0003  */
0004 /*
0005  * Copyright (c) 1998-2016 Carnegie Mellon University.  All rights reserved.
0006  *
0007  * Redistribution and use in source and binary forms, with or without
0008  * modification, are permitted provided that the following conditions
0009  * are met:
0010  *
0011  * 1. Redistributions of source code must retain the above copyright
0012  *    notice, this list of conditions and the following disclaimer.
0013  *
0014  * 2. Redistributions in binary form must reproduce the above copyright
0015  *    notice, this list of conditions and the following disclaimer in
0016  *    the documentation and/or other materials provided with the
0017  *    distribution.
0018  *
0019  * 3. The name "Carnegie Mellon University" must not be used to
0020  *    endorse or promote products derived from this software without
0021  *    prior written permission. For permission or any other legal
0022  *    details, please contact
0023  *      Carnegie Mellon University
0024  *      Center for Technology Transfer and Enterprise Creation
0025  *      4615 Forbes Avenue
0026  *      Suite 302
0027  *      Pittsburgh, PA  15213
0028  *      (412) 268-7393, fax: (412) 268-7395
0029  *      innovation@andrew.cmu.edu
0030  *
0031  * 4. Redistributions of any form whatsoever must retain the following
0032  *    acknowledgment:
0033  *    "This product includes software developed by Computing Services
0034  *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
0035  *
0036  * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
0037  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
0038  * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
0039  * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
0040  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
0041  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
0042  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
0043  */
0044 
0045 #include <config.h>
0046 #ifdef WIN32
0047 #include <versionhelpers.h>
0048 #include <winsock2.h>
0049 #else
0050 #ifndef macintosh
0051 #include <arpa/inet.h>
0052 #include <netdb.h>
0053 #endif /* macintosh */
0054 #include <netinet/in.h>
0055 #include <sys/socket.h>
0056 #include <sys/utsname.h>
0057 #endif /* WIN32 */ 
0058 #ifdef HAVE_UNISTD_H
0059 #include <unistd.h>
0060 #endif
0061 #include <fcntl.h>
0062 #include <sasl/sasl.h>
0063 #include <sasl/saslplug.h>
0064 #include <sasl/saslutil.h>
0065 
0066 #include <ctype.h>
0067 #include <errno.h>
0068 #include <stdio.h>
0069 
0070 #ifdef HAVE_INTTYPES_H
0071 #include <inttypes.h>
0072 #endif
0073 
0074 #include "plugin_common.h"
0075 
0076 /* translate IPv4 mapped IPv6 address to IPv4 address */
0077 static void sockaddr_unmapped(
0078 #ifdef IN6_IS_ADDR_V4MAPPED
0079     struct sockaddr *sa,
0080     socklen_t *len
0081 #else
0082     struct sockaddr *sa __attribute__((unused)),
0083     socklen_t *len __attribute__((unused))
0084 #endif
0085 )
0086 {
0087 #ifdef IN6_IS_ADDR_V4MAPPED
0088     struct sockaddr_in6 *sin6;
0089     struct sockaddr_in *sin4;
0090     uint32_t addr;
0091     int port;
0092 
0093     if (sa->sa_family != AF_INET6)
0094         return;
0095     sin6 = (struct sockaddr_in6 *)sa;
0096     if (!IN6_IS_ADDR_V4MAPPED((&sin6->sin6_addr)))
0097         return;
0098     sin4 = (struct sockaddr_in *)sa;
0099 #ifdef s6_addr32
0100     addr = *(uint32_t *)&sin6->sin6_addr.s6_addr32[3];
0101 #else
0102     memcpy(&addr, &sin6->sin6_addr.s6_addr[12], 4);
0103 #endif
0104     port = sin6->sin6_port;
0105     memset(sin4, 0, sizeof(struct sockaddr_in));
0106     sin4->sin_addr.s_addr = addr;
0107     sin4->sin_port = port;
0108     sin4->sin_family = AF_INET;
0109 #ifdef HAVE_SOCKADDR_SA_LEN
0110     sin4->sin_len = sizeof(struct sockaddr_in);
0111 #endif
0112     *len = sizeof(struct sockaddr_in);
0113 #else
0114     return;
0115 #endif
0116 }
0117 
0118 int _plug_ipfromstring(const sasl_utils_t *utils, const char *addr, struct sockaddr *out, socklen_t outlen)
0119 {
0120     int i, j;
0121     socklen_t len;
0122     struct sockaddr_storage ss;
0123     struct addrinfo hints, *ai = NULL;
0124     char hbuf[NI_MAXHOST];
0125 
0126     if (!utils || !addr || !out) {
0127         if (utils)
0128             PARAMERROR(utils);
0129         return SASL_BADPARAM;
0130     }
0131 
0132     /* Parse the address */
0133     for (i = 0; addr[i] != '\0' && addr[i] != ';'; i++) {
0134         if (i + 1 >= NI_MAXHOST) {
0135             if (utils)
0136                 PARAMERROR(utils);
0137             return SASL_BADPARAM;
0138         }
0139         hbuf[i] = addr[i];
0140     }
0141     hbuf[i] = '\0';
0142 
0143     if (addr[i] == ';')
0144         i++;
0145     /* XXX/FIXME: Do we need this check? */
0146     for (j = i; addr[j] != '\0'; j++)
0147         if (!isdigit((int)(addr[j]))) {
0148             PARAMERROR(utils);
0149             return SASL_BADPARAM;
0150         }
0151 
0152     memset(&hints, 0, sizeof(hints));
0153     hints.ai_family = PF_UNSPEC;
0154     hints.ai_socktype = SOCK_STREAM;
0155     hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
0156 
0157     if (getaddrinfo(hbuf, &addr[i], &hints, &ai) != 0) {
0158         PARAMERROR(utils);
0159         return SASL_BADPARAM;
0160     }
0161 
0162     len = (socklen_t)ai->ai_addrlen;
0163     memcpy(&ss, ai->ai_addr, len);
0164     freeaddrinfo(ai);
0165     sockaddr_unmapped((struct sockaddr *)&ss, &len);
0166     if (outlen < len) {
0167         PARAMERROR(utils);
0168         return SASL_BUFOVER;
0169     }
0170 
0171     memcpy(out, &ss, len);
0172 
0173     return SASL_OK;
0174 }
0175 
0176 int _plug_iovec_to_buf(const sasl_utils_t *utils, const struct iovec *vec, unsigned numiov, buffer_info_t **output)
0177 {
0178     unsigned i;
0179     int ret;
0180     buffer_info_t *out;
0181     char *pos;
0182 
0183     if (!utils || !vec || !output) {
0184         if (utils)
0185             PARAMERROR(utils);
0186         return SASL_BADPARAM;
0187     }
0188 
0189     if (!(*output)) {
0190         *output = utils->malloc(sizeof(buffer_info_t));
0191         if (!*output) {
0192             MEMERROR(utils);
0193             return SASL_NOMEM;
0194         }
0195         memset(*output, 0, sizeof(buffer_info_t));
0196     }
0197 
0198     out = *output;
0199 
0200     out->curlen = 0;
0201     for (i = 0; i < numiov; i++)
0202         out->curlen += vec[i].iov_len;
0203 
0204     ret = _plug_buf_alloc(utils, &out->data, &out->reallen, out->curlen);
0205 
0206     if (ret != SASL_OK) {
0207         MEMERROR(utils);
0208         return SASL_NOMEM;
0209     }
0210 
0211     memset(out->data, 0, out->reallen);
0212     pos = out->data;
0213 
0214     for (i = 0; i < numiov; i++) {
0215         memcpy(pos, vec[i].iov_base, vec[i].iov_len);
0216         pos += vec[i].iov_len;
0217     }
0218 
0219     return SASL_OK;
0220 }
0221 
0222 /* Basically a conditional call to realloc(), if we need more */
0223 int _plug_buf_alloc(const sasl_utils_t *utils, char **rwbuf, unsigned *curlen, unsigned newlen)
0224 {
0225     if (!utils || !rwbuf || !curlen) {
0226         if (utils)
0227             PARAMERROR(utils);
0228         return SASL_BADPARAM;
0229     }
0230 
0231     if (!(*rwbuf)) {
0232         *rwbuf = utils->malloc(newlen);
0233         if (*rwbuf == NULL) {
0234             *curlen = 0;
0235             MEMERROR(utils);
0236             return SASL_NOMEM;
0237         }
0238         *curlen = newlen;
0239     } else if (*rwbuf && *curlen < newlen) {
0240         unsigned needed = 2 * (*curlen);
0241 
0242         while (needed < newlen)
0243             needed *= 2;
0244 
0245         *rwbuf = utils->realloc(*rwbuf, needed);
0246         if (*rwbuf == NULL) {
0247             *curlen = 0;
0248             MEMERROR(utils);
0249             return SASL_NOMEM;
0250         }
0251         *curlen = needed;
0252     }
0253 
0254     return SASL_OK;
0255 }
0256 
0257 /* copy a string */
0258 int _plug_strdup(const sasl_utils_t *utils, const char *in, char **out, int *outlen)
0259 {
0260     size_t len = 0;
0261 
0262     if (!utils || !in || !out) {
0263         if (utils)
0264             PARAMERROR(utils);
0265         return SASL_BADPARAM;
0266     }
0267 
0268     len = strlen(in);
0269 
0270     *out = utils->malloc(len + 1);
0271     if (!*out) {
0272         MEMERROR(utils);
0273         return SASL_NOMEM;
0274     }
0275 
0276     strcpy((char *)*out, in);
0277 
0278     if (outlen)
0279         *outlen = (int)len;
0280 
0281     return SASL_OK;
0282 }
0283 
0284 void _plug_free_string(const sasl_utils_t *utils, char **str)
0285 {
0286     size_t len;
0287 
0288     if (!utils || !str || !(*str))
0289         return;
0290 
0291     len = strlen(*str);
0292 
0293     utils->erasebuffer(*str, (unsigned int)len);
0294     utils->free(*str);
0295 
0296     *str = NULL;
0297 }
0298 
0299 void _plug_free_secret(const sasl_utils_t *utils, sasl_secret_t **secret)
0300 {
0301     if (!utils || !secret || !(*secret))
0302         return;
0303 
0304     utils->erasebuffer((char *)(*secret)->data, (*secret)->len);
0305     utils->free(*secret);
0306     *secret = NULL;
0307 }
0308 
0309 /*
0310  * Trys to find the prompt with the lookingfor id in the prompt list
0311  * Returns it if found. NULL otherwise
0312  */
0313 sasl_interact_t *_plug_find_prompt(sasl_interact_t **promptlist, unsigned int lookingfor)
0314 {
0315     sasl_interact_t *prompt;
0316 
0317     if (promptlist && *promptlist) {
0318         for (prompt = *promptlist; prompt->id != SASL_CB_LIST_END; ++prompt) {
0319             if (prompt->id == lookingfor)
0320                 return prompt;
0321         }
0322     }
0323 
0324     return NULL;
0325 }
0326 
0327 /*
0328  * Retrieve the simple string given by the callback id.
0329  */
0330 int _plug_get_simple(const sasl_utils_t *utils, unsigned int id, int required, const char **result, sasl_interact_t **prompt_need)
0331 {
0332     int ret = SASL_FAIL;
0333     sasl_getsimple_t *simple_cb;
0334     void *simple_context;
0335     sasl_interact_t *prompt;
0336 
0337     *result = NULL;
0338 
0339     /* see if we were given the result in the prompt */
0340     prompt = _plug_find_prompt(prompt_need, id);
0341     if (prompt != NULL) {
0342         /* We prompted, and got.*/
0343 
0344         if (required && !prompt->result) {
0345             SETERROR(utils, "Unexpectedly missing a prompt result in _plug_get_simple");
0346             return SASL_BADPARAM;
0347         }
0348 
0349         *result = prompt->result;
0350         return SASL_OK;
0351     }
0352 
0353     /* Try to get the callback... */
0354     ret = utils->getcallback(utils->conn, id, (sasl_callback_ft *)&simple_cb, &simple_context);
0355 
0356     if (ret == SASL_FAIL && !required)
0357         return SASL_OK;
0358 
0359     if (ret == SASL_OK && simple_cb) {
0360         ret = simple_cb(simple_context, id, result, NULL);
0361         if (ret != SASL_OK)
0362             return ret;
0363 
0364         if (required && !*result) {
0365             PARAMERROR(utils);
0366             return SASL_BADPARAM;
0367         }
0368     }
0369 
0370     return ret;
0371 }
0372 
0373 /*
0374  * Retrieve the user password.
0375  */
0376 int _plug_get_password(const sasl_utils_t *utils, sasl_secret_t **password, unsigned int *iscopy, sasl_interact_t **prompt_need)
0377 {
0378     int ret = SASL_FAIL;
0379     sasl_getsecret_t *pass_cb;
0380     void *pass_context;
0381     sasl_interact_t *prompt;
0382 
0383     *password = NULL;
0384     *iscopy = 0;
0385 
0386     /* see if we were given the password in the prompt */
0387     prompt = _plug_find_prompt(prompt_need, SASL_CB_PASS);
0388     if (prompt != NULL) {
0389         /* We prompted, and got.*/
0390 
0391         if (!prompt->result) {
0392             SETERROR(utils, "Unexpectedly missing a prompt result in _plug_get_password");
0393             return SASL_BADPARAM;
0394         }
0395 
0396         /* copy what we got into a secret_t */
0397         *password = (sasl_secret_t *)utils->malloc(sizeof(sasl_secret_t) + prompt->len + 1);
0398         if (!*password) {
0399             MEMERROR(utils);
0400             return SASL_NOMEM;
0401         }
0402 
0403         (*password)->len = prompt->len;
0404         memcpy((*password)->data, prompt->result, prompt->len);
0405         (*password)->data[(*password)->len] = 0;
0406 
0407         *iscopy = 1;
0408 
0409         return SASL_OK;
0410     }
0411 
0412     /* Try to get the callback... */
0413     ret = utils->getcallback(utils->conn, SASL_CB_PASS, (sasl_callback_ft *)&pass_cb, &pass_context);
0414 
0415     if (ret == SASL_OK && pass_cb) {
0416         ret = pass_cb(utils->conn, pass_context, SASL_CB_PASS, password);
0417         if (ret != SASL_OK)
0418             return ret;
0419 
0420         if (!*password) {
0421             PARAMERROR(utils);
0422             return SASL_BADPARAM;
0423         }
0424     }
0425 
0426     return ret;
0427 }
0428 
0429 /*
0430  * Retrieve the string given by the challenge prompt id.
0431  */
0432 int _plug_challenge_prompt(const sasl_utils_t *utils,
0433                            unsigned int id,
0434                            const char *challenge,
0435                            const char *promptstr,
0436                            const char **result,
0437                            sasl_interact_t **prompt_need)
0438 {
0439     int ret = SASL_FAIL;
0440     sasl_chalprompt_t *chalprompt_cb;
0441     void *chalprompt_context;
0442     sasl_interact_t *prompt;
0443 
0444     *result = NULL;
0445 
0446     /* see if we were given the password in the prompt */
0447     prompt = _plug_find_prompt(prompt_need, id);
0448     if (prompt != NULL) {
0449         /* We prompted, and got.*/
0450 
0451         if (!prompt->result) {
0452             SETERROR(utils, "Unexpectedly missing a prompt result in _plug_challenge_prompt");
0453             return SASL_BADPARAM;
0454         }
0455 
0456         *result = prompt->result;
0457         return SASL_OK;
0458     }
0459 
0460     /* Try to get the callback... */
0461     ret = utils->getcallback(utils->conn, id, (sasl_callback_ft *)&chalprompt_cb, &chalprompt_context);
0462 
0463     if (ret == SASL_OK && chalprompt_cb) {
0464         ret = chalprompt_cb(chalprompt_context, id, challenge, promptstr, NULL, result, NULL);
0465         if (ret != SASL_OK)
0466             return ret;
0467 
0468         if (!*result) {
0469             PARAMERROR(utils);
0470             return SASL_BADPARAM;
0471         }
0472     }
0473 
0474     return ret;
0475 }
0476 
0477 /*
0478  * Retrieve the client realm.
0479  */
0480 int _plug_get_realm(const sasl_utils_t *utils, const char **availrealms, const char **realm, sasl_interact_t **prompt_need)
0481 {
0482     int ret = SASL_FAIL;
0483     sasl_getrealm_t *realm_cb;
0484     void *realm_context;
0485     sasl_interact_t *prompt;
0486 
0487     *realm = NULL;
0488 
0489     /* see if we were given the result in the prompt */
0490     prompt = _plug_find_prompt(prompt_need, SASL_CB_GETREALM);
0491     if (prompt != NULL) {
0492         /* We prompted, and got.*/
0493 
0494         if (!prompt->result) {
0495             SETERROR(utils, "Unexpectedly missing a prompt result in _plug_get_realm");
0496             return SASL_BADPARAM;
0497         }
0498 
0499         *realm = prompt->result;
0500         return SASL_OK;
0501     }
0502 
0503     /* Try to get the callback... */
0504     ret = utils->getcallback(utils->conn, SASL_CB_GETREALM, (sasl_callback_ft *)&realm_cb, &realm_context);
0505 
0506     if (ret == SASL_OK && realm_cb) {
0507         ret = realm_cb(realm_context, SASL_CB_GETREALM, availrealms, realm);
0508         if (ret != SASL_OK)
0509             return ret;
0510 
0511         if (!*realm) {
0512             PARAMERROR(utils);
0513             return SASL_BADPARAM;
0514         }
0515     }
0516 
0517     return ret;
0518 }
0519 
0520 /*
0521  * Make the requested prompts. (prompt==NULL means we don't want it)
0522  */
0523 int _plug_make_prompts(const sasl_utils_t *utils,
0524                        sasl_interact_t **prompts_res,
0525                        const char *user_prompt,
0526                        const char *user_def,
0527                        const char *auth_prompt,
0528                        const char *auth_def,
0529                        const char *pass_prompt,
0530                        const char *pass_def,
0531                        const char *echo_chal,
0532                        const char *echo_prompt,
0533                        const char *echo_def,
0534                        const char *realm_chal,
0535                        const char *realm_prompt,
0536                        const char *realm_def)
0537 {
0538     int num = 1;
0539     int alloc_size;
0540     sasl_interact_t *prompts;
0541 
0542     if (user_prompt)
0543         num++;
0544     if (auth_prompt)
0545         num++;
0546     if (pass_prompt)
0547         num++;
0548     if (echo_prompt)
0549         num++;
0550     if (realm_prompt)
0551         num++;
0552 
0553     if (num == 1) {
0554         SETERROR(utils, "make_prompts() called with no actual prompts");
0555         return SASL_FAIL;
0556     }
0557 
0558     alloc_size = sizeof(sasl_interact_t) * num;
0559     prompts = utils->malloc(alloc_size);
0560     if (!prompts) {
0561         MEMERROR(utils);
0562         return SASL_NOMEM;
0563     }
0564     memset(prompts, 0, alloc_size);
0565 
0566     *prompts_res = prompts;
0567 
0568     if (user_prompt) {
0569         (prompts)->id = SASL_CB_USER;
0570         (prompts)->challenge = "Authorization Name";
0571         (prompts)->prompt = user_prompt;
0572         (prompts)->defresult = user_def;
0573 
0574         prompts++;
0575     }
0576 
0577     if (auth_prompt) {
0578         (prompts)->id = SASL_CB_AUTHNAME;
0579         (prompts)->challenge = "Authentication Name";
0580         (prompts)->prompt = auth_prompt;
0581         (prompts)->defresult = auth_def;
0582 
0583         prompts++;
0584     }
0585 
0586     if (pass_prompt) {
0587         (prompts)->id = SASL_CB_PASS;
0588         (prompts)->challenge = "Password";
0589         (prompts)->prompt = pass_prompt;
0590         (prompts)->defresult = pass_def;
0591 
0592         prompts++;
0593     }
0594 
0595     if (echo_prompt) {
0596         (prompts)->id = SASL_CB_ECHOPROMPT;
0597         (prompts)->challenge = echo_chal;
0598         (prompts)->prompt = echo_prompt;
0599         (prompts)->defresult = echo_def;
0600 
0601         prompts++;
0602     }
0603 
0604     if (realm_prompt) {
0605         (prompts)->id = SASL_CB_GETREALM;
0606         (prompts)->challenge = realm_chal;
0607         (prompts)->prompt = realm_prompt;
0608         (prompts)->defresult = realm_def;
0609 
0610         prompts++;
0611     }
0612 
0613     /* add the ending one */
0614     (prompts)->id = SASL_CB_LIST_END;
0615     (prompts)->challenge = NULL;
0616     (prompts)->prompt = NULL;
0617     (prompts)->defresult = NULL;
0618 
0619     return SASL_OK;
0620 }
0621 
0622 void _plug_decode_init(decode_context_t *text, const sasl_utils_t *utils, unsigned int in_maxbuf)
0623 {
0624     memset(text, 0, sizeof(decode_context_t));
0625 
0626     text->utils = utils;
0627     text->needsize = 4;
0628     text->in_maxbuf = in_maxbuf;
0629 }
0630 
0631 /*
0632  * Decode as much of the input as possible (possibly none),
0633  * using decode_pkt() to decode individual packets.
0634  */
0635 int _plug_decode(decode_context_t *text,
0636                  const char *input,
0637                  unsigned inputlen,
0638                  char **output, /* output buffer */
0639                  unsigned *outputsize, /* current size of output buffer */
0640                  unsigned *outputlen, /* length of data in output buffer */
0641                  int (*decode_pkt)(void *rock, const char *input, unsigned inputlen, char **output, unsigned *outputlen),
0642                  void *rock)
0643 {
0644     unsigned int tocopy;
0645     unsigned diff;
0646     char *tmp;
0647     unsigned tmplen;
0648     int ret;
0649 
0650     *outputlen = 0;
0651 
0652     while (inputlen) { /* more input */
0653         if (text->needsize) { /* need to get the rest of the 4-byte size */
0654 
0655             /* copy as many bytes (up to 4) as we have into size buffer */
0656             tocopy = (inputlen > text->needsize) ? text->needsize : inputlen;
0657             memcpy(text->sizebuf + 4 - text->needsize, input, tocopy);
0658             text->needsize -= tocopy;
0659 
0660             input += tocopy;
0661             inputlen -= tocopy;
0662 
0663             if (!text->needsize) { /* we have the entire 4-byte size */
0664                 memcpy(&(text->size), text->sizebuf, 4);
0665                 text->size = ntohl(text->size);
0666 
0667                 if (!text->size) /* should never happen */
0668                     return SASL_FAIL;
0669 
0670                 if (text->size > text->in_maxbuf) {
0671                     text->utils->log(NULL, SASL_LOG_ERR, "encoded packet size too big (%d > %d)", text->size, text->in_maxbuf);
0672                     return SASL_FAIL;
0673                 }
0674 
0675                 if (!text->buffer)
0676                     text->buffer = text->utils->malloc(text->in_maxbuf);
0677                 if (text->buffer == NULL)
0678                     return SASL_NOMEM;
0679 
0680                 text->cursize = 0;
0681             } else {
0682                 /* We do NOT have the entire 4-byte size...
0683                  * wait for more data */
0684                 return SASL_OK;
0685             }
0686         }
0687 
0688         diff = text->size - text->cursize; /* bytes needed for full packet */
0689 
0690         if (inputlen < diff) { /* not a complete packet, need more input */
0691             memcpy(text->buffer + text->cursize, input, inputlen);
0692             text->cursize += inputlen;
0693             return SASL_OK;
0694         }
0695 
0696         /* copy the rest of the packet */
0697         memcpy(text->buffer + text->cursize, input, diff);
0698         input += diff;
0699         inputlen -= diff;
0700 
0701         /* decode the packet (no need to free tmp) */
0702         ret = decode_pkt(rock, text->buffer, text->size, &tmp, &tmplen);
0703         if (ret != SASL_OK)
0704             return ret;
0705 
0706         /* append the decoded packet to the output */
0707         ret = _plug_buf_alloc(text->utils, output, outputsize, *outputlen + tmplen + 1); /* +1 for NUL */
0708         if (ret != SASL_OK)
0709             return ret;
0710 
0711         memcpy(*output + *outputlen, tmp, tmplen);
0712         *outputlen += tmplen;
0713 
0714         /* protect stupid clients */
0715         *(*output + *outputlen) = '\0';
0716 
0717         /* reset for the next packet */
0718         text->needsize = 4;
0719     }
0720 
0721     return SASL_OK;
0722 }
0723 
0724 void _plug_decode_free(decode_context_t *text)
0725 {
0726     if (text->buffer)
0727         text->utils->free(text->buffer);
0728 }
0729 
0730 /* returns the realm we should pretend to be in */
0731 int _plug_parseuser(const sasl_utils_t *utils, char **user, char **realm, const char *user_realm, const char *serverFQDN, const char *input)
0732 {
0733     int ret;
0734     char *r;
0735 
0736     if (!user || !serverFQDN) {
0737         PARAMERROR(utils);
0738         return SASL_BADPARAM;
0739     }
0740 
0741     r = strchr(input, '@');
0742     if (!r) {
0743         /* hmmm, the user didn't specify a realm */
0744         if (user_realm && user_realm[0]) {
0745             ret = _plug_strdup(utils, user_realm, realm, NULL);
0746         } else {
0747             /* Default to serverFQDN */
0748             ret = _plug_strdup(utils, serverFQDN, realm, NULL);
0749         }
0750 
0751         if (ret == SASL_OK) {
0752             ret = _plug_strdup(utils, input, user, NULL);
0753         }
0754     } else {
0755         r++;
0756         ret = _plug_strdup(utils, r, realm, NULL);
0757         *--r = '\0';
0758         *user = utils->malloc(r - input + 1);
0759         if (*user) {
0760             strncpy(*user, input, r - input + 1);
0761         } else {
0762             MEMERROR(utils);
0763             ret = SASL_NOMEM;
0764         }
0765         *r = '@';
0766     }
0767 
0768     return ret;
0769 }
0770 
0771 int _plug_make_fulluser(const sasl_utils_t *utils, char **fulluser, const char *useronly, const char *realm)
0772 {
0773     if (!fulluser || !useronly || !realm) {
0774         PARAMERROR(utils);
0775         return (SASL_BADPARAM);
0776     }
0777 
0778     *fulluser = utils->malloc(strlen(useronly) + strlen(realm) + 2);
0779     if (*fulluser == NULL) {
0780         MEMERROR(utils);
0781         return (SASL_NOMEM);
0782     }
0783 
0784     strcpy(*fulluser, useronly);
0785     strcat(*fulluser, "@");
0786     strcat(*fulluser, realm);
0787 
0788     return (SASL_OK);
0789 }
0790 
0791 char *_plug_get_error_message(const sasl_utils_t *utils,
0792 #ifdef WIN32
0793                               DWORD error
0794 #else
0795                               int error
0796 #endif
0797 )
0798 {
0799     char *return_value;
0800 #ifdef WIN32
0801     LPVOID lpMsgBuf;
0802 
0803     FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
0804                   NULL,
0805                   error,
0806                   MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */
0807                   (LPTSTR)&lpMsgBuf,
0808                   0,
0809                   NULL);
0810 
0811     if (_plug_strdup(utils, lpMsgBuf, &return_value, NULL) != SASL_OK) {
0812         return_value = NULL;
0813     }
0814 
0815     LocalFree(lpMsgBuf);
0816 #else /* !WIN32 */
0817     if (_plug_strdup(utils, strerror(error), &return_value, NULL) != SASL_OK) {
0818         return_value = NULL;
0819     }
0820 #endif /* WIN32 */
0821     return (return_value);
0822 }
0823 
0824 void _plug_snprintf_os_info(char *osbuf, int osbuf_len)
0825 {
0826 #ifdef WIN32
0827     char *sysname;
0828     sysname = "Unknown Windows";
0829 
0830 /* Let's suppose it's still compilable with win2k sdk. So define everythig missing */
0831 #ifndef _WIN32_WINNT_WINXP
0832 #define _WIN32_WINNT_WINXP 0x0501
0833 #endif
0834 #ifndef _WIN32_WINNT_WS03
0835 #define _WIN32_WINNT_WS03 0x0502
0836 #endif
0837 #ifndef _WIN32_WINNT_WIN6
0838 #define _WIN32_WINNT_WIN6 0x0600
0839 #endif
0840 #ifndef _WIN32_WINNT_VISTA
0841 #define _WIN32_WINNT_VISTA 0x0600
0842 #endif
0843 #ifndef _WIN32_WINNT_WS08
0844 #define _WIN32_WINNT_WS08 0x0600
0845 #endif
0846 #ifndef _WIN32_WINNT_LONGHORN
0847 #define _WIN32_WINNT_LONGHORN 0x0600
0848 #endif
0849 #ifndef _WIN32_WINNT_WIN7
0850 #define _WIN32_WINNT_WIN7 0x0601
0851 #endif
0852 #ifndef _WIN32_WINNT_WIN8
0853 #define _WIN32_WINNT_WIN8 0x0602
0854 #endif
0855 #ifndef _WIN32_WINNT_WINBLUE
0856 #define _WIN32_WINNT_WINBLUE 0x0603
0857 #endif
0858 #ifndef _WIN32_WINNT_WIN10
0859 #define _WIN32_WINNT_WIN10 0x0A00
0860 #endif
0861 
0862     /* and use IsWindowsVersionOrGreater instead of convenient wrappers by the same reason */
0863     if (IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN10), LOBYTE(_WIN32_WINNT_WIN10), 0)) {
0864         sysname = "Windows 10 or greater";
0865     } else if (IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINBLUE), LOBYTE(_WIN32_WINNT_WINBLUE), 0)) {
0866         sysname = "Windows 8.1";
0867     } else if (IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN8), LOBYTE(_WIN32_WINNT_WIN8), 0)) {
0868         sysname = "Windows 8";
0869     } else if (IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN7), LOBYTE(_WIN32_WINNT_WIN7), 1)) {
0870         sysname = "Windows 7 SP1";
0871     } else if (IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN7), LOBYTE(_WIN32_WINNT_WIN7), 0)) {
0872         sysname = "Windows 7";
0873     } else if (IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA), LOBYTE(_WIN32_WINNT_VISTA), 2)) {
0874         sysname = "Windows Vista SP2";
0875     } else if (IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA), LOBYTE(_WIN32_WINNT_VISTA), 1)) {
0876         sysname = "Windows Vista SP1";
0877     } else if (IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA), LOBYTE(_WIN32_WINNT_VISTA), 0)) {
0878         sysname = "Windows Vista";
0879     } else if (IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP), LOBYTE(_WIN32_WINNT_WINXP), 3)) {
0880         sysname = "Windows XP SP3";
0881     } else if (IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP), LOBYTE(_WIN32_WINNT_WINXP), 2)) {
0882         sysname = "Windows XP SP2";
0883     } else if (IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP), LOBYTE(_WIN32_WINNT_WINXP), 1)) {
0884         sysname = "Windows XP SP1";
0885     } else if (IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP), LOBYTE(_WIN32_WINNT_WINXP), 0)) {
0886         sysname = "Windows XP";
0887     }
0888 
0889     snprintf(osbuf, osbuf_len, "%s", sysname);
0890 
0891 #else /* !WIN32 */
0892     struct utsname os;
0893 
0894     uname(&os);
0895     snprintf(osbuf, osbuf_len, "%s %s", os.sysname, os.release);
0896 #endif /* WIN32 */
0897 }
0898 
0899 #if defined(WIN32)
0900 unsigned int plug_sleep(unsigned int seconds)
0901 {
0902     long dwSec = seconds * 1000;
0903     Sleep(dwSec);
0904     return 0;
0905 }
0906 #endif