"Fossies" - the Fresh Open Source Software Archive

Member "smbnetfs-0.6.3/src/smb_conn_srv.c" (2 Mar 2019, 40451 Bytes) of package /linux/misc/smbnetfs-0.6.3.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "smb_conn_srv.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 0.6.1_vs_0.6.2.

    1 #include "config.h"
    2 #include <errno.h>
    3 #include <stdio.h>
    4 #include <iconv.h>
    5 #include <string.h>
    6 #include <stdlib.h>
    7 #include <stdarg.h>
    8 #include <unistd.h>
    9 #include <sys/uio.h>
   10 #include <sys/mman.h>
   11 #include <sys/select.h>
   12 #include <libsmbclient.h>
   13 
   14 #include "charset.h"
   15 #include "smb_conn_proto.h"
   16 #include "smb_conn_srv.h"
   17 
   18 void smb_conn_srv_debug_print(struct smb_conn_srv_ctx *ctx,
   19                 enum smb_conn_cmd msg_type,
   20                 int errno_value,
   21                 int level, int no_fallback,
   22                 const char *fmt, ...){
   23 
   24     static char         buf[COMM_BUF_SIZE];
   25     ssize_t         bytes;
   26     va_list         ap;
   27 
   28     if (ctx == NULL) goto fallback;
   29     if ((msg_type != MESSAGE) && (msg_type != DIE_MSG)) return;
   30     if (level > ctx->debug_level) return;
   31 
   32     bytes = sizeof(buf) - sizeof(struct smb_conn_reply_hdr) -
   33         sizeof(struct smb_conn_message_req) - 1;
   34     if (bytes <= 0) goto fallback;
   35 
   36     va_start(ap, fmt);
   37     vsnprintf(buf, (size_t) bytes, fmt, ap);
   38     buf[bytes] = '\0';
   39     va_end(ap);
   40 
   41     if (smb_conn_srv_send_msg(ctx, msg_type,
   42             errno_value, level, buf) == 0) return;
   43 
   44   fallback:
   45     if (no_fallback) return;
   46     va_start(ap, fmt);
   47     vfprintf(stderr, fmt, ap);
   48     fflush(stderr);
   49     va_end(ap);
   50 }
   51 
   52 static void smb_conn_srv_auth_fn(SMBCCTX *ctx,
   53         const char  *server,
   54         const char  *share,
   55         char        *wrkgrp, int wrkgrplen,
   56         char        *user,   int userlen,
   57         char        *passwd, int passwdlen){
   58 
   59     static char         buf[COMM_BUF_SIZE];
   60     static char         charset_buf[CHARSET_BUF_SIZE];
   61     struct smb_conn_srv_ctx *srv_ctx;
   62     int             retval;
   63     ssize_t         bytes;
   64     fd_set          readfds, exceptfds;
   65     struct timeval      tv;
   66     struct iovec        iov[4];
   67     struct smb_conn_reply_hdr   reply_header;
   68     struct smb_conn_passwd_req  reply;
   69     struct smb_conn_query_hdr   *query_hdr;
   70     struct smb_conn_passwd  *passwd_hdr;
   71     const char          *domain, *username, *password;
   72 
   73     srv_ctx = NULL;
   74 
   75     if (ctx == NULL) goto error;
   76     if ((srv_ctx = smbc_getOptionUserData(ctx)) == NULL) goto error;
   77     if ((server = charset_smb2local_r(server,
   78         charset_buf, sizeof(charset_buf))) == NULL) goto error;
   79     if ((server = strdup(server)) == NULL) goto error;
   80     if ((share  = charset_smb2local_r(share,
   81         charset_buf, sizeof(charset_buf))) == NULL) goto error;
   82 
   83     iov[0].iov_base = &reply_header;
   84     iov[0].iov_len  = sizeof(reply_header);
   85     iov[1].iov_base = &reply;
   86     iov[1].iov_len  = sizeof(reply);
   87     iov[2].iov_base = (char *) server;
   88     iov[2].iov_len  = strlen(server) + 1;
   89     iov[3].iov_base = (char *) share;
   90     iov[3].iov_len  = strlen(share) + 1;
   91 
   92     reply_header.reply_len   = iov[0].iov_len + iov[1].iov_len +
   93                    iov[2].iov_len + iov[3].iov_len;
   94     reply_header.reply_cmd   = PASSWORD;
   95     reply_header.errno_value = 0;
   96     reply.server_offs        = sizeof(reply);
   97     reply.share_offs         = sizeof(reply) + iov[2].iov_len;
   98 
   99     if (reply_header.reply_len > COMM_BUF_SIZE) goto error;
  100 
  101     /* send password request */
  102     bytes = writev(srv_ctx->conn_fd, iov, 4);
  103     if (bytes != (ssize_t) reply_header.reply_len) goto error;
  104 
  105     tv.tv_sec = srv_ctx->timeout;
  106     tv.tv_usec = 0;
  107 
  108     FD_ZERO(&readfds);
  109     FD_SET(srv_ctx->conn_fd, &readfds);
  110 
  111     FD_ZERO(&exceptfds);
  112     FD_SET(srv_ctx->conn_fd, &exceptfds);
  113 
  114     /* wait for password */
  115     retval = select(srv_ctx->conn_fd + 1, &readfds, NULL, &exceptfds, &tv);
  116     if ((retval <= 0) || FD_ISSET(srv_ctx->conn_fd, &exceptfds)) goto error;
  117 
  118     /* read password data */
  119     bytes = read(srv_ctx->conn_fd, buf, COMM_BUF_SIZE);
  120     if (buf[bytes - 1] != '\0' ) goto error;
  121     if (bytes < (ssize_t) sizeof(struct smb_conn_query_hdr)) goto error;
  122 
  123     /* check query */
  124     query_hdr = (struct smb_conn_query_hdr *) buf;
  125     if (bytes != (ssize_t) query_hdr->query_len) goto error;
  126     if (query_hdr->query_cmd != PASSWORD) goto error;
  127 
  128     bytes -= sizeof(struct smb_conn_query_hdr);
  129     if (bytes < (ssize_t) sizeof(struct smb_conn_passwd)) goto error;
  130 
  131     /* process password */
  132     passwd_hdr = (struct smb_conn_passwd *) (query_hdr + 1);
  133     if ((passwd_hdr->domain_offs   != sizeof(struct smb_conn_passwd)) ||
  134     (passwd_hdr->username_offs <= passwd_hdr->domain_offs) ||
  135     (passwd_hdr->password_offs <= passwd_hdr->username_offs) ||
  136     ((ssize_t) passwd_hdr->password_offs >  bytes - 1)) goto error;
  137     bytes -= sizeof(struct smb_conn_passwd);
  138 
  139     domain = smb_conn_srv_get_url_from_query(passwd_hdr,
  140             passwd_hdr->domain_offs);
  141     username = smb_conn_srv_get_url_from_query(passwd_hdr,
  142             passwd_hdr->username_offs);
  143     password = smb_conn_srv_get_url_from_query(passwd_hdr,
  144             passwd_hdr->password_offs);
  145     if (bytes != (ssize_t) (strlen(domain) + strlen(username) +
  146          strlen(password) + 3)) goto error;
  147 
  148     if (*domain != '\0'){
  149     strncpy(wrkgrp, domain, wrkgrplen);
  150     wrkgrp[wrkgrplen - 1] = '\0';
  151     }
  152     strncpy(user,   username, userlen); user[userlen - 1] = '\0';
  153     strncpy(passwd, password, passwdlen); passwd[passwdlen - 1] = '\0';
  154     DSRVPRINTF(srv_ctx, 6, "url=smb://%s/%s, grp=%s, user=%s, passwd=%s\n",
  155             server, share, wrkgrp, user, "********");
  156     free((char *) server);
  157     return;
  158 
  159   error:
  160     DSRVDIEMSG(srv_ctx, errno, "errno=%d, %s\n", errno, strerror(errno));
  161     exit(EXIT_FAILURE);
  162 }
  163 
  164 static void smb_conn_srv_samba_init(struct smb_conn_srv_ctx *srv_ctx){
  165     SMBCCTX *ctx;
  166 
  167     if ((ctx = smbc_new_context()) == NULL) goto error;
  168     smbc_setTimeout(ctx, srv_ctx->smb_timeout);
  169     smbc_setDebug(ctx, srv_ctx->smb_debug_level);
  170     smbc_setFunctionAuthDataWithContext(ctx, smb_conn_srv_auth_fn);
  171     smbc_setOptionUserData(ctx, srv_ctx);
  172 #if defined(SMB_CTX_FLAG_USE_KERBEROS) && defined(SMB_CTX_FLAG_FALLBACK_AFTER_KERBEROS)
  173     smbc_setOptionUseKerberos(ctx, 1);
  174     smbc_setOptionFallbackAfterKerberos(ctx, 1);
  175 #endif
  176     if (smbc_init_context(ctx) == NULL) goto error;
  177     smbc_set_context(ctx);
  178     return;
  179 
  180   error:
  181     DSRVDIEMSG(srv_ctx, errno, "errno=%d, %s\n", errno, strerror(errno));
  182     exit(EXIT_FAILURE);
  183 }
  184 
  185 void smb_conn_srv_listen(struct smb_conn_srv_ctx *ctx){
  186 
  187     static char             buf[COMM_BUF_SIZE];
  188 
  189     if (charset_init(ctx->local_charset, ctx->samba_charset) != 0){
  190     DSRVDIEMSG(ctx, EINVAL, "Can't set samba or local charset\n");
  191     exit(EXIT_FAILURE);
  192     }
  193     smb_conn_srv_samba_init(ctx);
  194     while(1){
  195     fd_set              readfds, exceptfds;
  196     struct timeval          tv;
  197     int             retval;
  198     void                *query;
  199     ssize_t             query_len;
  200     struct smb_conn_query_hdr   *query_hdr;
  201 
  202     tv.tv_sec = ctx->timeout;
  203     tv.tv_usec = 0;
  204 
  205     FD_ZERO(&readfds);
  206     FD_SET(ctx->conn_fd, &readfds);
  207 
  208     FD_ZERO(&exceptfds);
  209     FD_SET(ctx->conn_fd, &exceptfds);
  210 
  211     /* wait for query */
  212     retval = select(ctx->conn_fd + 1, &readfds, NULL, &exceptfds, &tv);
  213     if ((retval < 0)) goto error;
  214     if (retval == 0){
  215         /* we treat timeout as signal to exit, */
  216         /* no cleanup should be required       */
  217         DSRVDIEMSG(ctx, 0, "Timeout expired\n");
  218         exit(EXIT_SUCCESS);
  219     }
  220     if (FD_ISSET(ctx->conn_fd, &exceptfds)) goto error;
  221 
  222     /* read query */
  223     query_len = read(ctx->conn_fd, buf, COMM_BUF_SIZE);
  224     if (query_len < (ssize_t) sizeof(struct smb_conn_query_hdr)) goto error;
  225 
  226     /* check query */
  227     query_hdr = (struct smb_conn_query_hdr *) buf;
  228     if (query_len != (ssize_t) query_hdr->query_len) goto error;
  229 
  230     /* update debug_level from query */
  231     ctx->debug_level = query_hdr->debug_level;
  232 
  233     /* process query */
  234     errno = 0;
  235     query = (void*) (query_hdr + 1);
  236     query_len -= sizeof(struct smb_conn_query_hdr);
  237     DSRVPRINTF(ctx, 6, "process query=%d, query_len=%zd\n",
  238             query_hdr->query_cmd, query_len);
  239     switch(query_hdr->query_cmd){
  240         case OPEN:
  241         smb_conn_srv_open(ctx, query, query_len);
  242         break;
  243         case CREAT:
  244         smb_conn_srv_creat(ctx, query, query_len);
  245         break;
  246         case READ:
  247         smb_conn_srv_read(ctx, query, query_len);
  248         break;
  249         case WRITE:
  250         smb_conn_srv_write(ctx, query, query_len);
  251         break;
  252         case CLOSE:
  253         smb_conn_srv_close(ctx, query, query_len);
  254         break;
  255         case UNLINK:
  256         smb_conn_srv_unlink(ctx, query, query_len);
  257         break;
  258         case RENAME:
  259         smb_conn_srv_rename(ctx, query, query_len);
  260         break;
  261         case OPENDIR:
  262         smb_conn_srv_opendir(ctx, query, query_len);
  263         break;
  264         case CLOSEDIR:
  265         smb_conn_srv_closedir(ctx, query, query_len);
  266         break;
  267         case READDIR:
  268         smb_conn_srv_readdir(ctx, query, query_len);
  269         break;
  270         case MKDIR:
  271         smb_conn_srv_mkdir(ctx, query, query_len);
  272         break;
  273         case RMDIR:
  274         smb_conn_srv_rmdir(ctx, query, query_len);
  275         break;
  276         case STAT:
  277         smb_conn_srv_stat(ctx, query, query_len);
  278         break;
  279         case FSTAT:
  280         smb_conn_srv_fstat(ctx, query, query_len);
  281         break;
  282         case FTRUNCATE:
  283         smb_conn_srv_ftruncate(ctx, query, query_len);
  284         break;
  285         case CHMOD:
  286         smb_conn_srv_chmod(ctx, query, query_len);
  287         break;
  288         case UTIMES:
  289         smb_conn_srv_utimes(ctx, query, query_len);
  290         break;
  291         case SETXATTR:
  292         smb_conn_srv_setxattr(ctx, query, query_len);
  293         break;
  294         case GETXATTR:
  295         smb_conn_srv_getxattr(ctx, query, query_len);
  296         break;
  297         case LISTXATTR:
  298         smb_conn_srv_listxattr(ctx, query, query_len);
  299         break;
  300         case REMOVEXATTR:
  301         smb_conn_srv_removexattr(ctx, query, query_len);
  302         break;
  303         default:
  304         /* unknown qery ? */
  305         goto error;
  306     }
  307     }
  308 
  309   error:
  310     DSRVDIEMSG(ctx, errno, "errno=%d, %s\n", errno, strerror(errno));
  311     exit(EXIT_FAILURE);
  312 };
  313 
  314 void smb_conn_srv_send_reply(struct smb_conn_srv_ctx *ctx,
  315                 enum smb_conn_cmd reply_cmd,
  316                 int errno_value,
  317                 void *reply, size_t reply_len){
  318 
  319     int             iov_cnt;
  320     struct iovec        iov[2];
  321     struct smb_conn_reply_hdr   header;
  322 
  323     if (errno_value == 0){
  324     if (((reply == NULL) && (reply_len != 0)) ||
  325         ((reply != NULL) && (reply_len == 0))) goto error;
  326     }else{
  327     if ((reply != NULL) || (reply_len != 0)) goto error;
  328     }
  329 
  330     iov_cnt = 1;
  331     header.reply_cmd   = reply_cmd;
  332     header.errno_value = errno_value;
  333     header.reply_len   = sizeof(struct smb_conn_reply_hdr);
  334 
  335     iov[0].iov_base = &header;
  336     iov[0].iov_len  = sizeof(struct smb_conn_reply_hdr);
  337 
  338     if (reply_len > 0){
  339     iov[iov_cnt].iov_base = reply;
  340     iov[iov_cnt].iov_len  = reply_len;
  341     header.reply_len += iov[iov_cnt].iov_len;
  342     iov_cnt++;
  343     }
  344 
  345     if (header.reply_len > COMM_BUF_SIZE) goto error;
  346     if (writev(ctx->conn_fd, iov, iov_cnt) != (ssize_t) header.reply_len)
  347     goto error;
  348 
  349     return;
  350 
  351   error:
  352     DSRVDIEMSG(ctx, errno, "errno=%d, %s\n", errno, strerror(errno));
  353     exit(EXIT_FAILURE);
  354 }
  355 
  356 int smb_conn_srv_send_msg(struct smb_conn_srv_ctx *ctx,
  357                 enum smb_conn_cmd msg_type,
  358                 int errno_value,
  359                 int level,
  360                 const char *msg){
  361 
  362     ssize_t         bytes;
  363     struct iovec        iov[3];
  364     struct smb_conn_reply_hdr   reply_header;
  365     struct smb_conn_message_req reply;
  366 
  367     iov[0].iov_base = &reply_header;
  368     iov[0].iov_len  = sizeof(reply_header);
  369     iov[1].iov_base = &reply;
  370     iov[1].iov_len  = sizeof(reply);
  371     iov[2].iov_base = (char*) msg;
  372     iov[2].iov_len  = strlen(msg) + 1;
  373 
  374     reply_header.reply_len   = iov[0].iov_len + iov[1].iov_len +
  375                    iov[2].iov_len;
  376     reply_header.reply_cmd   = msg_type;
  377     reply_header.errno_value = errno_value;
  378     reply.pid                = getpid();
  379     reply.debug_level        = level;
  380     reply.msg_offs           = sizeof(reply);
  381 
  382     if (reply_header.reply_len > COMM_BUF_SIZE) return -1;
  383 
  384     /* send message */
  385     bytes = writev(ctx->conn_fd, iov, 3);
  386     if (bytes != (ssize_t) reply_header.reply_len) return -1;
  387     return 0;
  388 }
  389 
  390 void smb_conn_srv_open(struct smb_conn_srv_ctx *ctx,
  391             struct smb_conn_open_query *query, size_t query_len){
  392 
  393     const char          *url;
  394     struct smb_conn_srv_fd  *state;
  395     struct smb_conn_fd_reply    reply;
  396 
  397     if (query_len <= sizeof(struct smb_conn_open_query)) goto error;
  398     if ( *(((char *) query) + query_len - 1) != '\0' ) goto error;
  399     if (query->url_offs != sizeof(struct smb_conn_open_query)) goto error;
  400 
  401     url = smb_conn_srv_get_url_from_query(query, query->url_offs);
  402     if (query_len != sizeof(struct smb_conn_open_query) + strlen(url) + 1) goto error;
  403     if ((url = charset_local2smb(url)) == NULL) goto error;
  404 
  405     if ((state = malloc(sizeof(struct smb_conn_srv_fd))) == NULL) goto error;
  406 
  407     state->type = SMB_CONN_FILE;
  408     state->offset = (off_t) (-1);
  409     state->fd = smbc_open(url, query->flags, query->mode);
  410 
  411     if (state->fd < 0){
  412     int error = errno;
  413 
  414     free(state);
  415     switch(error){
  416         case EACCES:
  417         case EEXIST:
  418         case EFAULT:
  419         case EFBIG:
  420         case EINTR:
  421         case EISDIR:
  422         case ELOOP:
  423         case EMFILE:
  424         case ENAMETOOLONG:
  425         case ENFILE:
  426         case ENODEV:
  427         case ENOENT:
  428         case ENOSPC:
  429         case ENOTDIR:
  430         case EPERM:
  431         case EROFS:
  432         case ETXTBSY:
  433         smb_conn_srv_send_reply(ctx, OPEN, error, NULL, 0);
  434         return;
  435         default:
  436         goto error;
  437     }
  438     }
  439 
  440     reply.srv_fd = state;
  441     smb_conn_srv_send_reply(ctx, OPEN, 0, &reply, sizeof(reply));
  442     return;
  443 
  444   error:
  445     DSRVDIEMSG(ctx, errno, "errno=%d, %s\n", errno, strerror(errno));
  446     exit(EXIT_FAILURE);
  447 }
  448 
  449 void smb_conn_srv_creat(struct smb_conn_srv_ctx *ctx,
  450             struct smb_conn_url_mode_query *query, size_t query_len){
  451 
  452     const char          *url;
  453     struct smb_conn_srv_fd  *state;
  454     struct smb_conn_fd_reply    reply;
  455 
  456     if (query_len <= sizeof(struct smb_conn_url_mode_query)) goto error;
  457     if ( *(((char *) query) + query_len - 1) != '\0' ) goto error;
  458     if (query->url_offs != sizeof(struct smb_conn_url_mode_query)) goto error;
  459 
  460     url = smb_conn_srv_get_url_from_query(query, query->url_offs);
  461     if (query_len != sizeof(struct smb_conn_url_mode_query) + strlen(url) + 1) goto error;
  462     if ((url = charset_local2smb(url)) == NULL) goto error;
  463 
  464     if ((state = malloc(sizeof(struct smb_conn_srv_fd))) == NULL) goto error;
  465 
  466     state->type = SMB_CONN_FILE;
  467     state->offset = (off_t) (-1);
  468     state->fd = smbc_creat(url, query->mode);
  469 
  470     if (state->fd < 0){
  471     int error = errno;
  472 
  473     free(state);
  474     switch(error){
  475         case EACCES:
  476         case EEXIST:
  477         case EFAULT:
  478         case EFBIG:
  479         case EINTR:
  480         case EISDIR:
  481         case ELOOP:
  482         case EMFILE:
  483         case ENAMETOOLONG:
  484         case ENFILE:
  485         case ENODEV:
  486         case ENOENT:
  487         case ENOSPC:
  488         case ENOTDIR:
  489         case EPERM:
  490         case EROFS:
  491         case ETXTBSY:
  492         smb_conn_srv_send_reply(ctx, CREAT, error, NULL, 0);
  493         return;
  494         default:
  495         goto error;
  496     }
  497     }
  498 
  499     reply.srv_fd = state;
  500     smb_conn_srv_send_reply(ctx, CREAT, 0, &reply, sizeof(reply));
  501     return;
  502 
  503   error:
  504     DSRVDIEMSG(ctx, errno, "errno=%d, %s\n", errno, strerror(errno));
  505     exit(EXIT_FAILURE);
  506 }
  507 
  508 void smb_conn_srv_read(struct smb_conn_srv_ctx *ctx,
  509             struct smb_conn_rw_query *query, size_t query_len){
  510 
  511     struct smb_conn_srv_fd  *state;
  512     struct smb_conn_buf_reply   reply;
  513 
  514     if (query_len != sizeof(struct smb_conn_rw_query)) goto error;
  515     if ((query->offset == (off_t) (-1)) ||
  516     (query->bufsize > ctx->shmem_size) ||
  517     (query->srv_fd == NULL)) goto error;
  518 
  519     state = query->srv_fd;
  520     if ((state->fd < 0) || (state->type != SMB_CONN_FILE)) goto error;
  521 
  522     if (state->offset != query->offset){
  523     off_t   pos;
  524 
  525     pos = smbc_lseek(state->fd, query->offset, SEEK_SET);
  526     if (pos != query->offset) goto error;
  527     state->offset = query->offset;
  528     }
  529 
  530     reply.bufsize = smbc_read(state->fd, ctx->shmem_ptr, query->bufsize);
  531     if (reply.bufsize < 0){
  532     switch(errno){
  533         case EAGAIN:
  534         case EINTR:
  535         case EISDIR:
  536         state->offset = (off_t) (-1);
  537         smb_conn_srv_send_reply(ctx, READ, errno, NULL, 0);
  538         return;
  539         default:
  540         goto error;
  541     }
  542     }
  543 
  544     state->offset += reply.bufsize;
  545     msync(ctx->shmem_ptr, reply.bufsize, MS_SYNC);
  546     smb_conn_srv_send_reply(ctx, READ, 0, &reply, sizeof(reply));
  547     return;
  548 
  549   error:
  550     DSRVDIEMSG(ctx, errno, "errno=%d, %s\n", errno, strerror(errno));
  551     exit(EXIT_FAILURE);
  552 }
  553 
  554 void smb_conn_srv_write(struct smb_conn_srv_ctx *ctx,
  555             struct smb_conn_rw_query *query, size_t query_len){
  556 
  557     struct smb_conn_srv_fd  *state;
  558     struct smb_conn_buf_reply   reply;
  559 
  560     if (query_len != sizeof(struct smb_conn_rw_query)) goto error;
  561     if ((query->offset == (off_t) (-1)) ||
  562     (query->bufsize > ctx->shmem_size) ||
  563     (query->srv_fd == NULL)) goto error;
  564 
  565     state = query->srv_fd;
  566     if ((state->fd < 0) || (state->type != SMB_CONN_FILE)) goto error;
  567 
  568     if (state->offset != query->offset){
  569     off_t   pos;
  570 
  571     pos = smbc_lseek(state->fd, query->offset, SEEK_SET);
  572     if (pos != query->offset) goto error;
  573     state->offset = query->offset;
  574     }
  575 
  576     reply.bufsize = smbc_write(state->fd, ctx->shmem_ptr, query->bufsize);
  577     if (reply.bufsize < 0){
  578     switch(errno){
  579         case EAGAIN:
  580         case EINTR:
  581         case EINVAL:
  582         case EIO:
  583         case ENOSPC:
  584         case EISDIR:
  585         state->offset = (off_t) (-1);
  586         smb_conn_srv_send_reply(ctx, WRITE, errno, NULL, 0);
  587         return;
  588         default:
  589         goto error;
  590     }
  591     }
  592 
  593     state->offset += reply.bufsize;
  594     smb_conn_srv_send_reply(ctx, WRITE, 0, &reply, sizeof(reply));
  595     return;
  596 
  597   error:
  598     DSRVDIEMSG(ctx, errno, "errno=%d, %s\n", errno, strerror(errno));
  599     exit(EXIT_FAILURE);
  600 }
  601 
  602 void smb_conn_srv_close(struct smb_conn_srv_ctx *ctx,
  603             struct smb_conn_fd_query *query, size_t query_len){
  604 
  605     struct smb_conn_srv_fd  *state;
  606 
  607     if (query_len != sizeof(struct smb_conn_fd_query)) goto error;
  608     if (query->srv_fd == NULL) goto error;
  609 
  610     state = query->srv_fd;
  611     if ((state->fd < 0) || (state->type != SMB_CONN_FILE)) goto error;
  612 
  613     if (smbc_close(state->fd) < 0){
  614     switch(errno){
  615         case EINTR:
  616         smb_conn_srv_send_reply(ctx, CLOSE, errno, NULL, 0);
  617         return;
  618         default:
  619         goto error;
  620     }
  621     }
  622 
  623     free(state);
  624     smb_conn_srv_send_reply(ctx, CLOSE, 0, NULL, 0);
  625     return;
  626 
  627   error:
  628     DSRVDIEMSG(ctx, errno, "errno=%d, %s\n", errno, strerror(errno));
  629     exit(EXIT_FAILURE);
  630 }
  631 
  632 void smb_conn_srv_unlink(struct smb_conn_srv_ctx *ctx,
  633             struct smb_conn_url_query *query, size_t query_len){
  634 
  635     const char          *url;
  636     struct stat         st;
  637 
  638     if (query_len <= sizeof(struct smb_conn_url_query)) goto error;
  639     if ( *(((char *) query) + query_len - 1) != '\0' ) goto error;
  640     if (query->url_offs != sizeof(struct smb_conn_url_query)) goto error;
  641 
  642     url = smb_conn_srv_get_url_from_query(query, query->url_offs);
  643     if (query_len != sizeof(struct smb_conn_url_query) + strlen(url) + 1) goto error;
  644     if ((url = charset_local2smb(url)) == NULL) goto error;
  645 
  646     if (smbc_stat(url, &st) < 0){
  647     switch(errno){
  648         case EACCES:
  649         /* try to continue */
  650         break;
  651         case ELOOP:
  652         case ENAMETOOLONG:
  653         case ENOENT:
  654         case ENOTDIR:
  655         smb_conn_srv_send_reply(ctx, UNLINK, errno, NULL, 0);
  656         return;
  657         default:
  658         goto error;
  659     }
  660     }else{
  661     if (!S_ISREG(st.st_mode)){
  662         smb_conn_srv_send_reply(ctx, UNLINK, EISDIR, NULL, 0);
  663         return;
  664     }
  665     if ((st.st_mode & S_IWOTH) != S_IWOTH){
  666         if (smbc_chmod(url, st.st_mode | S_IWOTH) < 0){
  667         switch(errno){
  668             case EACCES:
  669             case EIO:
  670             case EPERM:
  671             /* try to continue */
  672             break;
  673             case ELOOP:
  674             case ENAMETOOLONG:
  675             case ENOENT:
  676             case ENOTDIR:
  677             case EROFS:
  678             smb_conn_srv_send_reply(ctx, UNLINK, errno, NULL, 0);
  679             return;
  680             default:
  681             goto error;
  682         };
  683         }
  684     }
  685     }
  686 
  687     if (smbc_unlink(url) < 0){
  688     switch(errno){
  689         case EACCES:
  690         case EBUSY:
  691         case EIO:
  692         case EISDIR:
  693         case ELOOP:
  694         case ENAMETOOLONG:
  695         case ENOENT:
  696         case ENOTDIR:
  697         case EPERM:
  698         case EROFS:
  699         smb_conn_srv_send_reply(ctx, UNLINK, errno, NULL, 0);
  700         return;
  701         default:
  702         goto error;
  703     }
  704     }
  705 
  706     smb_conn_srv_send_reply(ctx, UNLINK, 0, NULL, 0);
  707     return;
  708 
  709   error:
  710     DSRVDIEMSG(ctx, errno, "errno=%d, %s\n", errno, strerror(errno));
  711     exit(EXIT_FAILURE);
  712 }
  713 
  714 void smb_conn_srv_rename(struct smb_conn_srv_ctx *ctx,
  715             struct smb_conn_rename_query *query, size_t query_len){
  716 
  717     int             count;
  718     const char          *old_url;
  719     const char          *new_url;
  720     const char          *pos;
  721     struct stat         old_st;
  722     struct stat         new_st;
  723 
  724     if (query_len <= sizeof(struct smb_conn_rename_query)) goto error;
  725     if ( *(((char *) query) + query_len - 1) != '\0' ) goto error;
  726     if ((query->old_url_offs != sizeof(struct smb_conn_rename_query)) ||
  727     (query->new_url_offs <= query->old_url_offs) ||
  728     (query->new_url_offs >= query_len - 1)) goto error;
  729 
  730     old_url = smb_conn_srv_get_url_from_query(query, query->old_url_offs);
  731     new_url = smb_conn_srv_get_url_from_query(query, query->new_url_offs);
  732 
  733     if (new_url != old_url + strlen(old_url) + 1) goto error;
  734     if (query_len != sizeof(struct smb_conn_rename_query) +
  735             strlen(old_url) + strlen(new_url) + 2) goto error;
  736     if ((new_url = charset_local2smb(new_url)) == NULL) goto error;
  737     if ((new_url = strdup(new_url)) == NULL) goto error;
  738     if ((old_url = charset_local2smb(old_url)) == NULL) goto error;
  739 
  740     /*
  741      * old_url and new_url should point to the same samba share
  742      * try find the position of 4-th '/' in "smb://server/share/path" and
  743      * compare samba resource names
  744      */
  745     for(count = 0, pos = old_url; *pos; pos++)
  746     if ((*pos == '/') && (++count == 4)) break;
  747     if (*pos != '/'){
  748     smb_conn_srv_send_reply(ctx, RENAME, EXDEV, NULL, 0);
  749     free((char*)new_url);
  750     return;
  751     }
  752     if (strncasecmp(old_url, new_url, pos - old_url + 1) != 0){
  753     smb_conn_srv_send_reply(ctx, RENAME, EXDEV, NULL, 0);
  754     free((char*)new_url);
  755     return;
  756     }
  757 
  758     if (strcasecmp(new_url, old_url) == 0) goto rename;
  759 
  760     /* check the presence of old_url */
  761     if (smbc_stat(old_url, &old_st) < 0){
  762     switch(errno){
  763         case EACCES:
  764         /* try to continue */
  765         goto rename;
  766         case ELOOP:
  767         case ENAMETOOLONG:
  768         case ENOENT:
  769         case ENOTDIR:
  770         smb_conn_srv_send_reply(ctx, RENAME, errno, NULL, 0);
  771         free((char*)new_url);
  772         return;
  773         default:
  774         goto error;
  775     }
  776     }
  777 
  778     /* check the presence of new_url, delete new_url if necessary */
  779     if (smbc_stat(new_url, &new_st) < 0){
  780     switch(errno){
  781         case EACCES:
  782         /* try to continue */
  783         goto rename;
  784         case ENOENT:
  785         /* OK, new path does not exist */
  786         goto rename;
  787         case ELOOP:
  788         case ENAMETOOLONG:
  789         case ENOTDIR:
  790         smb_conn_srv_send_reply(ctx, RENAME, errno, NULL, 0);
  791         free((char*)new_url);
  792         return;
  793         default:
  794         goto error;
  795     }
  796     }
  797 
  798     /* rename dir to file is not possible */
  799     if (S_ISDIR(old_st.st_mode) && S_ISREG(new_st.st_mode)){
  800     smb_conn_srv_send_reply(ctx, RENAME, ENOTDIR, NULL, 0);
  801     free((char*)new_url);
  802     return;
  803     }
  804 
  805     /* rename dir to dir, if yes, try to delete new_url directory first */
  806     if (S_ISDIR(old_st.st_mode) && S_ISDIR(new_st.st_mode)){
  807     if (smbc_rmdir(new_url) != 0){
  808         switch(errno){
  809         case EACCES:
  810         case EBUSY:
  811         case EPERM:
  812             /* try to continue */
  813             goto rename;
  814         case EINVAL:
  815         case ELOOP:
  816         case ENAMETOOLONG:
  817         case ENOENT:
  818         case ENOTDIR:
  819         case ENOTEMPTY:
  820         case EROFS:
  821             smb_conn_srv_send_reply(ctx, RENAME, errno, NULL, 0);
  822             free((char*)new_url);
  823             return;
  824         default:
  825             goto error;
  826         }
  827     }
  828     goto rename;
  829     }
  830 
  831     /* rename file to file, if yes, try to delete new_url file first */
  832     if (S_ISREG(old_st.st_mode) && S_ISREG(new_st.st_mode)){
  833     if ((new_st.st_mode & S_IWOTH) != S_IWOTH){
  834         if (smbc_chmod(new_url, new_st.st_mode | S_IWOTH) < 0){
  835         switch(errno){
  836             case EACCES:
  837             case EIO:
  838             case EPERM:
  839             case ENOENT:
  840             case ENOTDIR:
  841             /* try to continue */
  842             break;
  843             case ELOOP:
  844             case ENAMETOOLONG:
  845             case EROFS:
  846             smb_conn_srv_send_reply(ctx, RENAME, errno, NULL, 0);
  847             free((char*)new_url);
  848             return;
  849             default:
  850             goto error;
  851         };
  852         }
  853     }
  854     if (smbc_unlink(new_url) < 0){
  855         switch(errno){
  856         case EACCES:
  857         case EBUSY:
  858         case EIO:
  859         case EISDIR:
  860         case ENOENT:
  861         case ENOTDIR:
  862         case EPERM:
  863             /* try to continue */
  864             break;
  865         case ELOOP:
  866         case ENAMETOOLONG:
  867         case EROFS:
  868             smb_conn_srv_send_reply(ctx, UNLINK, errno, NULL, 0);
  869             free((char*)new_url);
  870             return;
  871         default:
  872             goto error;
  873         }
  874     }
  875     }
  876 
  877   rename:
  878 
  879     if (smbc_rename(old_url, new_url) < 0){
  880     switch(errno){
  881         case EACCES:
  882         case EBUSY:
  883         case EINVAL:
  884         case EISDIR:
  885         case ELOOP:
  886         case EMLINK:
  887         case ENAMETOOLONG:
  888         case ENOENT:
  889         case ENOSPC:
  890         case ENOTDIR:
  891         case ENOTEMPTY:
  892         case EEXIST:
  893         case EPERM:
  894         case EROFS:
  895         case EXDEV:
  896         smb_conn_srv_send_reply(ctx, RENAME, errno, NULL, 0);
  897         free((char*)new_url);
  898         return;
  899         default:
  900         goto error;
  901     }
  902     }
  903 
  904     smb_conn_srv_send_reply(ctx, RENAME, 0, NULL, 0);
  905     free((char*)new_url);
  906     return;
  907 
  908   error:
  909     DSRVDIEMSG(ctx, errno, "errno=%d, %s\n", errno, strerror(errno));
  910     exit(EXIT_FAILURE);
  911 }
  912 
  913 void smb_conn_srv_opendir(struct smb_conn_srv_ctx *ctx,
  914             struct smb_conn_url_query *query, size_t query_len){
  915 
  916     const char          *url;
  917     struct smb_conn_srv_fd  *state;
  918     struct smb_conn_fd_reply    reply;
  919 
  920     if (query_len <= sizeof(struct smb_conn_url_query)) goto error;
  921     if ( *(((char *) query) + query_len - 1) != '\0' ) goto error;
  922     if (query->url_offs != sizeof(struct smb_conn_url_query)) goto error;
  923 
  924     url = smb_conn_srv_get_url_from_query(query, query->url_offs);
  925     if (query_len != sizeof(struct smb_conn_url_query) + strlen(url) + 1) goto error;
  926     if ((url = charset_local2smb(url)) == NULL) goto error;
  927 
  928     if ((state = malloc(sizeof(struct smb_conn_srv_fd))) == NULL) goto error;
  929 
  930     state->type = SMB_CONN_DIR;
  931     state->offset = (off_t) (-1);
  932     state->fd = smbc_opendir(url);
  933 
  934     if (state->fd < 0){
  935     int error = errno;
  936 
  937     free(state);
  938     switch(error){
  939         case EACCES:
  940         case EMFILE:
  941         case ENOENT:
  942         case ENOTDIR:
  943         case EPERM:
  944         case ENODEV:
  945         smb_conn_srv_send_reply(ctx, OPENDIR, error, NULL, 0);
  946         return;
  947         default:
  948         goto error;
  949     }
  950     }
  951 
  952     reply.srv_fd = state;
  953     smb_conn_srv_send_reply(ctx, OPENDIR, 0, &reply, sizeof(reply));
  954     return;
  955 
  956   error:
  957     DSRVDIEMSG(ctx, errno, "errno=%d, %s\n", errno, strerror(errno));
  958     exit(EXIT_FAILURE);
  959 }
  960 
  961 void smb_conn_srv_closedir(struct smb_conn_srv_ctx *ctx,
  962             struct smb_conn_fd_query *query, size_t query_len){
  963 
  964     struct smb_conn_srv_fd      *state;
  965 
  966     if (query_len != sizeof(struct smb_conn_fd_query)) goto error;
  967     if (query->srv_fd == NULL) goto error;
  968 
  969     state = query->srv_fd;
  970     if ((state->fd < 0) || (state->type != SMB_CONN_DIR)) goto error;
  971 
  972     if (smbc_closedir(state->fd) < 0) goto error;
  973 
  974     free(state);
  975     smb_conn_srv_send_reply(ctx, CLOSEDIR, 0, NULL, 0);
  976     return;
  977 
  978   error:
  979     DSRVDIEMSG(ctx, errno, "errno=%d, %s\n", errno, strerror(errno));
  980     exit(EXIT_FAILURE);
  981 }
  982 
  983 void smb_conn_srv_readdir(struct smb_conn_srv_ctx *ctx,
  984             struct smb_conn_rw_query *query, size_t query_len){
  985 
  986     const char          *name;
  987     struct smbc_dirent      *dirent;
  988     struct smb_conn_dirent_rec  *pos;
  989     struct smb_conn_srv_fd  *state;
  990     struct smb_conn_buf_reply   reply;
  991 
  992 
  993     if (query_len != sizeof(struct smb_conn_rw_query)) goto error;
  994     if ((query->offset != (off_t) (-1)) ||
  995     (query->bufsize > ctx->shmem_size) ||
  996     (query->srv_fd == NULL)) goto error;
  997 
  998     state = query->srv_fd;
  999     if ((state->fd < 0) ||
 1000     (state->type != SMB_CONN_DIR) ||
 1001     (state->offset != (off_t) (-1))) goto error;
 1002 
 1003     pos = (struct smb_conn_dirent_rec *) ctx->shmem_ptr;
 1004     while((char *) (pos + 1) < ctx->shmem_ptr + query->bufsize){
 1005     if ((dirent = smbc_readdir(state->fd)) == NULL) break;
 1006     if (strcmp(dirent->name, "") == 0) continue;
 1007     if (strcmp(dirent->name, ".") == 0) continue;
 1008     if (strcmp(dirent->name, "..") == 0) continue;
 1009 
 1010     name = charset_smb2local(dirent->name);
 1011     if (name == NULL){
 1012         /* the name can not be converted :-( */
 1013         continue;
 1014     }
 1015     if (strlen(name) + 1 > sizeof(pos->d_name)){
 1016         /* the name does not fit to struct smb_dirent_rec :-( */
 1017         continue;
 1018     }
 1019 
 1020     pos->smbc_type = dirent->smbc_type;
 1021     strcpy(pos->d_name, name);
 1022     pos++;
 1023     }
 1024 
 1025     reply.bufsize = ((char *) pos) - ctx->shmem_ptr;
 1026     msync(ctx->shmem_ptr, reply.bufsize, MS_SYNC);
 1027     smb_conn_srv_send_reply(ctx, READDIR, 0, &reply, sizeof(reply));
 1028     return;
 1029 
 1030   error:
 1031     DSRVDIEMSG(ctx, errno, "errno=%d, %s\n", errno, strerror(errno));
 1032     exit(EXIT_FAILURE);
 1033 }
 1034 
 1035 void smb_conn_srv_mkdir(struct smb_conn_srv_ctx *ctx,
 1036             struct smb_conn_url_mode_query *query, size_t query_len){
 1037 
 1038     const char          *url;
 1039 
 1040     if (query_len <= sizeof(struct smb_conn_url_mode_query)) goto error;
 1041     if ( *(((char *) query) + query_len - 1) != '\0' ) goto error;
 1042     if (query->url_offs != sizeof(struct smb_conn_url_mode_query)) goto error;
 1043 
 1044     url = smb_conn_srv_get_url_from_query(query, query->url_offs);
 1045     if (query_len != sizeof(struct smb_conn_url_mode_query) + strlen(url) + 1) goto error;
 1046     if ((url = charset_local2smb(url)) == NULL) goto error;
 1047 
 1048     if (smbc_mkdir(url, query->mode) < 0){
 1049     switch(errno){
 1050         case EACCES:
 1051         case EEXIST:
 1052         case ELOOP:
 1053         case ENAMETOOLONG:
 1054         case ENOENT:
 1055         case ENOSPC:
 1056         case ENOTDIR:
 1057         case EPERM:
 1058         case EROFS:
 1059         smb_conn_srv_send_reply(ctx, MKDIR, errno, NULL, 0);
 1060         return;
 1061         default:
 1062         goto error;
 1063     }
 1064     }
 1065 
 1066     smb_conn_srv_send_reply(ctx, MKDIR, 0, NULL, 0);
 1067     return;
 1068 
 1069   error:
 1070     DSRVDIEMSG(ctx, errno, "errno=%d, %s\n", errno, strerror(errno));
 1071     exit(EXIT_FAILURE);
 1072 }
 1073 
 1074 void smb_conn_srv_rmdir(struct smb_conn_srv_ctx *ctx,
 1075             struct smb_conn_url_query *query, size_t query_len){
 1076 
 1077     const char          *url;
 1078 
 1079     if (query_len <= sizeof(struct smb_conn_url_query)) goto error;
 1080     if ( *(((char *) query) + query_len - 1) != '\0' ) goto error;
 1081     if (query->url_offs != sizeof(struct smb_conn_url_query)) goto error;
 1082 
 1083     url = smb_conn_srv_get_url_from_query(query, query->url_offs);
 1084     if (query_len != sizeof(struct smb_conn_url_query) + strlen(url) + 1) goto error;
 1085     if ((url = charset_local2smb(url)) == NULL) goto error;
 1086 
 1087     if (smbc_rmdir(url) < 0){
 1088     switch(errno){
 1089         case EACCES:
 1090         case EBUSY:
 1091         case EINVAL:
 1092         case ELOOP:
 1093         case ENAMETOOLONG:
 1094         case ENOENT:
 1095         case ENOTDIR:
 1096         case ENOTEMPTY:
 1097         case EPERM:
 1098         case EROFS:
 1099         smb_conn_srv_send_reply(ctx, RMDIR, errno, NULL, 0);
 1100         return;
 1101         default:
 1102         goto error;
 1103     }
 1104     }
 1105 
 1106     smb_conn_srv_send_reply(ctx, RMDIR, 0, NULL, 0);
 1107     return;
 1108 
 1109   error:
 1110     DSRVDIEMSG(ctx, errno, "errno=%d, %s\n", errno, strerror(errno));
 1111     exit(EXIT_FAILURE);
 1112 }
 1113 
 1114 void smb_conn_srv_stat(struct smb_conn_srv_ctx *ctx,
 1115             struct smb_conn_url_query *query, size_t query_len){
 1116 
 1117     const char          *url;
 1118     struct smb_conn_stat_reply  reply;
 1119 
 1120     if (query_len <= sizeof(struct smb_conn_url_query)) goto error;
 1121     if ( *(((char *) query) + query_len - 1) != '\0' ) goto error;
 1122     if (query->url_offs != sizeof(struct smb_conn_url_query)) goto error;
 1123 
 1124     url = smb_conn_srv_get_url_from_query(query, query->url_offs);
 1125     if (query_len != sizeof(struct smb_conn_url_query) + strlen(url) + 1) goto error;
 1126     if ((url = charset_local2smb(url)) == NULL) goto error;
 1127 
 1128     memset(&reply.stat, 0, sizeof(reply.stat));
 1129     if (smbc_stat(url, &reply.stat) < 0){
 1130     switch(errno){
 1131         case EACCES:
 1132         case ELOOP:
 1133         case ENAMETOOLONG:
 1134         case ENOENT:
 1135         case ENOTDIR:
 1136         smb_conn_srv_send_reply(ctx, STAT, errno, NULL, 0);
 1137         return;
 1138         default:
 1139         goto error;
 1140     }
 1141     }
 1142 
 1143     smb_conn_srv_send_reply(ctx, STAT, 0, &reply, sizeof(reply));
 1144     return;
 1145 
 1146   error:
 1147     DSRVDIEMSG(ctx, errno, "errno=%d, %s\n", errno, strerror(errno));
 1148     exit(EXIT_FAILURE);
 1149 }
 1150 
 1151 void smb_conn_srv_fstat(struct smb_conn_srv_ctx *ctx,
 1152             struct smb_conn_fd_query *query, size_t query_len){
 1153 
 1154     struct smb_conn_srv_fd  *state;
 1155     struct smb_conn_stat_reply  reply;
 1156 
 1157     if (query_len != sizeof(struct smb_conn_fd_query)) goto error;
 1158     if (query->srv_fd == NULL) goto error;
 1159 
 1160     state = query->srv_fd;
 1161     if ((state->fd < 0) || (state->type != SMB_CONN_FILE)) goto error;
 1162 
 1163     memset(&reply.stat, 0, sizeof(reply.stat));
 1164     if (smbc_fstat(state->fd, &reply.stat) < 0){
 1165     switch(errno){
 1166         case EACCES:
 1167         case ELOOP:
 1168         case ENAMETOOLONG:
 1169         case ENOENT:
 1170         case ENOTDIR:
 1171         state->offset = (off_t) (-1);
 1172         smb_conn_srv_send_reply(ctx, FSTAT, errno, NULL, 0);
 1173         return;
 1174         default:
 1175         goto error;
 1176     }
 1177     }
 1178 
 1179     smb_conn_srv_send_reply(ctx, FSTAT, 0, &reply, sizeof(reply));
 1180     return;
 1181 
 1182   error:
 1183     DSRVDIEMSG(ctx, errno, "errno=%d, %s\n", errno, strerror(errno));
 1184     exit(EXIT_FAILURE);
 1185 }
 1186 
 1187 void smb_conn_srv_ftruncate(struct smb_conn_srv_ctx *ctx,
 1188             struct smb_conn_ftruncate_query *query, size_t query_len){
 1189 
 1190     struct smb_conn_srv_fd  *state;
 1191 
 1192     if (query_len != sizeof(struct smb_conn_ftruncate_query)) goto error;
 1193     if ((query->offset == (off_t) (-1)) || (query->srv_fd == NULL)) goto error;
 1194 
 1195     state = query->srv_fd;
 1196     if ((state->fd < 0) || (state->type != SMB_CONN_FILE)) goto error;
 1197 
 1198     if (smbc_ftruncate(state->fd, query->offset) < 0){
 1199     switch(errno){
 1200         case EACCES:
 1201         case EINTR:
 1202         case EINVAL:
 1203         case EIO:
 1204         case EISDIR:
 1205         case ELOOP:
 1206         case ENAMETOOLONG:
 1207         case ENOENT:
 1208         case ENOTDIR:
 1209         case EPERM:
 1210         case EROFS:
 1211         case ETXTBSY:
 1212         state->offset = (off_t) (-1);
 1213         smb_conn_srv_send_reply(ctx, FTRUNCATE, errno, NULL, 0);
 1214         return;
 1215         default:
 1216         goto error;
 1217     }
 1218     }
 1219 
 1220     state->offset = (off_t) (-1);
 1221     smb_conn_srv_send_reply(ctx, FTRUNCATE, 0, NULL, 0);
 1222     return;
 1223 
 1224   error:
 1225     DSRVDIEMSG(ctx, errno, "errno=%d, %s\n", errno, strerror(errno));
 1226     exit(EXIT_FAILURE);
 1227 }
 1228 
 1229 void smb_conn_srv_chmod(struct smb_conn_srv_ctx *ctx,
 1230             struct smb_conn_url_mode_query *query, size_t query_len){
 1231 
 1232     const char          *url;
 1233 
 1234     if (query_len <= sizeof(struct smb_conn_url_mode_query)) goto error;
 1235     if ( *(((char *) query) + query_len - 1) != '\0' ) goto error;
 1236     if (query->url_offs != sizeof(struct smb_conn_url_mode_query)) goto error;
 1237 
 1238     url = smb_conn_srv_get_url_from_query(query, query->url_offs);
 1239     if (query_len != sizeof(struct smb_conn_url_mode_query) + strlen(url) + 1) goto error;
 1240     if ((url = charset_local2smb(url)) == NULL) goto error;
 1241 
 1242     if (smbc_chmod(url, query->mode) < 0){
 1243     switch(errno){
 1244         case EACCES:
 1245         case EIO:
 1246         case ELOOP:
 1247         case ENAMETOOLONG:
 1248         case ENOENT:
 1249         case ENOTDIR:
 1250         case EPERM:
 1251         case EROFS:
 1252         smb_conn_srv_send_reply(ctx, CHMOD, errno, NULL, 0);
 1253         return;
 1254         default:
 1255         goto error;
 1256     }
 1257     }
 1258 
 1259     smb_conn_srv_send_reply(ctx, CHMOD, 0, NULL, 0);
 1260     return;
 1261 
 1262   error:
 1263     DSRVDIEMSG(ctx, errno, "errno=%d, %s\n", errno, strerror(errno));
 1264     exit(EXIT_FAILURE);
 1265 }
 1266 
 1267 void smb_conn_srv_utimes(struct smb_conn_srv_ctx *ctx,
 1268             struct smb_conn_utimes_query *query, size_t query_len){
 1269 
 1270     const char          *url;
 1271 
 1272     if (query_len <= sizeof(struct smb_conn_utimes_query)) goto error;
 1273     if ( *(((char *) query) + query_len - 1) != '\0' ) goto error;
 1274     if (query->url_offs != sizeof(struct smb_conn_utimes_query)) goto error;
 1275 
 1276     url = smb_conn_srv_get_url_from_query(query, query->url_offs);
 1277     if (query_len != sizeof(struct smb_conn_utimes_query) + strlen(url) + 1) goto error;
 1278     if ((url = charset_local2smb(url)) == NULL) goto error;
 1279 
 1280     if (smbc_utimes(url, query->tbuf) < 0){
 1281     switch(errno){
 1282         case EACCES:
 1283         case ENOENT:
 1284         case EPERM:
 1285         case EROFS:
 1286         smb_conn_srv_send_reply(ctx, UTIMES, errno, NULL, 0);
 1287         return;
 1288         default:
 1289         goto error;
 1290     }
 1291     }
 1292 
 1293     smb_conn_srv_send_reply(ctx, UTIMES, 0, NULL, 0);
 1294     return;
 1295 
 1296   error:
 1297     DSRVDIEMSG(ctx, errno, "errno=%d, %s\n", errno, strerror(errno));
 1298     exit(EXIT_FAILURE);
 1299 }
 1300 
 1301 void smb_conn_srv_setxattr(struct smb_conn_srv_ctx *ctx,
 1302             struct smb_conn_setxattr_query *query, size_t query_len){
 1303 
 1304     const char          *url;
 1305     const char          *name;
 1306 
 1307     if (query_len <= sizeof(struct smb_conn_setxattr_query)) goto error;
 1308     if ( *(((char *) query) + query_len - 1) != '\0' ) goto error;
 1309     if ((query->url_offs != sizeof(struct smb_conn_setxattr_query)) ||
 1310     (query->name_offs <= query->url_offs) ||
 1311     (query->name_offs >= query_len - 1)) goto error;
 1312 
 1313     url  = smb_conn_srv_get_url_from_query(query, query->url_offs);
 1314     name = smb_conn_srv_get_url_from_query(query, query->name_offs);
 1315 
 1316     if (name != url + strlen(url) + 1) goto error;
 1317     if (query_len != sizeof(struct smb_conn_setxattr_query) +
 1318             strlen(url) + strlen(name) + 2) goto error;
 1319     if ((url = charset_local2smb(url)) == NULL) goto error;
 1320 
 1321     if (smbc_setxattr(url, name, ctx->shmem_ptr, query->bufsize, query->flags) < 0){
 1322     switch(errno){
 1323         case EINVAL:
 1324         case EEXIST:
 1325         case ENOATTR:
 1326         case EPERM:
 1327         case ENOTSUP:
 1328         case ENOSPC:
 1329         case EDQUOT:
 1330 
 1331         case EACCES:
 1332         case ELOOP:
 1333         case ENAMETOOLONG:
 1334         case ENOTDIR:
 1335         smb_conn_srv_send_reply(ctx, SETXATTR, errno, NULL, 0);
 1336         return;
 1337         default:
 1338         goto error;
 1339     }
 1340     }
 1341 
 1342     smb_conn_srv_send_reply(ctx, SETXATTR, 0, NULL, 0);
 1343     return;
 1344 
 1345   error:
 1346     DSRVDIEMSG(ctx, errno, "errno=%d, %s\n", errno, strerror(errno));
 1347     exit(EXIT_FAILURE);
 1348 }
 1349 
 1350 void smb_conn_srv_getxattr(struct smb_conn_srv_ctx *ctx,
 1351             struct smb_conn_getxattr_query *query, size_t query_len){
 1352 
 1353     const char          *url;
 1354     const char          *name;
 1355 
 1356     if (query_len <= sizeof(struct smb_conn_getxattr_query)) goto error;
 1357     if ( *(((char *) query) + query_len - 1) != '\0' ) goto error;
 1358     if ((query->url_offs != sizeof(struct smb_conn_getxattr_query)) ||
 1359     (query->name_offs <= query->url_offs) ||
 1360     (query->name_offs >= query_len - 1)) goto error;
 1361 
 1362     url  = smb_conn_srv_get_url_from_query(query, query->url_offs);
 1363     name = smb_conn_srv_get_url_from_query(query, query->name_offs);
 1364 
 1365     if (name != url + strlen(url) + 1) goto error;
 1366     if (query_len != sizeof(struct smb_conn_getxattr_query) +
 1367             strlen(url) + strlen(name) + 2) goto error;
 1368     if ((url = charset_local2smb(url)) == NULL) goto error;
 1369 
 1370     if (smbc_getxattr(url, name, ctx->shmem_ptr, query->bufsize) < 0){
 1371     switch(errno){
 1372         case EINVAL:
 1373         case EEXIST:
 1374         case ENOATTR:
 1375         case EPERM:
 1376         case ENOTSUP:
 1377         case ERANGE:
 1378 
 1379         case EACCES:
 1380         case ELOOP:
 1381         case ENAMETOOLONG:
 1382         case ENOTDIR:
 1383         smb_conn_srv_send_reply(ctx, GETXATTR, errno, NULL, 0);
 1384         return;
 1385         default:
 1386         goto error;
 1387     }
 1388     }
 1389 
 1390     msync(ctx->shmem_ptr, query->bufsize, MS_SYNC);
 1391     smb_conn_srv_send_reply(ctx, GETXATTR, 0, NULL, 0);
 1392     return;
 1393 
 1394   error:
 1395     DSRVDIEMSG(ctx, errno, "errno=%d, %s\n", errno, strerror(errno));
 1396     exit(EXIT_FAILURE);
 1397 }
 1398 
 1399 void smb_conn_srv_listxattr(struct smb_conn_srv_ctx *ctx,
 1400             struct smb_conn_listxattr_query *query, size_t query_len){
 1401 
 1402     const char          *url;
 1403 
 1404     if (query_len <= sizeof(struct smb_conn_listxattr_query)) goto error;
 1405     if ( *(((char *) query) + query_len - 1) != '\0' ) goto error;
 1406     if ((query->url_offs != sizeof(struct smb_conn_listxattr_query)) ||
 1407     (query->bufsize > ctx->shmem_size)) goto error;
 1408 
 1409     url = smb_conn_srv_get_url_from_query(query, query->url_offs);
 1410     if (query_len != sizeof(struct smb_conn_listxattr_query) + strlen(url) + 1) goto error;
 1411     if ((url = charset_local2smb(url)) == NULL) goto error;
 1412 
 1413     if (smbc_listxattr(url, ctx->shmem_ptr, query->bufsize) < 0){
 1414     switch(errno){
 1415         case EPERM:
 1416         case ENOTSUP:
 1417         case ERANGE:
 1418 
 1419         case EACCES:
 1420         case ELOOP:
 1421         case ENAMETOOLONG:
 1422         case ENOENT:
 1423         case ENOTDIR:
 1424         smb_conn_srv_send_reply(ctx, LISTXATTR, errno, NULL, 0);
 1425         return;
 1426         default:
 1427         goto error;
 1428     }
 1429     }
 1430 
 1431     msync(ctx->shmem_ptr, query->bufsize, MS_SYNC);
 1432     smb_conn_srv_send_reply(ctx, LISTXATTR, 0, NULL, 0);
 1433     return;
 1434 
 1435   error:
 1436     DSRVDIEMSG(ctx, errno, "errno=%d, %s\n", errno, strerror(errno));
 1437     exit(EXIT_FAILURE);
 1438 }
 1439 
 1440 void smb_conn_srv_removexattr(struct smb_conn_srv_ctx *ctx,
 1441             struct smb_conn_removexattr_query *query, size_t query_len){
 1442 
 1443     const char          *url;
 1444     const char          *name;
 1445 
 1446     if (query_len <= sizeof(struct smb_conn_removexattr_query)) goto error;
 1447     if ( *(((char *) query) + query_len - 1) != '\0' ) goto error;
 1448     if ((query->url_offs != sizeof(struct smb_conn_getxattr_query)) ||
 1449     (query->name_offs <= query->url_offs) ||
 1450     (query->name_offs >= query_len - 1)) goto error;
 1451 
 1452     url  = smb_conn_srv_get_url_from_query(query, query->url_offs);
 1453     name = smb_conn_srv_get_url_from_query(query, query->name_offs);
 1454 
 1455     if (name != url + strlen(url) + 1) goto error;
 1456     if (query_len != sizeof(struct smb_conn_getxattr_query) +
 1457             strlen(url) + strlen(name) + 2) goto error;
 1458     if ((url = charset_local2smb(url)) == NULL) goto error;
 1459 
 1460     if (smbc_removexattr(url, name) < 0){
 1461     switch(errno){
 1462         case ENOATTR:
 1463         case EPERM:
 1464         case ENOTSUP:
 1465 
 1466         case EACCES:
 1467         case ELOOP:
 1468         case ENAMETOOLONG:
 1469         case ENOTDIR:
 1470         smb_conn_srv_send_reply(ctx, REMOVEXATTR, errno, NULL, 0);
 1471         return;
 1472         default:
 1473         goto error;
 1474     }
 1475     }
 1476 
 1477     smb_conn_srv_send_reply(ctx, REMOVEXATTR, 0, NULL, 0);
 1478     return;
 1479 
 1480   error:
 1481     DSRVDIEMSG(ctx, errno, "errno=%d, %s\n", errno, strerror(errno));
 1482     exit(EXIT_FAILURE);
 1483 }